❝欲望越大,我们需要的奔跑速度就越快;而筋疲力尽之时,便是我们幸福感滑坡之时 ❞
大家好,我是「柒八九」。
今天,我们又开辟了一个新的篇幅 --「前端面试」。即是把一些平时常用的概念和工具方法整理和罗列,也算是一种变向的「未雨绸缪」。
该系列的文章,大部分都是前面文章的知识点汇总,但是也不乏参考其他优秀文章。不过,大家可以放心,里面的代码和知识点,都有迹可循。
好了,天不早了,干点正事哇。
你能所学到的知识点
❝
- 选择器
- 流、元素
- 盒模型
- 元素超出宽度...处理
- 元素隐藏
- 层叠规则
- 块级格式化上下文
- 元素居中
- flex布局
- Chrome支持小于12px 的文字
- CSS 优化处理 (6个)
- 回流、重绘
- 硬件加速
- Css预编译语言
❞
选择器
选择器(.#[]:::
)5个
瞄准目标元素
- 类选择器
- 以
.
开头
- ID选择器
#
开头- 权重相当高
- ID一般指向唯一元素
- 属性选择器
- 含有
[]
的选择器 [title]{}/[title="test"]{}
- 伪类选择器
- 前面有一个冒号(
:
)的选择器 :link
:选择未被访问的链接:visited
:选取已被访问的链接:active
:选择活动链接:hover
:鼠标指针浮动在上面的元素
- 伪元素选择器
- 有连续两个冒号(
::
)的选择器 ::before
: 选择器在被选元素的内容前面插入内容::after
: 选择器在被选元素的内容后面插入内容
关系选择器 (空格>~+
)4个
「根据与其他元素的关系」选择元素的选择器
- 后代选择器
- 选择「所有」合乎规则的后代元素
- 「空格」链接
- 相邻后代选择器
- 仅仅选择合乎规则的「儿子元素」
- 孙子,重孙子元素忽略
>
链接
- 兄弟选择器
- 选择当前元素后面的「所有」合乎规则的「兄弟元素」
~
链接
- 相邻兄弟选择器
- 仅仅选择当前元素相邻的那个合乎规则的兄弟元素
+
链接- 常见的使用场景是,改变紧跟着一个标题的段的某些表现方面
权重
❝
!important
(10000
)- 「内联」(
1000
) - 「ID」选择器(
0100
) - 「类」选择器(
0010
) - 「标签」选择器(
0001
)
❞
上面的优先级计算规则,内联样式的优先级最高,如果外部样式需要覆盖内联样式,就需要使用!important
流、元素
块级元素
常见的块级元素
<div>
<li>
<table>
「块级元素和display为block的元素不是一个概念」
<li>
元素默认的display
值是list-item
<table>
元素默认的display
值是table
基本特征:一个水平流上只能「单独显示」一个元素,多个块级元素则换行显示
由于块级元素具有换行特性,配合clear
属性用来清除浮动
.clear::after{
content:'';
display:table; //或者list-item
clear:both;
}
盒子
❝每个元素都有两个盒子
- 「外在盒子」
- 负责元素是可以一行显示,还是只能换行显示
- 「内在盒子」
- 负责宽高、内容呈现
- ❞
按照display
的属性值不同
block
- 外在盒子:块级盒子
- 内在盒子:块级容器盒子
inline-block
- 外在盒子:内联盒子
- 内在盒子:块级容器盒子
inline
- 外在盒子:内联盒子
- 内在盒子:内联盒子
可以粗略的认为:
display:block ≈ display:block-block
display:inline≈ display:inline-inline
❝「块级盒子负责结构,内联盒子负责内容」 ❞
内联元素
如何区分内联元素
- 从「定义」上:内联元素的内联特指外在盒子
- 从「表现」上:可以和文字在一行显示
幽灵空白节点
在H5文档声明中,内联元素的所有解析和渲染表现就,如同每个「行框盒子」的前面有一个空白节点一样,这个空白节点「永远透明,不占据任何宽度」。表现如同文本节点一样。
幽灵空白节点也是一个盒子,但是一个「假想盒」,名为strut
。
❝一个存在于每个「行框盒子」前面,同时具有该元素的「字体」和「行高」属性的「0宽度的内联盒」 ❞
「行框盒子(line box)」,每一行就是一个行框盒子,每个行框盒子又是由一个个内联盒子组成的。
盒模型
一个盒子由四个部分组成:content
、padding
、border
、margin
content
,即实际内容,显示文本和图像
content
属性大都是用在::before/::after
这两个伪元素中
padding
,即内边距,内容周围的区域
- 内边距是「透明」的
- 取值不能为负
- 受盒子的
background
属性影响 padding
百分比值无论是水平还是垂直方向均是「相对于宽度计算」
boreder
,即边框,围绕元素内容的内边距的一条或多条线,由粗细、样式、颜色三部分组成margin
,即外边距,在元素外创建额外的「空白」,空白通常指不能放其他元素的区域
标准盒模型
- 盒子总宽度 =
width
+padding
+border
+margin
; - 盒子总高度 =
height
+padding
+border
+margin
也就是,width/height
只是「内容宽高」,不包含 padding
和 border
值
IE 怪异盒子模型
- 盒子总宽度 =
width
+margin
; - 盒子总高度 =
height
+margin
;
也就是,width/height
包含了 padding
和 border
值
更改盒模型
CSS 中的 box-sizing
属性定义了引擎应该如何计算一个元素的「总宽度和总高度」
box-sizing: content-box|border-box
content-box
(「默认值」),元素的width/height
不包含padding
,border
,与标准盒子模型表现一致border-box
元素的width/height
包含padding
,border
,与怪异盒子模型表现一致
唯一离不开box-sizing:border-box
的就是:原生普通文本框<input>
和文本域<textarea>
的100%自适应父容器宽度
替换元素的特性之一:尺寸由内部元素决定并且无论其display
属性值是Inline
还是block
也就是说替换元素的宽度却不受display
水平影响
而<textarea>/<input>
就是替换元素,修改<textarea>
的display
为block
是无法让尺寸100%自适应父容器。
通过设置<textarea>
的width为100%,自适应父容器。
textarea{
width:100%;
box-sizing:border-box;
}
❝设计初衷:解决「替换元素」宽度自适应问题 ❞
元素超出宽度...处理
单行 (AKA: TWO)
text-overflow:ellipsis
:当文本溢出时,显示省略符号来代表被修剪的文本white-space:nowrap
:设置文本不换行overflow:hidden
:当子元素内容超过容器宽度高度限制的时候,裁剪的边界是border box
的内边缘- 用三个属性的首字母就是:
TWO
p{
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
width:400px;
}
多行
- 基于高度截断(伪元素 + 定位)
- 基于行数截断()
基于高度截断
关键点height + line-height + ::after + 子绝父相
核心的css代码结构如下:
.text {
position: relative;
line-height: 20px;
height: 40px;
overflow: hidden;
}
.text::after {
content: "...";
position: absolute;
bottom: 0;
right: 0;
padding: 0 20px 0 10px;
}
基于行数截断
关键点:box + line-clamp + box-orient
+ overflow
display: -webkit-box
:将对象作为「弹性伸缩盒子模型」显示-webkit-line-clamp: n
:和①结合使用,用来限制在一个块元素显示的文本的行数(n
)-webkit-box-orient: vertical
:和①结合使用 ,设置或检索伸缩盒对象的子元素的排列方式overflow: hidden
<p>
In this example the <code>-webkit-line-clamp</code> property is set to
<code>3</code>, which means the text is clamped after three lines. An ellipsis
will be shown at the point where the text is clamped.
</p>
css
p {
width: 300px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
显示结果
元素隐藏
可按照隐藏元素「是否占据空间」分为「两大类」(6 + 3)
- 元素不可见,不占空间(
3absolute
+1relative
+1script
+1display
) <script>
display:none
absolute
+visibility:hidden
absolute
+clip:rect(0,0,0,0)
absolute
+opacity:0
relative
+left
负值- 元素不可见,占据空间(3个)
visibility
:hidden
relative
+z-index
负值opacity:0
元素不可见,不占空间
<script>
其他特点:辅助设备无法访问,同时不渲染
<script type="text/html">
<img src="1.jpg">
</script>
display:none
其他特点:辅助设备无法访问,「资源加载,DOM可访问」
对一个元素而言,如果display
计算值是none,则该元素以及所有后代元素都隐藏
.hidden {
display:none;
}
absolute + visibility
其他特点:辅助设备无法访问,但显隐的时候有transition
效果
.hidden{
position:absolute;
visibility:hidden;
}
absolute + clip
其他特点:不能点击,但「键盘可访问」
.hidden{
position:absolute;
clip:rect(0,0,0,0);
}
absolute + opacity
其他特点:可点击
.hidden{
position:absolute;
opacity:0;
}
relative
+负值
其他特点:不能点击,但键盘可访问
.hidden{
position:relative;
left:-999em;
}
元素不可见,占据空间
visibility:hidden
其他特点:不能点击,辅助设备无法访问
visibility
的继承性
- 父元素设置
visibility:hidden
,子元素也看不见 - 但是,如果子元素设置了
visibility:visible
,则「子元素又会显示出来」
.hidden{
visibility:hidden;
}
relative + z-index
其他特点:不能点击,键盘可访问
.hidden{
position:relative;
z-index:-1;
}
opacity:0
.hidden{
opacity:0;
filter:Alpha(opacity=0)
}
总结
最常用的还是display:none
和visibility:hidden
,其他的方式只能认为是奇招,它们的真正用途并不是用于隐藏元素,所以并不推荐使用它们。
关于display: none
、visibility: hidden
、opacity: 0
的区别,如下表所示:
层叠规则
所谓层叠规则,指的是当网页中的元素发生层叠时的表现规则。
❝z-index
:z-index
属性只有和「定位元素」(position
不为static
的元素)在一起的时候才有作用。 ❞
CSS3
中,z-index
已经并非只对定位元素有效,flex
盒子的「子元素」也可以设置z-index
属性。
层叠上下文Stacking Context
层叠上下文Stacking Context是HTML中一个三维概念,如果一个元素含有层叠上下文,可以理解这个元素在「Z轴」上高人一等。
层叠上下文的特性
- 层叠上下文的层叠水平要比普通元素高
- 层叠上下文可以阻断元素的混合模式
- 「层叠上下文可以嵌套,内部层叠上下文及其所有元素均受制于外部的层叠上下文」
- 每个层叠上下文和兄弟元素独立
- 当进行层叠变化或渲染的时候,只需要考虑后代元素
- 每个层叠上下文是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中
层叠上下文的创建(3类)
由一些CSS属性创建
- 「天生派」
- 「页面根元素天生具有层叠上下文」
- 根层叠上下文
- 「正统派」
z-index
值为数值的定位元素的传统层叠上下文
- 「扩招派」
- 其他CSS3属性
根层叠上下文
指的是页面根元素,页面中「所有的元素」一定处于至少一个层叠结界中
定位元素与传统层叠上下文
对于position
值为relative/absolute
的定位元素,当z-index
值不是auto
的时候,会创建层叠上下文。
CSS3属性(8个)
- 元素为
flex
布局元素(父元素display:flex|inline-flex
),同时z-index
值「不是auto」 - 「flex布局」 - 元素的
opactity
值不是1 - 透明度opactity - 元素的
transform
值不是none
- 转换transform - 元素
mix-blend-mode
值不是normal
- 混合模式mix-blend-mode - 元素的
filter
值不是none
- 滤镜filter - 元素的
isolation
值是isolate
- 隔离isolation - 元素的
will-change
属性值为上面②~⑥的任意一个(如will-change:opacity
) - 元素的
-webkit-overflow-scrolling
设为touch
层叠上下文与层叠顺序
❝层叠顺序Stacking Order表示元素发生层叠时有着特定的垂直显示顺序 ❞
一旦普通元素具有层叠上下文,其层叠顺序就会变高
分两种情况
- 如果层叠上下文元素「不依赖」
z-index
数值,则其层叠顺序是z-index:auto
- 可看成
z-index:0
- 如果层叠上下文元素「依赖」
z-index
数值,则其层叠顺序由z-index
值决定
定位元素会层叠在普通元素的上面?
根本原因就是:元素一旦成为「定位元素」,其z-index
就会自动生效,其z-index
就是默认的auto
.
不支持z-index
的层叠上下文元素天然是z-index:auto
级别,「层叠上下文元素」和「定位元素」是一个层叠顺序的。
z-index
z-index负值
「z-index
是支持负值的」,z-index
负值渲染的过程就是一个「寻找第一个层叠上下文元素的过程」,然后层叠顺序止步于这个层叠上下文元素
要实现「父元素覆盖子元素」--正确的解法是把子元素的z-index
设置为负数,这样父元素是一个块级元素,z-index<0
的子元素会在块级元素之下,就可以实现我们想要的效果。
z-index使用准则
对于非浮层元素,避免设置z-index
值,z-index
值没有任何道理需要超过2
定位元素一旦设置了z-index
值,就从普通定位元素变成了层叠上下文元素,相互间的层叠顺序就发生了根本变化,很容易出现设置了巨大的z-index
值无法覆盖其他元素的问题
块级格式化上下文Block Formatting Context
块级格式化上下文Block Formatting Context(「BFC」),它是页面中的一块渲染区域,并且有一套属于自己的渲染规则:
- 内部的盒子会在「垂直方向」一个接一个的放置
- 对于「同一个」BFC的俩个相邻的盒子的「margin会发生重叠,与方向无关」。
- 「每个元素的左外边距与包含块的左边界相接触」(页面布局方向从左到右),即使浮动元素也是如此
- BFC的区域不会与float的元素区域重叠
- 「计算BFC的高度时,浮动子元素也参与计算」
- BFC就是页面上的一个「隔离的独立容器」,容器里面的子元素不会影响到外面的元素,反之亦然
触发条件 (5个)
- 「根元素」,即HTML元素
- 「浮动元素」:
float
值为left、right
overflow
值不为visible
,为auto
、scroll
、hidden
display
的值为inline-block、table、inline-table、flex、inline-flex、grid、inline-grid
position
的值为absolute
或fixed
应用场景
- 防止
margin
重叠
- 将位于同一个BFC的元素,分割到不同的BFC中
- 高度塌陷 --- 「计算BFC的高度时,浮动子元素也参与计算」
- 子元素浮动
- 父元素
overflow: hidden;
构建BFC
- 多栏自适应 --- BFC的区域不会与float的元素区域重叠
margin-left:aside-width
overflow: hidden
构建BFCaside
左浮动main
-->
元素居中
水平居中
- 行内元素-水平居中
text-align:center
- 块级元素-水平居中
- 块级元素
inline-block
化 - 利用
flexbox
margin:0 auto
- 「固定宽度」的块级元素-水平居中
- 「多个块级元素」-水平居中
行内元素-水平居中
// 行内元素-水平居中
.center-inline {
text-align: center;
}
块级元素-水平居中
固定宽度的块级元素-水平居中
// 固定宽度的块级元素-水平居中
.center-block-fixed-width {
margin: 0 auto;
width:78px; // 不能缺
}
多个块级元素-水平居中
// xx 会被后续的特定的类名替换
<main class="xx-center">
<div>
块1
</div>
<div>
块2
</div>
<div>
块3
</div>
</main>
inline-block
// 父元素 设置水平居中
.inline-block-center {
text-align: center;
}
// 块级元素 `inline-block`化
.inline-block-center div {
display: inline-block;
}
flexbox
.flex-center {
display: flex;
justify-content: center;
}
垂直居中
- 行内元素-垂直居中
- 单行
- 多行
table
布局flexbox
- 设置上下
padding:xx
line-height:xx
- 块级元素-垂直居中
flex-direction: column
;justify-content: center
;- 「子绝父相」 + 子元素
top:50%
+transform: translateY(-50%)
- 「子绝父相」 + 子元素
top:50%
+ 子元素负margin
- 元素定高
- 元素高度不确定
flexbox
行内元素-垂直居中
单行
设置padding
.center-text-vertical {
padding-top: 30px;
padding-bottom: 30px;
}
设置line-height
.center-text-vertical-trick {
line-height: 100px;
white-space: nowrap;
}
多行
有如下的HTML结构,我们想实现<p>
元素内文本,在垂直方向居中显示
<div class="xxx">
<p>我是一个多行文本信息 bala bala </p>
</div>
利用display:table
.center-table {
display: table;
}
.center-table p {
display: table-cell;
// 手动指定 垂直方向居中显示
vertical-align: middle;
}
flexbox
.flex-center {
display: flex;
flex-direction: column;
justify-content: center;
height:200px; //这里不能缺少
}
块级元素-垂直居中
元素定高
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
height: 100px;
margin-top: -70px;
padding:20px;
}
元素高度不确定
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
flex
.parent {
display: flex;
flex-direction: column;
justify-content: center;
}
水平垂直居中
- 宽&高固定
absolute
+ 负margin
absolute
+margin auto
absolute
+calc
- 宽&高不固定
absolute
+transform: translate(-50%, -50%);
- flex布局
- grid 布局
宽&高固定
absolute
+ 负 margin
.parent {
position: relative;
}
.child {
width: 300px;
height: 100px;
padding: 20px;
position: absolute;
top: 50%;
left: 50%;
margin: -70px 0 0 -170px;
}
- 初始位置为方块1的位置
- 当设置
left、top
为50%的时候,内部子元素为方块2的位置 - 设置
margin
为负数时,使内部子元素到方块3的位置,即中间位置
absolute
+ margin auto
absolute
+ calc
宽&高不固定
absolute
+ transform: translate(-50%, -50%);
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
flex布局
.parent {
display: flex;
justify-content: center;
align-items: center;
}
grid布局
.parent {
display:grid;
}
.parent .child{
margin:auto;
}
flex 布局
采用flex
布局的元素,称为flex容器Container
它的所有子元素自动成为容器成员,称为flex项目Item
容器默认存在两根轴:水平的主轴main axis和垂直的交叉轴cross axis
容器的属性 (6个)
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
flex-direction属性
flex-direction
属性决定主轴的方向(即项目的排列方向)。
row
(「默认值」):主轴为水平方向,起点在左端。row-reverse
:主轴为水平方向,起点在右端。column
:主轴为垂直方向,起点在上沿。column-reverse
:主轴为垂直方向,起点在下沿。
flex-wrap属性
默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap
属性定义,如果一条轴线排不下,如何换行。
nowrap
:(「默认」):不换行。
wrap
:换行,第一行在上方。
wrap-reverse
:换行,第一行在下方
flex-flow
flex-flow
属性是flex-direction
属性和flex-wrap
属性的简写形式,默认值为row nowrap
。
justify-content属性
justify-content
属性定义了项目在「主轴上的对齐方式」。
flex-start
(「默认值」):左对齐flex-end
:右对齐center
: 居中space-between
:「两端对齐」,项目之间的间隔都相等。
space-around
:每个项目两侧的间隔相等。所以,「项目之间的间隔比项目与边框的间隔大一倍」。
align-items属性
align-items
属性定义项目在「交叉轴上如何对齐」。
stretch
(「默认值」):如果项目未设置高度或设为auto,将占满整个容器的高度。flex-start
:交叉轴的起点对齐。flex-end
:交叉轴的终点对齐。center
:交叉轴的中点对齐。baseline
: 项目的第一行文字的基线对齐。
align-content属性
align-content
属性定义了「多根轴线的对齐方式」。如果项目只有一根轴线,该属性不起作用。
项目的属性(6个)
order
flex-grow
flex-shrink
flex-basis
flex
align-self
order
order
属性定义项目的排列顺序。「数值越小,排列越靠前,默认为0」。
flex-grow
flex-grow
属性定义项目的「放大比例」,「默认为0,即如果存在剩余空间,也不放大」。
如果所有项目的flex-grow
属性都为1,则它们将「等分剩余空间」(如果有的话)。如果一个项目的flex-grow
属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
flex-shrink
flex-shrink
属性定义了项目的「缩小比例」,「默认为1,即如果空间不足,该项目将缩小」。
如果所有项目的flex-shrink
属性都为1,当空间不足时,都将「等比例缩小」。如果一个项目的flex-shrink
属性为0,其他项目都为1,则空间不足时,前者不缩小。
flex-basis属性
flex-basis
属性定义了在「分配多余空间之前」,项目占据的主轴空间main size。浏览器根据这个属性,计算主轴是否有多余空间。「它的默认值为auto,即项目的本来大小」。
它可以设为跟width
或height
属性一样的值(比如350px),则项目「将占据固定空间」。
flex
flex
属性是flex-grow
, flex-shrink
和 flex-basis
的简写,「默认值为0 1 auto」。「后两个属性可选」。
由于,后两个属性可选,所以,存在一些比较简洁的写法
- 「
flex: 1
=flex: 1 1 0%
」 flex: 2
=flex: 2 1 0%
flex: auto
=flex: 1 1 auto
flex: none
=flex: 0 0 auto
,常用于固定尺寸不伸缩
flex:1
和 flex:auto
的区别,可以归结于flex-basis:0
和flex-basis:auto
的区别
当设置为0时(绝对弹性元素),此时相当于告诉flex-grow
和flex-shrink
在伸缩的时候不需要考虑我的尺寸
当设置为auto
时(相对弹性元素),此时则需要在伸缩时将元素尺寸纳入考虑
align-self属性
align-self
属性允许单个项目有与其他项目不一样的对齐方式,「可覆盖align-items
属性。默认值为auto」,表示继承父元素的align-items
属性,如果没有父元素,则等同于stretch
。
Chrome支持小于12px 的文字
Chrome
「中文版浏览器会默认设定页面的最小字号是12px」,英文版没有限制
原由 Chrome
团队认为汉字小于12px就会增加识别难度
- 中文版浏览器 「与网页语言无关」,取决于用户在Chrome的设置里(
chrome://settings/languages
)把哪种语言设置为默认显示语言 - 系统级最小字号 浏览器默认设定页面的最小字号,用户可以前往
chrome://settings/fonts
根据需求更改
解决方案(3种)
zoom
transform:scale()
-webkit-text-size-adjust:none
zoom
zoom
可以改变页面上元素的尺寸,属于真实尺寸。
其支持的值类型有:
zoom:50%
,表示缩小到原来的一半zoom:0.5
,表示缩小到原来的一半
.span10{
font-size: 12px;
display: inline-block;
zoom: 0.8;
}
transform:scale()
用transform:scale()
这个属性进行放缩
使用scale
属性「只对可以定义宽高的元素生效」,所以,需要将指定元素转为行内块元素
.span10{
font-size: 12px;
display: inline-block;
transform:scale(0.8);
}
text-size-adjust
该属性用来设定文字大小是否根据设备(浏览器)来「自动调整显示大小」
属性值:
auto
:「默认」,字体大小会根据设备/浏览器来自动调整;percentage
:字体显示的大小none
:字体大小不会自动调整
「存在兼容性问题,chrome
受版本限制,safari
可以」。
CSS 优化处理 (6个)
- 「内联首屏关键」CSS
- 但是由于TCP的初始拥塞窗口的原因,导致这种方法只能针对CSS文件小的情况
- 「异步加载」CSS
- 使用
rel="preload"
对CSS类资源进行异步加载
- 文件压缩
- 去除无用CSS
- 一种是不同元素或者其他情况下的重复代码
- 一种是整个页面内没有生效的CSS代码
- 「合理使用选择器」
- 不要嵌套使用过多复杂选择器,最好不要三层以上
- 使用id选择器就没必要再进行嵌套
- 通配符和属性选择器效率最低,避免使用
- 不要使用
@import
- css样式文件有「两种引入方式」,
@import
会「影响浏览器的并行下载」,使得页面在加载时增加额外的延迟,增添了额外的往返耗时
- 一种是
link
元素, - 另一种是
@import
回流、重绘
页面渲染的流程, 简单来说,初次渲染时会经过以下6步:
❝
- 构建DOM树;
- 样式计算;
- 「布局定位」;
- 图层分层;
- 「图层绘制」;
- 「合成显示」;
❞
在CSS属性改变时,重渲染会分为「回流」、「重绘」和「直接合成」三种情况,分别对应从「布局定位」/「图层绘制」/「合成显示」开始,再走一遍上面的流程。
元素的CSS具体发生什么改变,则决定属于上面哪种情况:
- 回流(又叫重排):元素「位置、大小」发生变化导致其他节点联动,需要重新计算布局;
- 重绘:修改了一些不影响布局的「属性」,比如颜色;
- 直接合成:「合成层」的
transform、opacity
修改,只需要将多个图层「再次合并」,而后「生成位图」,最终展示到屏幕上;
触发时机
回流触发时机
回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流。
- 添加或删除「可见的DOM元素」
- 元素的「位置」发生变化
- 元素的「尺寸」发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
- 页面一开始渲染的时候(这避免不了)
- 浏览器的「窗口尺寸变化」(因为回流是根据视口的大小来计算元素的位置和大小的)
- 获取一些特定属性的值
offsetTop、offsetLeft、 offsetWidth、offsetHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight
clientTop、clientLeft、clientWidth、clientHeight
- 这些属性有一个共性,就是需要通过「即时计算」得到。因此浏览器为了获取这些值,也会进行回流。
重绘触发时机
❝触发回流一定会触发重绘 ❞
除此之外还有一些其他引起重绘行为:
- 「颜色」的修改
- 「文本方向」的修改
- 「阴影」的修改
浏览器优化机制
由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会「通过队列存储重排操作并批量执行来优化重排过程」。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。
当你获取布局信息的操作的时候,会「强制队列刷新」,例如offsetTop
等方法都会返回最新的数据。
因此浏览器不得不清空队列,触发回流重绘来返回正确的值
减少回流
- 对于那些复杂的动画,对其设置
position: fixed/absolute
,尽可能地使元素脱离文档流,从而减少对其他元素的影响 - 使用css3「硬件加速」,可以让
transform
、opacity
、filters
这些动画不会引起回流重绘 - 在使用
JavaScript
「动态插入多个节点」时, 可以使用DocumentFragment
.创建后一次插入. - 通过设置元素属性
display: none
,将其从页面上去掉,然后再进行后续操作,这些后续操作也不会触发回流与重绘,这个过程称为离线操作
硬件加速
浏览器中的层分为两种:「渲染层」和「合成层」。
渲染层
渲染层的概念跟层叠上下文密切相关。简单来说,拥有z-index
属性的定位元素会生成一个层叠上下文,一个生成层叠上下文的元素就生成了一个渲染层。
层叠上下文的创建(3类)
由一些CSS属性创建
- 天生派
- 页面根元素天生具有层叠上下文
- 根层叠上下文
- 正统派
z-index
值为数值的定位元素的传统层叠上下文
- 扩招派 (CSS3属性)
- 元素为
flex
布局元素(父元素display:flex|inline-flex
),同时z-index
值「不是auto」 - 「flex布局」 - 元素的
opactity
值不是1 - 透明度opactity - 元素的
transform
值不是none
- 转换transform - 元素
mix-blend-mode
值不是normal
- 混合模式mix-blend-mode - 元素的
filter
值不是none
- 滤镜filter - 元素的
isolation
值是isolate
- 隔离isolation - 元素的
will-change
属性值为上面②~⑥的任意一个(如will-change:opacity
) - 元素的
-webkit-overflow-scrolling
设为touch
合成层
「只有一些特殊的渲染层才会被提升为合成层」,通常来说有这些情况:
transform:3D
变换:translate3d
,translateZ
;will-change:opacity | transform | filter
- 对
opacity
|transform
|fliter
应用了过渡和动画(transition/animation
) video、canvas、iframe
硬件加速
浏览器为什么要分层呢?答案是「硬件加速」。就是给HTML元素加上某些CSS属性,比如3D变换,将其提升成一个合成层,「独立渲染」。
之所以叫硬件加速,就是因为「合成层会交给GPU(显卡)去处理」,在硬件层面上开外挂,比在主线程(CPU)上效率更高。
利用硬件加速,可以把需要重排/重绘的元素单独拎出来,减少绘制的面积。
避免重排/重绘,直接进行合成,合成层的transform
和 opacity
的修改都是直接进入合成阶段的;
- 可以使用
transform:translate
代替left/top
修改元素的位置; - 使用
transform:scale
代替宽度、高度的修改;
Css预编译语言
Css预编译语言在前端里面有三大优秀的预编处理器,分别是:
sass
less
stylus
虽然各种预处理器功能强大,但使用最多的,还是以下特性:
- 变量(
variables
)
less
声明的变量必须以@
开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号:
分隔开sass
声明的变量名前面使用$
开头
- 作用域(
scope
) - 代码混合(
mixins
) - 嵌套(
nested rules
) - 代码模块化(
Modules
)
- 模块化就是将Css代码分成一个个模块
@import
后记
「分享是一种态度」。
「全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。」