本专栏收录于前端面试手册-CSS系列如果该文章对您有帮助还希望你能点一个小小的订阅,来增加博主创作的动力✍🏻话不多说开始进入正题
回流和重构在前端CSS中是一个常见的问题,那么你对回流何重构有哪些了解呢?
一、什么场景下会触发回流和重构,如何减少回流重构?
想要回答这个问题首先要知道什么是回流和重构,然后从回流重构的
1.什么是回流和重构
重构
当元素的某些属性发生变化,这些属性又只影响元素的外观和风格,而不改变元素的布局、大小比如颜色、背景。 此时触发的浏览器行为称作重构。
回流
当元素的布局、大小规模和显示方式发生改变时,触发的浏览器行为叫回流
浏览器行为规范
首先,要解析HTML和CSS,分贝生成DOM树,CSSOM树,然后将DOM树和CSSOM树结合,生成渲染树
Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
Display:将像素发送给GPU,展示在页面上
2.触发回流情况
①添加或删除可见的DOM元素
②元素的位置发生变化
③元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
④内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
⑤页面一开始渲染的时候(这避免不了)⑥浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
⑥获取一些特定属性的值(该属性们都需要通过计算来得到)
offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight
3.重绘触发时机
触发回流一定会触发重绘,但触发重绘不一定触发回流
元素属性(颜色,阴影,背景颜色等)的修改就是重绘
4.如何使回流重绘得到优化
①如果想设定元素的样式,通过改变元素的 class
类名
②尽量避免内联样式的使用
③应用元素的动画,使用 position
属性的 fixed
值或 absolute
值
④由于table布局中若有一个元素修改,则需要重新计算所有的,所以我们可以避免使用table布局,从而达优化的目的
⑥使元素脱离文档流,从而减少对其他元素的影响
⑦使用css3硬件加速,可以让transform
、opacity
、filters
这些动画不会引起回流重绘
⑧避免使用 CSS 的 JS 表达式
⑨在使用 JavaScript
动态插入多个节点时, 可以使用DocumentFragment
. 创建后一次插入. 就能避免多次的渲染性能
但有时候,我们会无可避免地进行回流或者重绘,我们可以更好使用它们
例如,多次修改一个把元素布局的时候,我们很可能会如下操作
// 获取DOM元素
const div = document.getElementById('div')
// 直接循环遍历应用到DOM上
for(let i=0;i<10;i++) {
div.style.top = div.offsetTop + 100 + "rem";
div.style.left = div.offsetLeft + 100 + "rem";
}
每次循环都需要获取多次offset
属性,所以我们可以以变量的形式参起来,减少每次的计算获取
// 缓存offsetLeft与offsetTop的值
const div = document.getElementById('div')
let offLeft = div.offsetLeft, offTop = div.offsetTop
// 进行计算
for(let i=0;i<10;i++) {
offLeft += 10
offTop += 10
}
// 将计算结果应用到DOM上
div.style.left = offLeft + "rem"
div.style.top = offTop + "rem"
⑩使用类名去合并样式
<style>
.basic_style {
width: 100px;
height: 200px;
border: 10px solid red;
color: red;
}
</style>
<script>
const container = document.getElementById('container')
container.classList.add('basic_style')
</script>
二、如何实现单行或多行文本溢出的省略样式?
1.单行文本溢出省略
概:即的那行文本超出限制则以省略号形式呈现
我们可以使用一下css属性来进行单行文本超出省略号显示
-
text-overflow:规定当文本溢出时,显示省略符号来代表被修剪的文本
text-overflow
属性值有如下:- clip:当对象内文本溢出部分裁切掉
- ellipsis:当对象内文本溢出时显示省略标记(…)
text-overflow
只有在设置了overflow:hidden
和white-space:nowrap
才能够生效的 -
white-space:设置文字在一行显示,不能换行
-
overflow:文字长度超出限定宽度,则隐藏超出的内容
overflow
设为hidden
,普通情况用在块级元素的外层隐藏内部溢出元素
例如:
<style>
p{
overflow: hidden;
line-height: 40px;
width:400px;
height:40px;
border:1px solid green;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
<p 山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼山鱼的活动社区</p >
2.多行文本溢出省略多行文本溢出省略
多行文本溢出两种情况:①基于高度截断②基于行数截断
①基于高度截断
使用为元素+定位的方法实现
- position: relative:为伪元素绝对定位
- overflow: hidden:文本溢出限定的宽度就隐藏内容
- position: absolute:给省略号绝对定位
- line-height: 20px:结合元素高度,高度固定的情况下,设定行高, 控制显示行数
- height: 40px:设定当前元素高度
- ::after {xxx} :设置省略号样式
代码如下所示:
<style>
.shanyu {
position: relative;
line-height: 20px;
height: 40px;
overflow: hidden;
}
.shanyu::after {
position: absolute;
content: "......";
bottom: 0;
right: 0;
padding: 0 20px 0 10px;
}
</style>
<body>
<div class='shanyu'>--------超级超级长的文本——————</div>
</body>
注:该方法就是使用伪元素的绝对定位遮住多出来的文字,然后通过overflow:hidden隐藏超出的文本。若文本存在英文,可设置word-break: break-all
使得单词可拆分
②基于行数截断
使用以下属性实现
①-webkit-line-clamp:2用来限制在一个块元素显示的文本的行数
- display: -webkit-box:和①结合使用,将对象作为弹性伸缩盒子模型显示
- -webkit-box-orient: vertical:和①结合使用 ,设置伸缩盒对象的子元素的排列方式
- overflow: hidden:文本溢出限定的宽度就隐藏内容
- text-overflow: ellipsis:多行文本下,用省略号
...
隐藏溢出范围的文本
<style>
p {
width: 400px;
border-radius: 1px solid red;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<p>
小解的活动社区小解的活动社区小解的活动社区小解的活动社区小解的活动社区小解的活动社区
小解的活动社区小解的活动社区小解的活动社区小解的活动社区小解的活动社区小解的活动社区
</p >
可以看到,上述使用了webkit
的CSS
属性扩展,所以兼容浏览器范围是PC
端的webkit
内核的浏览器,由于移动端大多数是使用webkit
,所以移动端常用该形式。如果文本为一段很长的英文或者数字,则需要添加word-wrap: break-word
属性,还能通过使用javascript
实现配合css
CSS部分
p {
position: relative;
width: 400px;
line-height: 20px;
overflow: hidden;
}
.pEnd:after{
content: "...";
position: absolute;
bottom: 0;
right: 0;
padding-left: 40px;
background: -webkit-linear-gradient(left, transparent, #fff 55%);
background: -moz-linear-gradient(left, transparent, #fff 55%);
background: -o-linear-gradient(left, transparent, #fff 55%);
background: linear-gradient(to right, transparent, #fff 55%);
}
JS部分
$(function(){
//获取文本的行高,并获取文本的高度,假设我们规定的行数是五行,那么对超过行数的部分进行限制高度,并加上省略号
$('p').each(function(i, obj){
// 获取行高
var lineHeight = parseInt($(this).css("line-height"));
// 获取文本高度
var height = parseInt($(this).height());
判断文本的高度比上行高是否大于3
if((height / lineHeight) >3 ){
// 如果超过了3行则添加上面css里面所定义的类名且设置高度为60px
$(this).addClass("pEnd")
$(this).css("height","60px");
}else{
// 否则的话移除类名
$(this).removeClass("pEnd");
}
})
})
三、你是如何理解CSS预编语言
1.CSS是什么
Css
作为一门标记性语言,语法相对简单,对使用者的要求较低,但同时也带来一些问题
如:逻辑性不强,不宜与维护等,所以就出现了预处理语言
2.CSS的预处理语言
扩充了 Css
语言,增加了诸如变量、混合、函数等功能,解决了CSS的逻辑性不强,不易维护等不足,他们通过自己的规则,最终将预处理语言编译为CSS
3.你了解有哪些预处理
三个常用的预编处理
- sass
- less
- stylus
①sass
2007 年诞生,最早也是最成熟的 Css
预处理器,拥有 Ruby 社区的支持和 Compass
这一最强大的 Css
框架,目前受 LESS
影响,已经进化到了全面兼容 Css
的 Scss
。文件后缀名为.sass
与scss
,可以严格按照 sass 的缩进方式省去大括号和分号
②less
2009年出现,受SASS
的影响较大,但又使用 Css
的语法,让大部分开发者和设计师更容易上手,在 Ruby
社区之外支持者远超过 SASS
其缺点是比起 SASS
来,可编程功能不够,不过优点是简单和兼容 Css
,反过来也影响了 SASS
演变到了Scss
的时代
③stylus
Stylus
是一个Css
的预处理框架,2010 年产生,来自 Node.js
社区,主要用来给 Node
项目进行 Css
预处理支持
所以Stylus
是一种新型语言,可以创建健壮的、动态的、富有表现力的Css
。比较年轻,其本质上做的事情与SASS/LESS
等类似
4.他们的区别
常用特性有:
- 变量(variables)
- 作用域(scope)
- 代码混合( mixins)
- 嵌套(nested rules)
- 代码模块化(Modules)
因此,下面就展开这些方面的区别
5.基本使用
/*stylus*/
.box
display: block
/*sass*/
.box
display: block
/*less和scss*/
.box {
display: block;
}
6.嵌套使用
三者的嵌套语法都是一致的,甚至连引用父级选择器的标记 & 也相同区别只是 Sass 和 Stylus 可以用没有大括号的方式书写less
.a {
&.b {
color: red;
}
}
7.变量使用
less
声明的变量必须以@
开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号:
分隔开
@red: #c00;
strong {
color: @red;
}
sass
声明的变量跟less
十分的相似,只是变量名前面使用@
开头
$red: #c00;
strong {
color: $red;
}
stylus
red = #FFFFFF
strong
color: red
8.作用域
Css
预编译器把变量赋予作用域,也就是存在生命周期。就像 js
一样,它会先从局部作用域查找变量,依次向上级作用域查找sass
中不存在全局变量,所以,在sass
中最好不要定义相同的变量名
$color: black;
.scoped {
$bg: blue;
$color: white;
color: $color;
background-color:$bg;
}
.unscoped {
color:$color;
}
less
与stylus
的作用域跟javascript
十分的相似,首先会查找局部定义的变量,如果没有找到,会像冒泡一样,一级一级往下查找,直到最外层为止
@color: black;
.scoped {
@bg: blue;
@color: white;
color: @color;
background-color:@bg;
}
.unscoped {
color:@color;
}
9.预处理器的混入mixin
混入(mixin)应该说是预处理器最精髓的功能之一了,简单点来说,Mixins
可以将一部分样式抽出,作为单独定义的模块,被很多选择器重复使用
可以在Mixins
中定义变量或者默认参数
在less
中,混合的用法是指将定义好的ClassA
中引入另一个已经定义的Class
,也能使用够传递参数,参数变量为@
声明
.alert {
font-weight: 700;
}
.highlight(@color: red) {
font-size: 1.2em;
color: @color;
}
.heads-up {
.alert;
.highlight(red);
}
Sass
声明mixins
时需要使用@mixinn
,后面紧跟mixin
的名,也可以设置参数,参数名为变量$
声明的形式
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}
stylus
中的混合和前两款Css
预处理器语言的混合有些许不同,他可以不使用任何符号,就是直接声明Mixins
名,然后在定义参数和默认值之间用等号=
来连接
error(borderWidth= 2px) {
border: borderWidth solid #F00;
color: #F00;
}
.generic-error {
padding: 20px;
margin: 4px;
error(); /* 调用error mixins */
}
.login-error {
left: 12px;
position: absolute;
top: 20px;
error(5px); /* 调用error mixins,并将参数$borderWidth的值指定为5px */
}
10.代码模块化
模块化就是将Css
代码分成一个个模块
scss
、less
、stylus
三者的使用方法都如下所示
@import './common';
@import './github-markdown';
@import './mixin';
@import './variables';