阅读 386

css_07 | CSS——CSS 基本视觉格式化:① “块盒子”格式化

本文推荐 PC 端阅读~

本文版权归 “公众号 | 前端一万小时” 所有,未经授权,请勿转载!
复制代码

获取编号.png

css_07
复制代码

涉及面试题.png

1. 块级元素和行内元素分别有哪些? 空(void)元素有那些?块级元素和行内元素有什么区别?
2. IE 盒模型和 W3C 盒模型有什么区别?
3. 在什么场景下会出现外边距合并?如何合并?如何不让相邻元素外边距合并?给个父子外边距合并的范例?
4. 关于 .item { width: 100%; },以下说法正确的是:
  ❌ .item 的宽度(包括左右 margin、左右边框、左右 padding、content)等于它父亲的宽度(包括左右 margin、左右边框、左右 padding、content)。
  ❌ .item 的宽度(包括左右边框、左右 padding、content)等于它父亲的宽度(左右边框、左右 padding、content)。
  ❌ .item 的宽度(左右 padding、content)等于它父亲的宽度(左右 padding、content)。
  ✅ .item 的宽度(content)等于它父亲的宽度(content)。
  ❌ 如果设置了 * {box-sizing:border-box},.item 的宽度(包括左右边框、左右 padding、content)等于它父亲的宽度(左右边框、左右 padding、content)。
复制代码

前言: 接下来的几篇系列文章我们讲一个东西:盒子(BOX)。
“盒模型”(box model)作为 CSS 看待元素的一种方式,CSS 将每个元素都看作由一个盒子表示。从某方面来说,对于初级、中级学习者的我们,大可将 CSS 的学习看作是对“盒子”的学习。
为什么这么说?请看下图我个人的 CSS 学习流程:

07-01.png

图中我们可以看到,几乎所有的内容都是围绕着“盒子”这个东西在展开。
本篇我们将阐述最基本的理论知识,将“盒子”的方方面面一步步带到我们跟前。



1 什么是“盒子”

“盒子 box”由 CSS 引擎根据文档中的内容所创建,主要用于文档元素的格式化、定位和布局等。

盒子与元素并不是一一对应的,有时多个元素会合并生成一个盒子,有时一个元素会生成多个盒子(如匿名盒子)。

一个完整的“盒子”中心有一个内容区(content area)。这个内容区周围有可选的 padding、边框和 margin。这些项之所以被认为是可选的,是因为它们的宽度可以设置为 0,实际上就是从“盒子”上去除这些项。

07-02.png
一个完整的“盒子”


2 “视觉格式化模型”概述

CSS 视觉格式化模型(visual formatting model)是用来处理和在视觉媒体上显示文档时使用的计算规则。

通俗的讲就是:页面(文档树)可以想象成是由一个个 box 组合而成的,而“视觉格式化模型(Visual formatting model)” 是一套规则,将这些 box “布局”成访问者看到的样子。

每个盒子的“布局”由以下因素决定(本篇文章和下一篇文章主要讲解第①、②点,其属于“最基本的视觉格式化”,而对于剩下的要点,我们在接下来的系列文章中会挨个讨论):

① 盒子的尺寸:精确指定、由约束条件指定或没有指定;
② 盒子的类型:行内盒子(inline box)、行内级盒子(inline-level box)、原子行内级盒子(atomic inline-level box)、块盒子(block box);

③ 定位方案(positioning scheme):普通流定位、浮动定位或绝对定位;
④ 文档树中的其它元素:即当前盒子的子元素或兄弟元素;
⑤ 视口尺寸与位置;
⑥ 所包含的图片的尺寸;
⑦ 其他的某些外部因素。

07-03.png
每一个元素都是一个“盒子”,“盒子”可以嵌套“盒子”

💡如上图所示,视觉格式化模型会根据盒子的“包含块”(containing block)——(包含其他盒子的块称为“包含块”)的边界来渲染盒子。通常,盒子会创建一个包含其后代元素的“包含块”,但是盒子并不由“包含块”所限制,当盒子的布局跑到”包含块“的外面时称为溢出(overflow)。

上图中,section 的包含块是 body ,header、article、footer 的包含块是 section。

⚠️区别:

  • “盒子模型”是处理盒子本身的内部属性——边距、边框等;
  • 而“视觉格式化模型”是用来处理这些盒子的摆放。

3 关于“盒子”我们一定需要知道的——基本视觉格式化

3.1 “盒子”的生成

盒子的生成是 CSS “视觉格式化模型”的一部分,用于从文档元素生成盒子。

盒子有不同的类型,盒子的类型取决于 CSS 的 display 属性——元素“角色”的改变。

3.1.1 “块级元素”和“块级盒子”

设置元素的 display 属性为 block、list-item 或 table 时,该元素将成为“块级元素”。
这些元素在正常流中时,会在其框之前和之后生成“换行”,所以处于
正常流中的块级元素会“垂直”摆放

选择器 {
    display: block、list-item 或 table;
}
复制代码

💡(“正常流”是指:西方语言文本从左向右、从上向下显示的方向,这也是我们熟悉的传统 HTML 文档的文本布局方向。注意,在非西方语言中,流方向可能不同。)

但,元素是否是“块级元素”仅是元素本身的属性,并不直接用于格式化上下文的创建或布局。
一个“块级元素”会被格式化成一个块(例如文章的一个段落),且默认按照垂直方向依次排列。

💡一个“块级元素”都会至少生成一个“块级盒子”,也有可能生成多个(例如列表项元素)。而“块级盒子”才会参与“块格式化上下文(block formatting context)”的创建。

3.1.2 “行内级元素”和“行内盒子”

当元素的 display 属性为 inline、inline-block 或 inline-table 时,该元素将成为“行内级元素”。

选择器 {
    display: inline、inline-block 或 inline-table;
}
复制代码

这些元素不会在之前或之后生成“行分隔符”,所以处于正常流中的块级元素会 “水平” 摆放,它们是块级元素的后代。

显示时,它不会生成内容块,但是可以与其他行内级内容一起显示为多行。

💡同理,“行内级元素”会生成“行内级盒子”,该盒子同时会参与“行内格式化上下文(inline formatting context)”的创建。

🏆小总结: 相对更详细的“盒子”细分:

07-04.png

⚠️注意: 一定要记得的是,display 之所以得名,是因为它影响的是元素如何“显示”,而不影响他本质上是何种元素,也就不能乱玩“嵌套关系”!
一个极端的反例就是:你不能让一个“链接”来包围一个“段落”。

<a href="http://…" style="display: block;">
<p style="display: inline;">这是一个错误的示例</p>
</a>
复制代码

(对于生成不同类型“盒子”在实际项目中的运用,我们将在后续文章详细讨论。例如:怎样给“链接”加样式——生成导航栏、怎样给“表单”加样式等。)

3.2 不同类型“盒子”在格式化方式上也有所不同

本篇我们主要探讨 “块盒子”格式化,下篇文章讨论“行内盒子”格式化。

07-05.png
块盒子

3.2.1 水平格式化

正常流中,“块盒子”的水平部分 = 其父元素的 width = 7 个属性之和——(margin-left ➕ margin-right) ➕ (padding-left ➕padding-right)➕(border-left➕border-right)➕内容区自身 width 。

在这 7 个属性中只有 3 个属性的值可以设置为 auto:width、margin-left、margin-right。其余的要不必须是确定的值,要不就是默认值 0。

07-06.png

🚀可详细分为以下 5 种组合:

  • 3 个都不是 auto:按 CSS 的术语来讲,这叫“格式化属性过分受限”,此时总会把 margin-right 强制为 auto 来适应父元素的宽度
  • 2 个不是 auto:是 auto 的将自动调整到适应父级元素的宽度;
  • margin-left、margin-right 是 auto:他们会自动设置为相等的长度,导致此元素在其父级元素中居中
  • 一个 margin 和 width 是auto:auto 的 margin 会减为0,width 自动填充其包含块;
  • 3 个都是 auto:两个外边距减为 0,width 会尽可能的宽(自动充满)。

⚠️注意:由于水平 margin 不会合并,父元素的 padding 、边框、margin 可能会对子元素带来“偏移”的影响。

3.2.2 垂直格式化

正常流中,“块盒子”的垂直部分 = 其父元素的 height = 7 个属性之和——(margin-top ➕margin-bottom) ➕ (padding-top ➕padding-bottom)➕(border-top ➕border-bottom)➕内容区自身 height 。

同理,在这 7 个属性中只有 3 个的值可以设置为 auto:height、margin-top、margin-bottom。其余的要不必须是确定的值,要不就是默认值 0。

⚠️不过,margin-top 和 margin-bottom 设置为 auto 也没有什么用,因为会被重置为 0。所以,想利用上下 margin 都是 auto 来垂直居中是不可能的。

07-07.png

垂直格式化的另一个重要方面是垂直相邻 margin 的合并。
这种合并行为只应用于 margin,如果元素有 padding 和边框,padding 和边框是不会合并的。当两个或更多垂直 margin 相遇时,他们将形成唯一一个 margin,这个 margin 的高度等于两个发生叠加的 margin 的高度中的较大者。

⚠️注意:当一个元素包含在另一个元素中时,彼此相邻的 margin-bottom 和 magin-top 也会发生叠加,取较大者。

3.2.3 负 margin

🤔提问:水平或垂直方向各自 7 大属性相加要等于父元素的 width 或 height,那 margin 为负值会造成什么结果?

  1. 水平方向
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
<div>
  <p class="wide">How are you?</p>
  <p>Fine,thank you,and you?</p>
</div>
</body>
</html>
复制代码

(1)类型①

div {
    width: 400px;
    border: 3px solid black;
}

p.wide {
    border: 1px dashed black;
    margin-left: 20px;
    width: auto;
    margin-right: -50px;
    background-color: yellow;
}
复制代码

(2)类型②

div {
    width: 400px;
    border: 3px solid black;
}

p.wide {
    border: 1px dashed black;
    margin-left: 20px;
    width: 500px;
    margin-right: auto;
    background-color: yellow;
}
复制代码

(3)类型③

div {
    width: 400px;
    border: 3px solid black;
}

p.wide {
    border: 1px dashed black;
    margin-left: -50px;
    width: auto;
    margin-right: 10px;
    background-color: yellow;
}
复制代码

07-08.png

  1. 垂直方向
    (1)类型 ①:负 margin-top
    🔗效果及源码链接
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
<div>
  <p class="wide1">How are you?</p>
  <p class="wide2">Fine,thank you,and you?</p>
</div>
</body>
</html>
复制代码
div {
    width: 400px;
    border: 3px solid black;
}

p.wide1 {
    border: 1px dashed black;
    margin-top: -20px;  /*修改这里的值来观察效果*/

    margin-right: 20px;
    margin-bottom: 30px;
    margin-left: 20px;
    width: auto;
    background-color: yellow;
}   
  
p.wide2 {
    border: 1px dashed black;
    margin-top: ;
    margin-right: 20px;
    margin-bottom: ;
    margin-left: 20px;
    width: auto;
    background-color: grey;
}
复制代码

07-09.gif
💡把段落1的 margin-top 设为“负”,它就被向上“拉”了 20 像素,且紧挨它的段落2也相应向上拉了 20 像素。

(2)类型 ②:负 margin-bottom
🔗效果及源码链接

div {
    width: 400px;
    border: 3px solid black;
}

p.wide1 {
    border: 1px dashed black;
    margin-top: px;
    margin-right: 20px;
    margin-bottom: -50px;  /*修改这里的值来观察效果*/

    margin-left: 20px;
    width: auto;
    background-color: yellow;
}   
    
p.wide2 {border: 1px dashed black;
         margin-top: ;
         margin-right: 20px;
         margin-bottom: ;
         margin-left: 20px;
         width: auto;
         background-color: grey;
}
复制代码

07-10.gif
💡把段落1的 margin-bottom 设为“负”,段落2会根据段落1底端的位置放置。

(3)类型 ③:正负 margin 合并
“块盒子”重叠的时候,如果垂直 margin 都为负值,浏览器会取两个 margin 绝对值的最大值;如果一个正 margin 与一个负 margin 合并,则会从正 margin 减去这个负 margin 的绝对值。
🔗效果及源码链接

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
<div>
 <ul>
  <li>Fine</li>
  <li>thank you</li>
  <li>and you?</li>
 </ul>
<p>回答 How are you? 的方式!</p>
</div>
</body>
</html>
复制代码
div {
    width: 400px;
    border: 3px solid black;
}

ul {
    border: 1px dashed black;
    margin-top: px;
    margin-right: 20px;
    margin-bottom: -15px;  /*①修改这里的值来观察效果*/
    margin-left: 20px;
    width: auto;
    background-color: yellow;
}   
    
li {
    border: 1px dashed black;
    margin-top: ;
    margin-right: 20px;
    margin-bottom: 20px;   /*②修改这里的值来观察效果*/
    margin-left: 20px;
    width: auto;
    background-color: grey;
}

p {
    border: 1px dashed black;
    margin-top: -18px;  /*①修改这里的值来观察效果*/
    margin-right: 20px;
    margin-bottom: px;
    margin-left: 20px;
    width: auto;
    background-color: yellow;
}
复制代码

07-11.gif
💡ul 和 p 重叠的 margin 都为“负”,则取绝对值较大者(-18px)
07-12.gif
💡当上边的较大者(-18px)增加到 li 的最大正 margin 上(20px)时,就得到了 20px - 18px =2px



后记: 这篇我们学习了“块盒子”的格式化方式,下一篇我们接着这篇继续探讨“行内盒子”的格式化方式。在“行内盒子”格式化方式中,我们会谈到很多细小的基础知识,和本篇的学习方式一样,让我们尽可能的用代码、用图片来攻克它们。

祝好,qdywxs ♥ you!

关注下面的标签,发现更多相似文章
评论