前端面试之CSS重点概念精讲

CSS/设计
368
0
0
2023-01-17
标签   前端面试
❝欲望越大,我们需要的奔跑速度就越快;而筋疲力尽之时,便是我们幸福感滑坡之时 ❞

大家好,我是「柒八九」

今天,我们又开辟了一个新的篇幅 --「前端面试」。即是把一些平时常用的概念和工具方法整理和罗列,也算是一种变向的「未雨绸缪」

该系列的文章,大部分都是前面文章的知识点汇总,但是也不乏参考其他优秀文章。不过,大家可以放心,里面的代码和知识点,都有迹可循。

好了,天不早了,干点正事哇。

img

你能所学到的知识点

  1. 选择器
  2. 流、元素
  3. 盒模型
  4. 元素超出宽度...处理
  5. 元素隐藏
  6. 层叠规则
  7. 块级格式化上下文
  8. 元素居中
  9. flex布局
  10. Chrome支持小于12px 的文字
  11. CSS 优化处理 (6个)
  12. 回流、重绘
  13. 硬件加速
  14. Css预编译语言

选择器

选择器(.#[]:::)5个

瞄准目标元素

  1. 类选择器
  • .开头
  1. ID选择器
  • #开头
  • 权重相当高
  • ID一般指向唯一元素
  1. 属性选择器
  • 含有[]的选择器
  • [title]{}/[title="test"]{}
  1. 伪类选择器
  • 前面有一个冒号(:)的选择器
  • :link :选择未被访问的链接
  • :visited:选取已被访问的链接
  • :active:选择活动链接
  • :hover :鼠标指针浮动在上面的元素
  1. 伪元素选择器
  • 有连续两个冒号(::)的选择器
  • ::before : 选择器在被选元素的内容前面插入内容
  • ::after : 选择器在被选元素的内容后面插入内容

关系选择器 (空格>~+)4个

「根据与其他元素的关系」选择元素的选择器

  1. 后代选择器
  • 选择「所有」合乎规则的后代元素
  • 「空格」链接
  1. 相邻后代选择器
  • 仅仅选择合乎规则的「儿子元素」
  • 孙子,重孙子元素忽略
  • >链接
  1. 兄弟选择器
  • 选择当前元素后面的「所有」合乎规则的「兄弟元素」
  • ~链接
  1. 相邻兄弟选择器
  • 仅仅选择当前元素相邻的那个合乎规则的兄弟元素
  • +链接
  • 常见的使用场景是,改变紧跟着一个标题的段的某些表现方面

权重

  1. !important (10000)
  2. 「内联」1000
  3. 「ID」选择器(0100
  4. 「类」选择器(0010
  5. 「标签」选择器(0001

img

上面的优先级计算规则,内联样式的优先级最高,如果外部样式需要覆盖内联样式,就需要使用!important

流、元素

块级元素

常见的块级元素

  • <div>
  • <li>
  • <table>

「块级元素和display为block的元素不是一个概念」

  • <li>元素默认的display值是list-item
  • <table>元素默认的display值是table

基本特征:一个水平流上只能「单独显示」一个元素,多个块级元素则换行显示

由于块级元素具有换行特性,配合clear属性用来清除浮动

.clear::after{
     content:'';
     display:table; //或者list-item 
     clear:both;
}

盒子

❝每个元素都有两个盒子
  1. 「外在盒子」
  • 负责元素是可以一行显示,还是只能换行显示
  1. 「内在盒子」
  • 负责宽高、内容呈现

按照display的属性值不同

  1. block
  • 外在盒子:块级盒子
  • 内在盒子:块级容器盒子
  1. inline-block
  • 外在盒子:内联盒子
  • 内在盒子:块级容器盒子
  1. inline
  • 外在盒子:内联盒子
  • 内在盒子:内联盒子

可以粗略的认为:

display:block ≈ display:block-block
display:inline≈ display:inline-inline
「块级盒子负责结构,内联盒子负责内容」

内联元素

如何区分内联元素

  1. 「定义」上:内联元素的内联特指外在盒子
  2. 「表现」上:可以和文字在一行显示

幽灵空白节点

在H5文档声明中,内联元素的所有解析和渲染表现就,如同每个「行框盒子」的前面有一个空白节点一样,这个空白节点「永远透明,不占据任何宽度」。表现如同文本节点一样。

幽灵空白节点也是一个盒子,但是一个「假想盒」,名为strut

❝一个存在于每个「行框盒子」前面,同时具有该元素的「字体」「行高」属性的「0宽度的内联盒」

「行框盒子(line box)」,每一行就是一个行框盒子,每个行框盒子又是由一个个内联盒子组成的。

盒模型

一个盒子由四个部分组成:contentpaddingbordermargin

  1. content,即实际内容,显示文本和图像
  • content 属性大都是用在::before/::after这两个伪元素中
  1. padding,即内边距,内容周围的区域
  • 内边距是「透明」
  • 取值不能为负
  • 受盒子的background属性影响
  • padding 百分比值无论是水平还是垂直方向均是「相对于宽度计算」
  1. boreder,即边框,围绕元素内容的内边距的一条或多条线,由粗细、样式、颜色三部分组成
  2. margin,即外边距,在元素外创建额外的「空白」,空白通常指不能放其他元素的区域

img

标准盒模型

img

  • 盒子总宽度 = width + padding + border + margin;
  • 盒子总高度 = height + padding + border + margin

也就是,width/height 只是「内容宽高」,不包含 paddingborder

IE 怪异盒子模型

img

  • 盒子总宽度 = width + margin;
  • 盒子总高度 = height + margin;

也就是,width/height 包含了 paddingborder

更改盒模型

CSS 中的 box-sizing 属性定义了引擎应该如何计算一个元素的「总宽度和总高度」

box-sizing: content-box|border-box
  1. content-box (「默认值」),元素的 width/height 不包含paddingborder,与标准盒子模型表现一致
  2. border-box 元素的 width/height 包含 paddingborder,与怪异盒子模型表现一致

唯一离不开box-sizing:border-box的就是:原生普通文本框<input>和文本域<textarea>的100%自适应父容器宽度

替换元素的特性之一:尺寸由内部元素决定并且无论其display属性值是Inline还是block也就是说替换元素的宽度却不受display水平影响

<textarea>/<input>就是替换元素,修改<textarea>displayblock是无法让尺寸100%自适应父容器。

通过设置<textarea>的width为100%,自适应父容器。

textarea{
 width:100%;
 box-sizing:border-box;
}
❝设计初衷:解决「替换元素」宽度自适应问题 ❞

元素超出宽度...处理

单行 (AKA: TWO)

  1. text-overflow:ellipsis:当文本溢出时,显示省略符号来代表被修剪的文本
  2. white-space:nowrap:设置文本不换行
  3. overflow:hidden:当子元素内容超过容器宽度高度限制的时候,裁剪的边界是border box的内边缘
  4. 用三个属性的首字母就是:TWO
p{
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
    width:400px;
  }

多行

  1. 基于高度截断(伪元素 + 定位)
  2. 基于行数截断()

基于高度截断

关键点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

  1. display: -webkit-box:将对象作为「弹性伸缩盒子模型」显示
  2. -webkit-line-clamp: n:和①结合使用,用来限制在一个块元素显示的文本的行数(n)
  3. -webkit-box-orient: vertical:和①结合使用 ,设置或检索伸缩盒对象的子元素的排列方式
  4. 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;
}

img

显示结果

元素隐藏

可按照隐藏元素「是否占据空间」分为「两大类」(6 + 3)

  1. 元素不可见,不占空间(3absolute+1relative+1script+1display)
  2. <script>
  3. display:none
  4. absolute + visibility:hidden
  5. absolute + clip:rect(0,0,0,0)
  6. absolute + opacity:0
  7. relative+left负值
  8. 元素不可见,占据空间(3个)
  9. visibility:hidden
  10. relative + z-index负值
  11. 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:nonevisibility:hidden,其他的方式只能认为是奇招,它们的真正用途并不是用于隐藏元素,所以并不推荐使用它们。

关于display: nonevisibility: hiddenopacity: 0的区别,如下表所示:

img

层叠规则

所谓层叠规则,指的是当网页中的元素发生层叠时的表现规则。

z-index:z-index属性只有和「定位元素」(position不为static的元素)在一起的时候才有作用。 ❞

CSS3中,z-index已经并非只对定位元素有效,flex盒子的「子元素」也可以设置z-index属性。

层叠上下文Stacking Context

层叠上下文Stacking Context是HTML中一个三维概念,如果一个元素含有层叠上下文,可以理解这个元素在「Z轴」上高人一等。

层叠上下文的特性

  • 层叠上下文的层叠水平要比普通元素高
  • 层叠上下文可以阻断元素的混合模式
  • 「层叠上下文可以嵌套,内部层叠上下文及其所有元素均受制于外部的层叠上下文」
  • 每个层叠上下文和兄弟元素独立
  • 当进行层叠变化或渲染的时候,只需要考虑后代元素
  • 每个层叠上下文是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中

层叠上下文的创建(3类)

由一些CSS属性创建

  1. 「天生派」
  • 「页面根元素天生具有层叠上下文」
  • 根层叠上下文
  1. 「正统派」
  • z-index值为数值的定位元素的传统层叠上下文
  1. 「扩招派」
  • 其他CSS3属性

根层叠上下文

指的是页面根元素,页面中「所有的元素」一定处于至少一个层叠结界中

定位元素与传统层叠上下文

对于position值为relative/absolute的定位元素,当z-index值不是auto的时候,会创建层叠上下文。

CSS3属性(8个)

  1. 元素为flex布局元素(父元素display:flex|inline-flex),同时z-index「不是auto」 - 「flex布局」
  2. 元素的opactity值不是1 - 透明度opactity
  3. 元素的transform值不是none - 转换transform
  4. 元素mix-blend-mode值不是normal - 混合模式mix-blend-mode
  5. 元素的filter值不是none - 滤镜filter
  6. 元素的isolation值是isolate - 隔离isolation
  7. 元素的will-change属性值为上面②~⑥的任意一个(如will-change:opacity
  8. 元素的-webkit-overflow-scrolling设为touch

层叠上下文与层叠顺序

❝层叠顺序Stacking Order表示元素发生层叠时有着特定的垂直显示顺序 ❞

一旦普通元素具有层叠上下文,其层叠顺序就会变高

分两种情况

  1. 如果层叠上下文元素「不依赖」z-index数值,则其层叠顺序是z-index:auto
  • 可看成z-index:0
  1. 如果层叠上下文元素「依赖」z-index数值,则其层叠顺序由z-index值决定

img

定位元素会层叠在普通元素的上面?

根本原因就是:元素一旦成为「定位元素」,其z-index就会自动生效,其z-index就是默认的auto.

不支持z-index的层叠上下文元素天然是z-index:auto级别,「层叠上下文元素」「定位元素」是一个层叠顺序的。

z-index

z-index负值

z-index是支持负值的」,z-index负值渲染的过程就是一个「寻找第一个层叠上下文元素的过程」,然后层叠顺序止步于这个层叠上下文元素

要实现「父元素覆盖子元素」--正确的解法是把子元素的z-index设置为负数,这样父元素是一个块级元素,z-index<0 的子元素会在块级元素之下,就可以实现我们想要的效果。

img

z-index使用准则

对于非浮层元素,避免设置z-index值,z-index值没有任何道理需要超过2

定位元素一旦设置了z-index值,就从普通定位元素变成了层叠上下文元素,相互间的层叠顺序就发生了根本变化,很容易出现设置了巨大的z-index值无法覆盖其他元素的问题

块级格式化上下文Block Formatting Context

块级格式化上下文Block Formatting Context(「BFC」),它是页面中的一块渲染区域,并且有一套属于自己的渲染规则:

  1. 内部的盒子会在「垂直方向」一个接一个的放置
  2. 对于「同一个」BFC的俩个相邻的盒子的「margin会发生重叠,与方向无关」
  3. 「每个元素的左外边距与包含块的左边界相接触」(页面布局方向从左到右),即使浮动元素也是如此
  4. BFC的区域不会与float的元素区域重叠
  5. 「计算BFC的高度时,浮动子元素也参与计算」
  6. BFC就是页面上的一个「隔离的独立容器」,容器里面的子元素不会影响到外面的元素,反之亦然

触发条件 (5个)

  1. 「根元素」,即HTML元素
  2. 「浮动元素」float值为left、right
  3. overflow值不为 visible,为 autoscrollhidden
  4. display的值为inline-block、table、inline-table、flex、inline-flex、grid、inline-grid
  5. position 的值为absolutefixed

应用场景

  1. 防止margin重叠
  • 将位于同一个BFC的元素,分割到不同的BFC中
  1. 高度塌陷 --- 「计算BFC的高度时,浮动子元素也参与计算」
  • 子元素浮动
  • 父元素 overflow: hidden;构建BFC
  1. 多栏自适应 --- BFC的区域不会与float的元素区域重叠
  • margin-left:aside-width
  • overflow: hidden构建BFC
  • aside 左浮动
  • main -->

元素居中

水平居中

  1. 行内元素-水平居中
  • text-align:center
  1. 块级元素-水平居中
  • 块级元素inline-block
  • 利用flexbox
  • margin:0 auto
  • 「固定宽度」的块级元素-水平居中
  • 「多个块级元素」-水平居中

行内元素-水平居中

// 行内元素-水平居中
.center-inline {
  text-align: center;
}

块级元素-水平居中

固定宽度的块级元素-水平居中

// 固定宽度的块级元素-水平居中
.center-block-fixed-width {
  margin: 0 auto;
  width:78px; // 不能缺
}

多个块级元素-水平居中

img

// 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;
}

垂直居中

  1. 行内元素-垂直居中
  • 单行
  • 多行
  1. table布局
  2. flexbox
  3. 设置上下padding:xx
  4. line-height:xx
  5. 块级元素-垂直居中
  • 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;
}

水平垂直居中

  1. 宽&高固定
  2. absolute + 负 margin
  3. absolute + margin auto
  4. absolute + calc
  5. 宽&高不固定
  6. absolute + transform: translate(-50%, -50%);
  7. flex布局
  8. grid 布局

宽&高固定

absolute + 负 margin

.parent {
  position: relative;
}

.child {
  width: 300px;
  height: 100px;
  padding: 20px;

  position: absolute;
  top: 50%;
  left: 50%;

  margin: -70px 0 0 -170px;
}

img

  • 初始位置为方块1的位置
  • 当设置left、top为50%的时候,内部子元素为方块2的位置
  • 设置margin为负数时,使内部子元素到方块3的位置,即中间位置

absolute + margin auto

img

absolute + calc

img

宽&高不固定

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

img

容器默认存在两根轴:水平的主轴main axis和垂直的交叉轴cross axis

容器的属性 (6个)

  1. flex-direction
  2. flex-wrap
  3. flex-flow
  4. justify-content
  5. align-items
  6. align-content

flex-direction属性

flex-direction属性决定主轴的方向(即项目的排列方向)。

  1. row「默认值」):主轴为水平方向,起点在左端。
  2. row-reverse:主轴为水平方向,起点在右端。
  3. column:主轴为垂直方向,起点在上沿。
  4. column-reverse:主轴为垂直方向,起点在下沿。

flex-wrap属性

默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。

  1. nowrap:(「默认」):不换行。

  1. img
  2. wrap:换行,第一行在上方。

  1. img
  2. wrap-reverse:换行,第一行在下方

  1. img

flex-flow

flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

justify-content属性

justify-content属性定义了项目在「主轴上的对齐方式」

  1. flex-start「默认值」):左对齐
  2. flex-end:右对齐
  3. center: 居中
  4. space-between「两端对齐」,项目之间的间隔都相等。

  1. img
  2. space-around:每个项目两侧的间隔相等。所以,「项目之间的间隔比项目与边框的间隔大一倍」

  1. img

align-items属性

align-items属性定义项目在「交叉轴上如何对齐」

  1. stretch「默认值」):如果项目未设置高度或设为auto,将占满整个容器的高度。
  2. flex-start:交叉轴的起点对齐。
  3. flex-end:交叉轴的终点对齐。
  4. center:交叉轴的中点对齐。
  5. baseline: 项目的第一行文字的基线对齐。

align-content属性

align-content属性定义了「多根轴线的对齐方式」。如果项目只有一根轴线,该属性不起作用。

项目的属性(6个)

  1. order
  2. flex-grow
  3. flex-shrink
  4. flex-basis
  5. flex
  6. align-self

order

order属性定义项目的排列顺序。「数值越小,排列越靠前,默认为0」

img

flex-grow

flex-grow属性定义项目的「放大比例」「默认为0,即如果存在剩余空间,也不放大」

如果所有项目的flex-grow属性都为1,则它们将「等分剩余空间」(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

img

flex-shrink

flex-shrink属性定义了项目的「缩小比例」「默认为1,即如果空间不足,该项目将缩小」

如果所有项目的flex-shrink属性都为1,当空间不足时,都将「等比例缩小」。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

img

flex-basis属性

flex-basis属性定义了在「分配多余空间之前」,项目占据的主轴空间main size。浏览器根据这个属性,计算主轴是否有多余空间。「它的默认值为auto,即项目的本来大小」

它可以设为跟widthheight属性一样的值(比如350px),则项目「将占据固定空间」

flex

flex属性是flex-grow, flex-shrinkflex-basis的简写,「默认值为0 1 auto」「后两个属性可选」

由于,后两个属性可选,所以,存在一些比较简洁的写法

  1. flex: 1 = flex: 1 1 0%
  2. flex: 2 = flex: 2 1 0%
  3. flex: auto = flex: 1 1 auto
  4. flex: none = flex: 0 0 auto,常用于固定尺寸不伸缩

flex:1flex:auto 的区别,可以归结于flex-basis:0flex-basis:auto的区别

当设置为0时(绝对弹性元素),此时相当于告诉flex-growflex-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种)

  1. zoom
  2. transform:scale()
  3. -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个)

  1. 「内联首屏关键」CSS
  • 但是由于TCP的初始拥塞窗口的原因,导致这种方法只能针对CSS文件小的情况
  1. 「异步加载」CSS
  • 使用rel="preload"对CSS类资源进行异步加载
  1. 文件压缩
  2. 去除无用CSS
  3. 一种是不同元素或者其他情况下的重复代码
  4. 一种是整个页面内没有生效的CSS代码
  5. 「合理使用选择器」
  • 不要嵌套使用过多复杂选择器,最好不要三层以上
  • 使用id选择器就没必要再进行嵌套
  • 通配符和属性选择器效率最低,避免使用
  1. 不要使用@import
  • css样式文件有「两种引入方式」
  • @import「影响浏览器的并行下载」,使得页面在加载时增加额外的延迟,增添了额外的往返耗时
  1. 一种是link元素,
  2. 另一种是@import

回流、重绘

页面渲染的流程, 简单来说,初次渲染时会经过以下6步:

  1. 构建DOM树;
  2. 样式计算;
  3. 「布局定位」
  4. 图层分层;
  5. 「图层绘制」
  6. 「合成显示」

在CSS属性改变时,重渲染会分为「回流」「重绘」「直接合成」三种情况,分别对应从「布局定位」/「图层绘制」/「合成显示」开始,再走一遍上面的流程。

元素的CSS具体发生什么改变,则决定属于上面哪种情况:

  • 回流(又叫重排):元素「位置、大小」发生变化导致其他节点联动,需要重新计算布局;
  • 重绘:修改了一些不影响布局的「属性」,比如颜色;
  • 直接合成:「合成层」transform、opacity修改,只需要将多个图层「再次合并」,而后「生成位图」,最终展示到屏幕上;

触发时机

回流触发时机

回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流。

  • 添加或删除「可见的DOM元素」
  • 元素的「位置」发生变化
  • 元素的「尺寸」发生变化(包括外边距、内边框、边框大小、高度和宽度等)
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
  • 页面一开始渲染的时候(这避免不了)
  • 浏览器的「窗口尺寸变化」(因为回流是根据视口的大小来计算元素的位置和大小的)
  • 获取一些特定属性的值
  • offsetTop、offsetLeft、 offsetWidth、offsetHeight
  • scrollTop、scrollLeft、scrollWidth、scrollHeight
  • clientTop、clientLeft、clientWidth、clientHeight
  • 这些属性有一个共性,就是需要通过「即时计算」得到。因此浏览器为了获取这些值,也会进行回流。

重绘触发时机

❝触发回流一定会触发重绘 ❞

除此之外还有一些其他引起重绘行为:

  • 「颜色」的修改
  • 「文本方向」的修改
  • 「阴影」的修改

浏览器优化机制

由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会「通过队列存储重排操作并批量执行来优化重排过程」。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。

当你获取布局信息的操作的时候,会「强制队列刷新」,例如offsetTop等方法都会返回最新的数据。

因此浏览器不得不清空队列,触发回流重绘来返回正确的值

减少回流

  1. 对于那些复杂的动画,对其设置 position: fixed/absolute,尽可能地使元素脱离文档流,从而减少对其他元素的影响
  2. 使用css3「硬件加速」,可以让transformopacityfilters这些动画不会引起回流重绘
  3. 在使用 JavaScript 「动态插入多个节点」时, 可以使用DocumentFragment.创建后一次插入.
  4. 通过设置元素属性display: none,将其从页面上去掉,然后再进行后续操作,这些后续操作也不会触发回流与重绘,这个过程称为离线操作

硬件加速

浏览器中的层分为两种:「渲染层」「合成层」

渲染层

渲染层的概念跟层叠上下文密切相关。简单来说,拥有z-index属性的定位元素会生成一个层叠上下文,一个生成层叠上下文的元素就生成了一个渲染层。

层叠上下文的创建(3类)

由一些CSS属性创建

  1. 天生派
  • 页面根元素天生具有层叠上下文
  • 根层叠上下文
  1. 正统派
  • z-index值为数值的定位元素的传统层叠上下文
  1. 扩招派 (CSS3属性)
  2. 元素为flex布局元素(父元素display:flex|inline-flex),同时z-index「不是auto」 - 「flex布局」
  3. 元素的opactity值不是1 - 透明度opactity
  4. 元素的transform值不是none - 转换transform
  5. 元素mix-blend-mode值不是normal - 混合模式mix-blend-mode
  6. 元素的filter值不是none - 滤镜filter
  7. 元素的isolation值是isolate - 隔离isolation
  8. 元素的will-change属性值为上面②~⑥的任意一个(如will-change:opacity
  9. 元素的-webkit-overflow-scrolling设为touch

合成层

「只有一些特殊的渲染层才会被提升为合成层」,通常来说有这些情况:

  1. transform:3D变换:translate3dtranslateZ
  2. will-change:opacity | transform | filter
  3. opacity | transform | fliter 应用了过渡和动画(transition/animation
  4. video、canvas、iframe

硬件加速

浏览器为什么要分层呢?答案是「硬件加速」。就是给HTML元素加上某些CSS属性,比如3D变换,将其提升成一个合成层,「独立渲染」

之所以叫硬件加速,就是因为「合成层会交给GPU(显卡)去处理」,在硬件层面上开外挂,比在主线程(CPU)上效率更高。

利用硬件加速,可以把需要重排/重绘的元素单独拎出来,减少绘制的面积。

避免重排/重绘,直接进行合成,合成层的transformopacity的修改都是直接进入合成阶段的;

  • 可以使用transform:translate代替left/top修改元素的位置;
  • 使用transform:scale代替宽度、高度的修改;

Css预编译语言

Css预编译语言在前端里面有三大优秀的预编处理器,分别是:

  1. sass
  2. less
  3. stylus

虽然各种预处理器功能强大,但使用最多的,还是以下特性:

  1. 变量(variables
  • less声明的变量必须以@开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号:分隔开
  • sass声明的变量名前面使用$开头
  1. 作用域(scope
  2. 代码混合( mixins
  3. 嵌套(nested rules
  4. 代码模块化(Modules
  • 模块化就是将Css代码分成一个个模块
  • @import

后记

「分享是一种态度」

「全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。」