Evan's blog Evan's blog
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)

conanan

真相只有一个
首页
关于
  • 分类
  • 标签
  • 归档
  • H5&CSS3
  • JS
  • TS
  • Node
  • Webpack
  • Vue2
  • Vue3
  • 微信小程序
  • Andorid
  • Flutter
推荐
GitHub (opens new window)
  • HTML
  • CSS基础

  • CSS布局

    • 盒子模型
      • box-sizing 盒子标准 🔥
      • Visual formatting model 细节 🔥
        • 布局和包含块 🔥
        • Horizontal Formatting🔥
      • width 宽度
      • height 高度
      • padding 内边距
      • border 边框
        • border 缩写 🔥
        • border-width 宽度
        • border-style 样式
        • border-color 颜色
        • 利用border作图 🔥
        • border-collapse 表格边框 🔥
        • border-radius圆角边框 🔥
      • outline轮廓线
      • margin 外边距
        • margin 缩写 🔥
        • margin 负值 🔥
        • 问题 1
        • 问题 2
        • 块级盒子水平居中 🔥
        • 边界折叠问题 🔥
        • 兄弟元素
        • 父子元素
        • 空的块级元素
      • box-shadow 盒子阴影 🔥
    • 标准流
    • 浮动
    • 定位
    • 传统布局总结
    • Flexible
    • 移动端适配
    • 京东
    • 考拉
  • 高级技巧
  • 代码规范
  • H5&CSS3
  • CSS布局
xugaoyi
2020-03-14
目录

盒子模型

# Box Model 盒子模型

盒子模型:所有 HTML 元素可以看作盒子,盒子模型用来设计和布局时使用。CSS 盒模型本质上是一个盒子,封装周围的 HTML 元素,它包括:margin,border,padding 和 content。盒模型允许我们在其它元素和周围元素 border 之间的空间放置元素。

CSS box-model

# box-sizing 盒子标准 🔥

CSS3 中可以通过 box-sizing 来指定盒模型,这样我们计算盒子大小的方式就发生了改变。有 2 个值:

  • content-box:即设置width和height仅针对content,最终盒子大小为 content + padding + border

    若盒子模型改为content-box且没有指定 width 或 height(即使子节点和父节点一样宽,也不要指定宽度,100%也不行),则给定 padding 不会改变盒子大小及 width 或 height(对应,没 width 则不改变 width,没 height 则不改变 height)

    但是 padding可以撑开盒子,我们可以做非常巧妙的运用。因为每个导航栏里面的字数不一样多,我们可以不用给每个盒子宽度了,直接给 padding 最合适,且 a 标签为行内元素,需转为行内块元素才能修改宽高

  • border-box:CSS3,即设置width和height针对 content + padding + border

    若盒子模型改为 border-box , 那 padding 和 border 就不会撑大盒子了,前提 padding 和 border 不会超过 width 宽度

# Visual formatting model 细节 🔥

# 布局和包含块 🔥

提示

参考W3 文档 (opens new window), MDN 文档 (opens new window)。

一个元素大小的和位置经常受其包含块的影响。大多数情况下,包含块就是这个元素最近的祖先块元素 (opens new window)的内容区 (opens new window),但也不是总是这样。确定一个元素的包含块的过程完全依赖于这个元素的 position (opens new window) 属性:

  1. 如果 position 属性为 static 或 relative ,包含块就是由它的最近的祖先块元素(比如说 inline-block, block 或 list-item 元素)或格式化上下文(比如说 a table container, flex container, grid container, or the block container itself)的内容区的边缘组成的。
  2. 如果 position 属性为 absolute ,包含块就是由它的最近的 position 的值不是 static (也就是值为fixed, absolute, relative 或 sticky)的祖先元素的内边距区的边缘组成。
  3. 如果 position 属性是 fixed,在连续媒体的情况下(continuous media)包含块是 viewport (opens new window) ,在分页媒体(paged media)下的情况下包含块是分页区域(page area)。
  4. 如果 position 属性是 absolute 或 fixed,包含块也可能是由满足以下条件的最近父级元素的内边距区的边缘组成的:
    1. A transform (opens new window) or perspective (opens new window) value other than none
    2. A will-change (opens new window) value of transform or perspective
    3. A filter (opens new window) value other than none or a will-change value of filter(only works on Firefox).
    4. A contain (opens new window) value of paint (例如: contain: paint;)

注意

根元素(<html>)所在的包含块是一个被称为初始包含块的矩形。

# Horizontal Formatting🔥

标准流水平布局中的七个属性中必须包含以下约束(绝对/固定定位的公式需要添加 left 和 right,其余规则类似):

margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right
=
width of containing block
1
2
3
  • 🔥 上述值中只有 'width', 'margin-left' 和 'margin-right' 可以设置为 'auto',且 'width' 默认就是 'auto'(只可设置为非负值)。其余几个属性必须设置为特定的值或默认值为 0。且只有 'margin' 可以为负值。

  • 🔥 如果恰好有一个值指定为“ auto”,其余俩值有特定值,则 'auto' 值根据等式计算得出。

    div {
      width: 500px;
    }
    p {
      margin-left: auto;
      margin-right: 100px;
      width: 100px;
    } /* 'auto' left margin evaluates to 300px */
    
    1
    2
    3
    4
    5
    6
    7
    8
    p {
      margin-left: 100px;
      margin-right: 100px;
      /* 省略了也是默认值 auto */
      /* width: auto; */
    }
    
    1
    2
    3
    4
    5
    6
  • 🔥 如果 'width' 被设置为 'auto',那么任何其他 'auto' 的值都将变成 '0',并且 'width 的值由等式推出(即计算包含块)。

    div {
      width: 500px;
    }
    p {
      margin-left: auto;
      margin-right: 100px;
      width: auto;
    } /* left margin evaluates to 0; width becomes 400px */
    
    1
    2
    3
    4
    5
    6
    7
    8
    div {
      width: 500px;
    }
    p {
      margin-left: auto;
      margin-right: auto;
      width: auto;
    } /* left and right margin evaluates to 0; width becomes 500px */
    
    1
    2
    3
    4
    5
    6
    7
    8
  • 🔥 若 'width' 有除 “auto” 以外的计算值,且 'margin-left' 和 'margin-right' 均为 'auto',则它们的使用值相等(当然也可以手动设置相同值,不过没必要)。这使元素相对于包含块的边缘水平居中。

    div {
      width: 500px;
    }
    p {
      width: 300px;
      margin-left: auto;
      margin-right: auto;
    }
    /* each margin is 100 pixels wide, because (500-300)/2 = 100 */
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  • 🔥 如果以上所有内容均具有除 “auto” 以外的计算值,则这些值被称为“过度约束”,并且必定造成其中一个的值与其计算值不同。 如果包含块的 'direction' 属性的值为 'ltr',则将忽略指定的 'margin-right' 值(即设置为 'auto'),并计算该值以使等式成立。 如果 'direction'的值为 'rtl',则恰好是 'margin-left'(即设置为 'auto')。设置为 'auto' 后会根据等式计算得出值。

    div {
      width: 500px;
    }
    p {
      margin-left: 100px;
      margin-right: 100px;
      width: 100px;
    } /* right margin forced to be 300px */
    
    1
    2
    3
    4
    5
    6
    7
    8
  • 🔥 当 'width of containing block' 一定,若 'margin-right' 为负值且其他值不变,则 'widht' 变大;'margin-left' 为负值,左移。

    当添加 padding 或 border 后,width 会变小。

    div {
      width: 500px;
      border: 3px solid black;
    }
    p.wide {
      margin-left: 10px;
      width: auto;
      margin-right: -50px;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  • 如果 'width' 不是 'auto' 并且 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width'(加上任何值不是 'auto' 的 'margin-left' 或 'margin-right' )大于包含块的宽度,那么对于任何 'auto' 的 'margin-left' 或 'margin-right',将应用如下规则:'auto' 值都将被视为 0。没懂!不知道场景!

# width 宽度

  • width 设置盒子的宽度,默认值为 'auto'

  • min-width 代表最小宽度,最终值大于等于min-width,多用于 PC 网站,固定最小宽度

  • max-width 代表最大宽度,最终值小于等于max-width,用于inline-block的元素内容,超过即换行

# height 高度

  • height 设置盒子的高度

  • min-height 代表最小高度,最终值大于等于min-height,多用于 PC 网站,固定最小高度

  • max-height 代表最大高度,最终值小于等于max-width,用于固定最大高度,超过可通过overflow隐藏

# padding 内边距

padding 属性用于设置内边距,即 border 与 content 之间的距离。也可以分开指定上下左右。

值的个数 含义
padding: 5px; 1 个值,代表上下左右
padding: 5px 10px; 2 个值,代表上下、左右
padding: 5px 10px 20px; 3 个值,代表上、左右、下
padding: 5px 10px 20px 30px; 4 个值,代表上、右、下、左
  • 在box-sizing为content-box时,padding 影响了盒子实际大小。 也就是说,如果盒子已经有了宽度和高度,此时再指定内边框,会撑大盒子;如果盒子没有了宽度或高度,则不影响

  • 背景颜色会延伸到内边距上

# border 边框

# border 缩写 🔥

简写

border: border-width || border-style || border-color;
1

分开写

border-top: border-width || border-style || border-color;
border-bottom: border-width || border-style || border-color;
border-left: border-width || border-style || border-color;
border-right: border-width || border-style || border-color;
1
2
3
4

注意边框的层叠性

# border-width 宽度

  • 同其他

# border-style 样式

  • none:没有边框即忽略所有边框的宽度,默认
  • solid:单实线,常用
  • double:双实线
  • dashed:块虚线
  • dotted:点虚线
  • ...

# border-color 颜色

  • 同其他
  • transparent透明

# 利用border作图 🔥

如下代码:

<style>
  div {
    display: inline-block;
  }
  .border-shape-1 {
    width: 100px;
    height: 100px;
    border-top: 50px solid red;
    border-right: 50px solid blue;
    border-bottom: 50px solid green;
    border-left: 50px solid skyblue;
  }

  .border-shape-2 {
    /* 宽度必须给0,否则独占一行,默认为父容器宽度。高度可以不给,通过内容撑起来 */
    width: 0;
    border-top: 100px solid red;
    border-right: 100px solid blue;
    border-bottom: 100px solid green;
    border-left: 100px solid skyblue;
  }

  .border-shape-3 {
    /* 宽度必须给0,否则独占一行,默认为父容器宽度。高度可以不给,通过内容撑起来 */
    width: 0;
    border-top: 200px solid red;
    border-left: 200px solid skyblue;
    /* 上左,上右改变分割线方向 */
    /* border-right: 200px solid blue; */
  }

  /* 也可以配合3种示例,结合旋转实现 */
  .border-shape-4 {
    /* 宽度必须给0,否则独占一行,默认为父容器宽度。高度可以不给,通过内容撑起来 */
    width: 0;
    border: 100px solid transparent;
    border-left: 100px solid skyblue;
  }

  .border-shape-5 {
    /* 宽度必须给0,否则独占一行,默认为父容器宽度。高度可以不给,通过内容撑起来 */
    width: 0;
    border-top: 200px solid red;
    border-right: 100px solid blue;
    border-left: 100px solid skyblue;
  }
</style>
<div class="border-shape-1"></div>
<div class="border-shape-2"></div>
<div class="border-shape-3"></div>
<div class="border-shape-4"></div>
<div class="border-shape-5"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

显示效果如下:

<style>
    .shape-demo div {
        display: inline-block;
    }
    .shape-demo .border-shape-1 {
        width: 100px;
        height: 100px;
        border-top: 25px solid red;
        border-right: 25px solid blue;
        border-bottom: 25px solid green;
        border-left: 25px solid skyblue;
    }

    .shape-demo .border-shape-2 {
        /* 宽度必须给0,否则独占一行,默认为父容器宽度。高度可以不给,通过内容撑起来 */
        width: 0;
        border-top: 50px solid red;
        border-right: 50px solid blue;
        border-bottom: 50px solid green;
        border-left: 50px solid skyblue;
    }

    .shape-demo .border-shape-3 {
        /* 宽度必须给0,否则独占一行,默认为父容器宽度。高度可以不给,通过内容撑起来 */
        width: 0;
        border-top: 100px solid red;
        border-left: 100px solid skyblue;
        /* 上左,上右改变分割线方向 */
        /* border-right: 200px solid blue; */
    }

    /* 也可以配合3种示例,结合旋转实现 */
    .shape-demo .border-shape-4 {
        /* 宽度必须给0,否则独占一行,默认为父容器宽度。高度可以不给,通过内容撑起来 */
        width: 0;
        border: 50px solid transparent;
        border-left: 50px solid skyblue;
    }

    .shape-demo .border-shape-5 {
        /* 宽度必须给0,否则独占一行,默认为父容器宽度。高度可以不给,通过内容撑起来 */
        width: 0;
        border-top: 100px solid red;
        border-right: 50px solid blue;
        border-left: 50px solid skyblue;
    }
</style>
<html>
    <div class="shape-demo">
        <div class="border-shape-1"></div>
        <div class="border-shape-2"></div>
        <div class="border-shape-3"></div>
        <div class="border-shape-4"></div>
        <div class="border-shape-5"></div>
    </div>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# border-collapse 表格边框 🔥

border-collapse 属性控制浏览器绘制表格边框的方式。它控制相邻单元格的边框。

border-collapse: collapse || separate;
1
  • collapse:合并,表示相邻边框合并在一起,常用
  • separate:分开

# border-radius圆角边框 🔥

radius:半径

可以分别给四个角都设置角度

  • 左上、 右上、 右下、 左下
  • 左上和右下、 右上和左下
  • 甚至还能直接指定 top、bottom、left、right,必须前两个在前面
  • 可以对每个角的 x, y 设置不同的角度
  • 若单位为%,则参考的是当前盒子的宽度

案例

  • 如何让一个盒子变圆形:给border-radius为正方盒子 width 和 height(相等) 的一半,如 50%

    div {
      border-radius: 50%;
    }
    
    1
    2
    3
  • 如何让一个盒子变圆角矩形:给border-radius为盒子 height 的一半,如 50%

# outline轮廓线

不属于盒子模型。同 border 相比,outline不会增加盒子的大小,默认显示在border外面,取值同 border。

可用于分析网站布局;也可用于去掉input或a(tab 选中)或textraea的 focus 轮廓蓝线。

  • none:取消,写0也可

# margin 外边距

# margin 缩写 🔥

margin 清除周围的(外边框)元素区域。margin 没有背景颜色,是完全透明的。也可以分开指定上下左右。默认值为 0

值的个数 含义
margin: 5px; 1 个值,代表上下左右
margin: 5px 10px; 2 个值,代表上下、左右
margin: 5px 10px 20px; 3 个值,代表上、左右、下
margin: 5px 10px 20px 30px; 4 个值,代表上、右、下、左

# margin 负值 🔥

# 问题 1

有间隙的格子布局时一行中最后一个元素的margin-right总会多余

解决:

  • 选择一行最后一个元素,添加class,去除margin-right

  • 使用伪类选择器(IE8 不支持)

  • 增大包含块的宽度。

    .container固定宽度> .wrap>很多item。.wrap一般是ul

    给.wrap+负margin即可增大.wrap宽度;或直接给.wrap宽度增大

# 问题 2

无间隙的格子布局,需要对变粗的边界进行合并,可以使用负margin

# 块级盒子水平居中 🔥

margin 典型应用——让块级盒子水平居中,但需满足两个条件

  • 子盒子必须指定了 width

  • 子盒子的左右 margin 都设置为 auto

    div {
      width: 100px;
      margin: 0 auto;
    }
    
    1
    2
    3
    4

若是行内元素或行内块元素的内容需要水平居中,可以给其父元素添加text-align: center即可

margin 水平居中原理

原理参考 Visual formatting model 章节

对块元素所属行的剩余空间的分配问题。auto则表示剩余空间都给这侧。据此可以实现左对齐,右对齐。

垂直居中需要使用定位和移动,移动父元素高度的一半并减去子元素盒子高度的一半。

# 边界折叠问题 🔥

两个块元素(block)的相邻垂直margin同时都有设定时只会只会保留最大边距,这种行为称为边界折叠(margin collapsing),有时也翻译为外边距重叠。只有垂直外边距会发生该问题。

有三种情况会形成外边距重叠:

# 兄弟元素

相邻的两个兄弟元素之间的外边距重叠,除非后一个元素加上clear-fix 清除浮动 (opens new window)。

  • 两者都是正值,兄弟元素间的相邻垂直外边距会取两者之间的较大值
  • 如果相邻的外边距一正一负,则取两者的和
  • 如果相邻的外边距都是负值,则取两者中绝对值较大的

兄弟元素之间的外边距的重叠,对于开发是有利的,所以我们不需要进行处理

如下图,上面的元素有下外边距 margin-bottom,下面的元素有上外边距 margin-top ,则他们之间的垂直间距是取最大值。对于段落p元素正好可以使用该副作用。

image-20191223002453257

<style>
  p:nth-child(1) {
    width: 100px;
    height: 100px;
    background-color: skyblue;
    margin-bottom: 50px;
  }
  p:nth-child(2) {
    width: 100px;
    height: 100px;
    background-color: skyblue;
    margin-top: 50px;
  }
</style>

<div>
  <p>下边界范围会...</p>
  <p>...会跟这个元素的上边界范围重叠。</p>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

解决方案(一般无需解决):

  • 尽量只给一个盒子添加 margin 值

# 父子元素

如果没有 border,padding,content,也没有创建块级格式上下文或清除浮动来分开一个块级元素的上边界 margin-top 与其内一个或多个后代块级元素的上边界 margin-top;

或没有边框,内边距,行内内容,高度 height,最小高度 min-height 或 最大高度 max-height 来分开一个块级元素的下边界 margin-bottom 与其内的一个或多个后代后代块元素的下边界 margin-bottom

则就会出现父块元素和其内后代块元素外边界重叠,重叠部分最终会溢出到父级块元素外面。即子元素的会传递给父元素(上外边距)

父子外边距的折叠会影响到页面的布局,必须要进行处理

如下图,对于两个嵌套关系(父子关系)的块元素,父元素有上外边距同时(其实父元素可以没有外边距)子元素也有上外边距,此时父元素会塌陷较大的外边距值。即子元素想距离父元素上边距失效(即父子元素上边框还是重合的)。注意以内容区域为视角看问题。下外边距同理(但是必须父元素的高度是auto)

image-20191223003825165

<style type="text/css">
  section {
    width: 400px;
    height: auto;
    background-color: skyblue;
    margin-top: 50px;
    margin-bottom: 100px;
  }

  header {
    width: 100px;
    height: 100px;
    background-color: orange;
    margin-top: 100px;
  }

  footer {
    width: 100px;
    height: 100px;
    background-color: greenyellow;
    margin-bottom: 50px;
  }
</style>

<hr />
<section>
  <header>上边界重叠</header>
  <main></main>
  <footer>下边界重叠</footer>
</section>
<hr />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

解决方案:

  • 可以为父元素定义border-top/bottom

  • 可以为父元素定义padding-top/bottom

  • 触发 BFC(查看 float 章节)

    推荐使用伪元素添加一个display:table匿名表格单元格元素(推荐,查看 float 章节)

# 空的块级元素

当一个块元素上边界 margin-top 直接贴到元素下边界 margin-bottom 时也会发生边界折叠。这种情况会发生在一个块元素完全没有设定边框 border、内边距 paddng、高度 height、最小高度 min-height 、最大高度 max-height 、内容设定为 inline 或是加上 clear-fix 的时候。

<style>
  p {
    margin: 0;
  }
  div {
    margin-top: 13px;
    margin-bottom: 87px;
  }
</style>

<p>上边界范围是 87 ...</p>
<div></div>
<p>... 上边界范围是 87</p>
1
2
3
4
5
6
7
8
9
10
11
12
13
  • 上述情况的组合会产生更复杂的外边距折叠。
  • 即使某一外边距为 0,这些规则仍然适用。因此就算父元素的外边距是 0,第一个或最后一个子元素的外边距仍然会“溢出”到父元素的外面。
  • 如果参与折叠的外边距中包含负值,折叠后的外边距的值为最大的正边距与最小的负边距(即绝对值最大的负边距)的和,;也就是说如果有-13px 8px 100px 叠在一起,边界范围的技术就是 100px -13px 的 87px。
  • 如果所有参与折叠的外边距都为负,折叠后的外边距的值为最小的负边距的值。这一规则适用于相邻元素和嵌套元素。

# box-shadow 盒子阴影 🔥

同类型的还有text-shadow,用得少,见属性笔记

box-shadow: h-shadow v-shadow blur spread color inset; /* 与顺序无关 */
1
值 描述
h-shadow 必需。水平阴影的位置。正值向右移动,负值向左移动
v-shadow 必需。垂直阴影的位置。正值向下移动,负值向上移动
blur 可选。模糊半径,阴影的发散程度
spread 可选。阴影的尺寸,就是阴影向四周延伸的大小
color 可选。阴影的颜色。请参阅 CSS 颜色值。
inset 可选。将外部阴影 (outset) 改为内部阴影。不能写 outset 否则失效

可以通过,设置多个值

div {
  box-shadow: 5px 5px 10px, -5px -5px 10px; /* 对应x y blur, y x blur. 但是明显对角线割裂了,不推荐 */
}
1
2
3

注意

影子不占用空间,不影响其他盒子排列

编辑 (opens new window)
上次更新: 2022/03/23, 17:55:39
Less
标准流

← Less 标准流→

最近更新
01
重点
04-12
02
搭建项目
04-04
03
TS补充
03-30
更多文章>
Theme by Vdoing | Copyright © 2019-2022 conanan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式