CSS世界摘记-2
务必了解的 CSS 世界的专业术语
本章节主要涉及CSS属性、值、关键字、变量、选择器等,在此不多做赘述,仅讲解部分特殊内容。
未定义行为
CSS直接中有web的标准来约束元素的行为,但是标准无法面面俱到,所以标准未规定的场景只能由各大浏览器厂家自行实现,这些场景就是未定义行为。具体表现为在部分场景下,不同浏览器的表现不一致。
流、元素与基本尺寸
按照 W3C 的 CSS 规范区分,这里应该分为“块级元素”和“内联级元素” (inline-level element)。但是,在 W3C 的 HTML4 规范中,已经明确把 HTML 元素分成了 “块级元素”和“内联元素”,后续”内联级元素“和”内联元素“都将以”内联元素“称呼。
块级元素
常见的块级元素有<div>
、<li>
、<table>
。
注意,块级元素并不等于display: block
的元素。例如,<li>
的display
为list-item
,<table>
的display
为table
。
“内外盒子”
list-item
最开始,只有块级盒子和内联盒子,但是这个模型无法解释list-item
元素为什么会出现项目符号。
所以,添加了一个标记盒子,用于放置圆点、数字等项目符号,同时为了兼容上面的描述,还需要有一个主块级盒子。
inline-block
这个标签同时具有inline和block的两种特性,上述的模型也无法解释。为了便于理解,我们可以认为每个元素都有至少两个盒子,外在盒子和内在盒子。外在盒子负责流动性的管理(一行显示、换行显示),内在盒子负责元素的宽高、内容呈现。
我们将内在盒子换成更专业的名称——容器盒子。
举个例子:
display: block
的元素是由外在的块级盒子和内在的块级容器盒子构成的。display: inline-block
的元素是由外在的内联盒子和内在的块级容器盒子构成的。display: inline
的元素是由外在的内联盒子和内在的内联容器盒子构成的。
width和height作用在哪里?
width
width的初值:auto
在本菜鸟编写样式代码中,经常会出现宽度不符合预期的情况,很多时候并不知道为什么,只能加些属性调试调试,既浪费时间,也增加了不少的冗余代码,下面我们将讨论width的auto
值。
auto
至少包含了四种不同的宽度表现:
- 充分利用空间,比如
<div>
、<p>
等,表现为width: 100%,叫做fill-available
; - 收缩与包裹,比如浮动、绝对定位、inline-block、table元素等,叫做
shrink-to-fit
,与CSS3中的fit-content一致; - 收缩到最小,比如table-layout为auto的表格中,叫做
minimum content width
,与CSS3中的min-content一致; - 超出容器限制,比如很长的连续英文或数字,或设置了
white-space: nowrap
,与CSS3中的max-content一致;
1 | <div style="width: 200px"> |
外部尺寸与流体特性
上述的auto中的第一条充分利用空间就是外部尺寸。
了解了这些后,我们可以尽量避免代码中的width的显式设置,利用流的特性来实现样式的排布,适配性更高且代码更好维护。
在页面中随便扔一个元素,其尺寸表现就会和这水流 一样铺满容器。这就是 block 容器的流特性。这种特性,所有浏览器的表现都是一致的。
内部尺寸与流体特性
上述的auto中的第二、三、四条都是内部尺寸,下面将一一对应的介绍:
- 包裹性:
这里用<button>
标签来理解:
1 | <div class="box"> |
可以看到,当宽度小于父容器时,按钮的宽度会包裹住内容。
当宽度大于父容器时,按钮会自动换行,并不会超出父容器的宽度。
在开发中有以下场景可以用到这个特性:
此时只需:
1 | .box { |
- 首选最小宽度:
元素的最适合的最小宽度。
- 东亚文字(如中文)的最小宽度为每个汉字的宽度;
- 西亚文字最小宽度由特定的连续的英文字符单元决定;具体可以使用white-space、word-break等属性进行设置;
- 类似图片这样的替换元素的最小宽度就是该元素内容本身的宽度;
- 最大宽度:
最大宽度就是元素可以有的最大宽度。如果内部没有块级元素或者块级元素没有设定宽度值,则“最大宽度”实际上是最大的连 续内联盒子的宽度。
细节
上面我们讨论到元素的宽高是由容器盒子决定的,而容器盒子的结果就是著名的盒模型。
里面对应content-box、padding-box、border-box和margin-box(?)。
但是实际上并没有margin-box,因为没有任何需要用到的场景。margin的背景永远是透明的。
基于以上的前置知识,我们可以推测出,width是作用在content box上的。这样的设定可能带来以下的问题:
- 流动性丢失:如果
width: auto
,则元素会如水流般充满整个容器,而一旦设定了 width 具体数值,则元素的流动性就会被阻断。
使用起来有一定障碍,下面将介绍“宽度分离原则”。
不能出现以下的组合:
1
2
3.box { width: 100px; border: 1px solid; }
或
.box { width: 100px; padding: 20px; }应将width独立占用一层标签,而padding、border、margin 利用流动性在内部自适应呈现。
1
2
3
4
5
6
7
8.father {
width: 180px;
}
.son {
margin: 0 20px;
padding: 20px;
border: 1px solid;
}更加便于维护,代码可读性更强。但也增加新的html节点,有一定的成本。
height
height:auto
比width:auto
简单而单纯的多。因此,宽度的分配规则就比较复杂,高度的就显得比较随意。
height:auto
的表现基本上就是有几个元素盒子,每个多高,累加得到最终值。
当然其他的场景比如说float或者margin等,下面也会具体讨论。
height: 100%
对于height
属性,如果父元素的height为auto,只要子元素在文档流中,其百分比值就被完全忽略了。
比如一个很常见的错误写法:
1 | div { |
结果就是这个div的高度永远是0,即使父级<body>
已经塞满了内容,想实现的话还需要设置:
1 | html, body { |
对于普通文档流中的元素,百分比高度值要想起作用, 其父级必须有一个可以生效的高度值。
1. 为何height: 100%无效?
首先,我们要了解浏览器渲染的基本原理:先下载文档内容,加载头部的 样式资源(如果有的话),然后按照从上而下、自外而内的顺序渲染 DOM 内容。
体现在上面的例子就是:先渲染父元素,后渲染子元素,是有先后顺序的。
因此,当渲染到父元素的时候,子元素的 width:100%并没有渲染,宽度就是图片加文字内容的宽度;等渲染到文字这个子元素的时候, 父元素宽度已经固定,此时的 width:100%就是已经固定好的父元素的宽度。宽度不够怎么办?溢出就好了,overflow 属性就是为此而生的。
高度和宽度的原理类似,但是在规范中,高度的定义是:
如果包含块的高度没有显式指定(即高度由内容决定),并且该元素不是绝对定位,则计算值为 auto。
一句话总结就是:因为解释成了 auto。对于auto进行百分比计算式没有意义的。
宽度的定义是:如果包含块的宽度取决于该元素的宽度,那么产生的布局在 CSS 2.1 中是未定义的。
经过测试,绝大多数浏览器的width计算并不像高度一样变成auto,所以对它的宽度设置百分比是有效的。
2. 如何让元素支持height:100%效果
设置显式的高度值:
1
2
3html, body {
height: 100%;
}使用绝对定位:
1
2
3
4div {
height: 100%;
position: absolute;
}
CSS min-width/max-width和min-height/max-height
这些属性和我们上面讨论的width和height在盒尺寸机制和一些值的渲染规则上是一致的,在此我们不多做讨论。我们主要讨论这几个属性和width和height不一样的地方。
为流体而生的 min-width/max-width
在 CSS 世界中,min-width/max-width 出现的场景一定是自适应布局或者流体布局中。考虑以下两个场景:
现代桌面显示器分辨率越来越大,960 像素网页设计已经显得有些小家碧玉了,但随便搞 一个大尺寸(如 1400 像素)的网页宽度也不合时宜,因为还有很多笔记本用户,此时,一种特 定区间内的自适应布局方案就诞生了,网页宽度在 1200~1400 像素自适应,既满足大屏的大气, 又满足笔记本的良好显示,此时,min-width/max-width 就可以大显神威了:
1
2
3
4.container {
min-width: 1200px;
max-width: 1400px;
}在公众号的热门文章中,经常会有图片,这些图片都是用户上传产生的,因此尺寸会有大 有小,为了避免图片在移动端展示过大影响体验,常常会有下面的 max-width 限制:
1
2
3
4img {
max-width: 100%;
height: auto ;
}height: auto
是必需的,否则,如果原始图片有设定height,max-width 生效的时候, 图片就会被水平压缩。强制height 为 auto 可以确保宽度不超出的同时使图片保持原来的比 例。但这样也会有体验上的问题,那就是在加载时图片占据高度会从 0 变成计算高度,图文会有明显的瀑布式下落。
与众不同的初始值
min-width/max-width 和 min-height/max-height 的初始值则要复杂些。这里要分为两部分,分别是 max-*系列和 min-*系列。 max-width 和 max-height 的初始值是none,min-width 和 min-height 的初始值是auto。
超越!important,超越最大
max-width会覆盖width,而且这种覆盖不是普通的覆盖,它的优先级甚至高于!important。
超越最大指的是min-width覆盖max-width,此规则发生在min-width和max-width 冲突的时候。
当最小宽度比最大宽度设置得还大时,遵循 “超越最大”规则(注意不是“后来居上”规则),min-width 活下来,max-width 被忽略。
内联元素
如何辨别内联元素
- 从定义看:”内联元素“的”内联“特指”外在盒子“,和display为inline不是一个概念;
- 从表现看:“内联元素”的典型特征就是可以和文字在一行显示。因此,文字是内联元素,图片是内联元素,按钮是内联元素,输入框、下拉框等原生表单控件也是内联元素。
内联盒模型
下面是一段很普通的 HTML:
1 | <p>这是一行普通的文字,这里有个 <em>em</em> 标签。</p> |
但是这段HTML中包含了很多种盒子,主要包括:
内容区域:内容区域指一种围绕文字看不见的盒子,其大小仅受字符本身 特性控制,本质上是一个字符盒子(character box);但是有些元素,如图片这样的替换元素,其内 容显然不是文字,不存在字符盒子之类的,因此,对于这些元素,内容区域可以看成元素自身。
内联盒子:“内联盒子”不会让内容成块显示,而是排成一行,这里的“内联盒子”实际指的就是元素的“外在盒子”,用来决定元素是内联还是块级。该盒子又可以细分 为“内联盒子”和“匿名内联盒子”两类:
如果外部含内联标签(
<span>
、<a>
和<em>
等),则属于“内联盒子”(实线框标注);如 果是个光秃秃的文字,则属于“匿名内联盒子”(虚线框标注)。 需要注意的是,并不是所有光秃秃的文字都是“匿名内联盒子”,其还有可能是“匿名块 级盒子”,关键要看前后的标签是内联还是块级。行框盒子:
每一行就是一个“行框盒子”(实线框标注),每个“行框盒子”又是由一个一个“内联盒子” 组成的。
包含盒子:
<p>
标签就是一个“包含盒子”,此盒子由一行一行的“行框盒子”组成。需要补充说明一点,在 CSS 规范中,并没有“包含盒子”的说法,更准确的称呼应该是“包 含块”(containing block)。这里之所以把它称为盒子,一是为了与其他盒子名称统一,二是称 为盒子更形象、更容易理解。
幽灵空白节点
“幽灵空白节点”是内联盒模型中非常重要的一个概念,具体指的是:在 HTML5 文档声明 中,内联元素的所有解析和渲染表现就如同每个行框盒子的前面有一个“空白节点”一样。这 个“空白节点”永远透明,不占据任何宽度,看不见也无法通过脚本获取,就好像幽灵一样, 但又确确实实地存在,表现如同文本节点一样。
1 |
|
虽然说“幽灵空白节点”是我自己根据 CSS 的特性表现起的一个非常形象的名字,但其绝不 是空中楼阁、信口胡诌的。规范中实际上对这个“幽灵空白节点”是有提及的,“幽灵空白节点” 实际上也是一个盒子,不过是个假想盒,名叫“strut”,中文直译为“支柱”,是一个存在于每个“行 框盒子”前面,同时具有该元素的字体和行高属性的 0 宽度的内联盒。