这是我参与「第四届青训营 」笔记创作活动的的第3天,今天基础班没有排课,但对于CSS的布局相关我进行了额外的学习。昨天的课程中,老师讲到了CSS的布局和渲染流程,以及常用的弹性盒布局Flex Box、网格布局Grid布局等。趁着今天空余时间比较充足,我更针对性地对CSS比较重要的知识以及这些布局进行了更深入的学习。
CSS求值过程
首先浏览器拿到HTNL之后,会把HTML解析成一个DOM树。在解析的过程中,会发现<link>、<style>这类样式标签,就把它们组成样式规则。接下来浏览器为了布局和渲染页面,它需要找到页面上每一个元素对应的每一个CSS属性的值。因此它需要遍历到所有的元素,以及所有元素对应的属性的值。
第一步,filtering,筛选样式规则,看样式规则是否匹配。
遍历样式规则,对样式规则用选择器匹配、属性有效、符合当前media这三点进行筛选。这样就能得到一组能够与之匹配的CSS样式规则,称为\textbf\color{blueviolet}{声明值}的(Declared Values)。要注意的是,一个元素某属性的声明值可能有0到多个。
比如要给某个<p>元素设置font-size属性,筛选出来的声明值可能会有p{ font-size:16px;}和p.text{ font-size:1.2em;}两条都能匹配上。
第二步,cascading,选出优先级最高的一个属性值。
按照来源(比如是开发者在页面里写的样式,或者浏览器预置的样式,或者用户通过插件修改等)、!important(样式中写了这个的优先级高于没写的)、选择器特异性、书写顺序等选出优先级最高的一个属性值,称为\textbf\color{blueviolet}{层叠值}(Cascaded Value)。
比如在第一步的例子中,p.text{ font-size:1.2em;}这条样式的优先级更高,就选择1.2em作为层叠值。
第三步,defaulting,获得有且只有一个的值。
要注意的是,有的时候层叠值可能为空,比如没有匹配的声明值。当层叠值为空时,会自动使用继承或初始值。这样就获得了一个唯一的\textbf\color{blueviolet}{指定值}(Specified Value)。
经过cascading和defaulting后,保证指定值一定不为空。但是这个值还不能直接被浏览器用来渲染,例如在第二步的例子中的值为1.2em,这个值是一个相对长度单位。所以指定值还需要进行一些转换。
第四步,resolving,单位转换。
将一些相对值或关键字转换为绝对值,这样得到的值称作\textbf\color{blueviolet}{计算值}(Computed Value)。
比如em转换成px,相对路径转换成绝对路径等。
要注意的是,并不是所有的相对长度都会在这一步被计算,比如60%这样的数值不会被进行转换(将在下一步进行)。
第五步,formatting,进一步单位转换。
将计算值进一步转换,比如关键字、百分比等都转为绝对值这样得到的值称作\textbf\color{blueviolet}{使用值}(Used Value)。使用值是进行实际布局时使用的值,不会再有关键字或相对值。
第六步,constraining,取整。
将小数像素值转为整数,这样得到的值称作\textbf\color{blueviolet}{实际值}。实际值是渲染时实际生效的值。
弹性盒布局Flex Box
子元素的行为受容器flex相关属性的控制,不会再遵循IFC或者BFC,而是遵循Flex布局的上下文规则。一个简单的弹性盒布局如下:
<div class="container">
<div class="a">A</div>
<div class="b">B</div>
<div class="c">C</div>
</div>
<style>
.container {
display: flex;
border: 2px solid #966;
}
.a, .b, .c {
text-align: center;
padding: 1em;
}
.a {
background: #fcc;
}
.b {
background: #cfc;
}
.c {
background: #ccf;
}
</style>
效果:
常用属性
1、Flex布局默认的是从左到右(主轴)的流向,可以通过flex-direction来更改流向。
2、主轴上用
justify-content去做对齐。
3、侧轴上用
align-items去做对齐。
4、即使容器设置了
align-items进行了统一对齐,但是仍然可以给其中某一个元素设置成其他值实现不同的效果。align-self属性可以给某个元素单独进行设置对齐方式。
5、可以设置
order,元素会按照设定好的顺序进行排列。
Flexibility
我们可以把弹性盒中的元素认为是有弹性的元素,可以像弹簧一样压缩和拉伸。
- 可以设置子项的弹性:当容器有剩余空间时伸展,容器空间不够时收缩。
flex-grow有剩余空间时的伸展能力flex-shrink容器空间不足时的收缩能力flex-basis没有伸展或收缩时的基础长度
flex-grow
修改刚才的简单弹性盒布局:
<div class="container">
<div class="a">A</div>
<div class="b">B</div>
<div class="c">C</div>
</div>
<style>
.container {
display: flex;
}
.a, .b, .c {
width: 100px;
}
.a {
flex-grow: 2;
}
.b {
flex-grow: 1;
}
</style>
效果:
A、B、C三个元素原本的宽度都是
100px,但是我们给A的样式设置flex-grow: 2;,给B的样式设置flex-grow: 1;。原本这个容器放置三个宽度100px的盒子还剩余了一些空间,而这样设置之后,容器就会把原本剩余的空间按照2:1的比例分别分给A和B。注意这样设置并不代表A的宽度就是B的两倍,只是把原本剩余的空间按照这样的比例进行额外分配。
flex-shrink
<div class="container">
<div class="a">A</div>
<div class="b">B</div>
<div class="c">C</div>
</div>
<style>
.container {
display: flex;
}
.a, .b, .c {
width: 400px;
}
.a {
flex-shrink: 0;
}
</style>
效果:
A、B、C三个元素原本的宽度都是
400px,但是我们给A的样式设置flex-shrink: 0;这意味着A元素是刚性的,无法被弹性盒压缩,因此A盒子仍保持400px的宽度。但由于容器宽度不够,B和C都被压缩,但没有专门的设置,因此B和C被压缩了同样的程度。
flex
flex-grow、flex-shrink、flex-basis这三者可以缩写成一个flex属性。
| flex | 含义 |
|---|---|
| flex:1 | flex-grow:1 |
| flex:100px | flex-basis:100px |
| flex:2 1 | flex-grow:2; flex-shrink:1 |
| flex:1 100px | flex-grow:1; flex-basis:100px |
| flex:2 0 100px | flex-grow:2; flex-shrink:0; flex-basis:100px |
| flex:auto | flex:1 1 auto |
| flex:none | flex:0 0 auto |
网格布局Grid
弹性盒布局已经是很强大、能实现很多功能的布局方式了,但实际布局中,我们需要的不仅仅是单纯的从左到右或是从上到下的单一方向的布局,因此需要二维的网格布局来进行更好的布局。
与弹性盒的display:flex;相似,网格布局需要写上display:grid;生成一个块级的grid容器。
常用属性
1、使用grid-template来进行网格的划分。简单的划分:
在列上划分为分别占
100px、100px、200px的三列。
在行上划分为分别占100px、100px的两行。
在列上划分为分别占
30%、30%以及一个自动计算宽度(即40%)的三列。
在行上划分为分别占100px以及一个自动计算高度(即容器高度-100px)的两行。
fr是英文单词fraction的缩写。B列和C列各设置
1fr,意为容器宽度-A列所占的100px之后剩下的空间中B列和C列各占一份。
在列上划分为分别占100px、(容器宽度-100px)/2、(容器宽度-100px)/2的三列。
在行上划分为分别占100px、(容器高度-100px)的两行。
2、划分完网格之后,通过网格线grid-line来标识一个个网格,通过grid-row属性和grid-column属性来指定某网格线。
3、通过网格线的编号可以写出每个网格区域grid-area,标识元素所占网格的方式也简化了。
Grid布局非常强大,几乎所有的布局都能通过Grid布局来进行实现。