每天10个前端小知识(1day)
一、var和let的区别
1、var是函数作用域,let是块级作用域。
在函数中声明了var,整个函数内都是有效的,比如说在for循环内定义的一个var变量,实际上其在for循环以外也是可以访问的。
而let由于是块作用域,所以如果在块作用域内定义的变量,比如说在for循环内,在其外面是不可被访问的,所以for循环推荐用let。
for (var i = 0;i<10;i++){}console.log('i的值是:'+i)for (let j = 0;j<10;j++){}console.log('i的值是:'+j)
2、let不能在定义之前访问该变量,但是var可以
let必须先声明,在使用。而var先使用后声明也行,只不过直接使用但没有定义的时候,其值是undefined。var有一个变量提升的过程,当整个函数作用域被创建的时候,实际上var定义的变量都会被创建,并且如果此时没有初始化的话,则默认为初始化一个undefined
console.log(t); //undefinedvar t = 'hello!';console.log(t) //hello!console.log(b); //Uncaught ReferenceError: Cannot access 'b' before initializationlet b = 'hello!';console.log(b)
3、let不能被重新定义,但是var可以
var v = 100;console.log(v) //100; var v=200console.log(v) //200; let v = 100;console.log(v) //Uncaught SyntaxError: Identifier 'v' has already been declared; let v=200console.log(v) ;
二、说说你对盒子模型的理解
1、是什么?
当对一个文档进行布局(layout)的时候,浏览器的渲染引擎会根据标准之一的 CSS 基础框盒模型(CSS basic box model),将所有元素表示为一个个矩形的盒子(box)
一个盒子由四个部分组成:content
、padding
、border
、margin
下面来段代码:
<style>
.box {width: 200px;height: 100px;padding: 20px;
}
</style><div class="box">
盒子模型
</div>
当我们在i浏览器查看元素时,却发现元素的大小变成了240px
这是因为,在CSS
中,盒子模型可以分成:
- W3C 标准盒子模型
- IE 怪异盒子模型
默认情况下,盒子模型为W3C
标准盒子模型
2、标准盒子模型
标准盒子模型,是浏览器默认的盒子模型
下面看看标准盒子模型的模型图:
从上图可以看到:
- 盒子总宽度 = width + padding + border + margin;
- 盒子总高度 = height + padding + border + margin
也就是,width/height
只是内容高度,不包含 padding
和 border
值
所以上面问题中,设置width
为200px,但由于存在padding
,但实际上盒子的宽度有240px
3、IE 怪异盒子模型
同样看看IE 怪异盒子模型的模型图:
从上图可以看到:
- 盒子总宽度 = width + margin;
- 盒子总高度 = height + margin;
也就是,width/height
包含了 padding
和 border
值
CSS 中的 box-sizing 属性定义了引擎应该如何计算一个元素的总宽度和总高度
语法:
box-sizing: content-box|border-box|inherit;
<style>
.box {width: 200px;height: 100px;padding: 20px;box-sizing: border-box;
}
</style>
<div class="box">
盒子模型
</div>
- content-box 默认值,元素的 width/height 不包含padding,border,与标准盒子模型表现一致
- border-box 元素的 width/height 包含 padding,border,与怪异盒子模型表现一致
- inherit 指定 box-sizing 属性的值,应该从父元素继承
回到上面的例子里,设置盒子为 border-box 模型
这时候,就可以发现盒子的所占据的宽度为200px
三、css选择器有哪些?优先级分别是什么?哪些属性可以继承?
1、选择器
关于css
属性选择器常用的有:
- id选择器(#box),选择id为box的元素
- 类选择器(.one),选择类名为one的所有元素
- 标签选择器(div),选择标签为div的所有元素
- 后代选择器(#box div),选择id为box元素内部所有的div元素
- 子选择器(.one>one_1),选择父元素为.one的所有.one_1的元素
- 相邻同胞选择器(.one+.two),选择紧接在.one之后的所有.two元素
- 群组选择器(div,p),选择div、p的所有元素
还有一些使用频率相对没那么多的选择器:
- 伪类选择器
- :link :选择未被访问的链接
- :visited:选取已被访问的链接
- :active:选择活动链接
- :hover :鼠标指针浮动在上面的元素
- :focus :选择具有焦点的
- :first-child:父元素的首个子元素
- 伪元素选择器
- :first-letter :用于选取指定选择器的首字母
- :first-line :选取指定选择器的首行
- :before : 选择器在被选元素的内容前面插入内容
- :after : 选择器在被选元素的内容后面插入内容
在CSS3
中新增的选择器有如下:
- 层次选择器(p~ul),选择前面有p元素的每个ul元素
- 伪类选择器
- :first-of-type 父元素的首个元素
- :last-of-type 父元素的最后一个元素
- :only-of-type 父元素的特定类型的唯一子元素
- :only-child 父元素中唯一子元素
- :nth-child(n) 选择父元素中第N个子元素
- :nth-last-of-type(n) 选择父元素中第N个子元素,从后往前
- :last-child 父元素的最后一个元素
- :root 设置HTML文档
- :empty 指定空的元素
- :enabled 选择被禁用元素
- :disabled 选择被禁用元素
- :checked 选择选中的元素
- :not(selector) 选择非 <selector> 元素的所有元素
- 属性选择器
- [attribute*=value]:选择attribute属性值包含value的所有元素
- [attribute^=value]:选择attribute属性开头为value的所有元素
- [attribute$=value]:选择attribute属性结尾为value的所有元素
2、优先级
内联 > ID选择器 > 类选择器 > 标签选择器
如果外部样式需要覆盖内联样式,就需要使用!important
3、继承
在css
中,继承是指的是给父元素设置一些属性,后代元素会自动拥有这些属性 关于继承属性,可以分成:
- 字体系列属性
- font:组合字体
- font-family:规定元素的字体系列
- font-weight:设置字体的粗细
- font-size:设置字体的尺寸
- font-style:定义字体的风格
- font-variant:偏大或偏小的字体
- 文本系列属性
- text-indent:文本缩进
- text-align:文本水平对齐
- line-height:行高
- word-spacing:增加或减少单词间的空白
- letter-spacing:增加或减少字符间的空白
- text-transform:控制文本大小写
- direction:规定文本的书写方向
- color:文本颜色
- 元素可见性
visibility
- 表格布局属性
- caption-side:定位表格标题位置
- border-collapse:合并表格边框
- border-spacing:设置相邻单元格的边框间的距离
- empty-cells:单元格的边框的出现与消失
- table-layout:表格的宽度由什么决定
- 列表属性
- list-style-type:文字前面的小点点样式
- list-style-position:小点点位置
- list-style:以上的属性可通过这属性集合
- 引用
- quotes:设置嵌套引用的引号类型
- 光标属性
cursor:箭头可以变成需要的形状
继承中比较特殊的几点:
- a 标签的字体颜色不能被继承
- h1-h6标签字体的大下也是不能被继承的
4、无继承的属性
- display
- 文本属性:vertical-align、text-decoration
- 盒子模型的属性:宽度、高度、内外边距、边框等
- 背景属性:背景图片、颜色、位置等
- 定位属性:浮动、清除浮动、定位position等
- 生成内容属性:content、counter-reset、counter-increment
- 轮廓样式属性:outline-style、outline-width、outline-color、outline
- 页面样式属性:size、page-break-before、page-break-after
四、em/px/rem/vh/vw 这些单位有什么区别?
1、介绍
传统的项目开发中,我们只会用到px
、%
、em
这几个单位,它可以适用于大部分的项目开发,且拥有比较良好的兼容性
从CSS3
开始,浏览器对计量单位的支持又提升到了另外一个境界,新增了rem
、vh
、vw
、vm
等一些新的计量单位
利用这些新的单位开发出比较良好的响应式页面,适应多种不同分辨率的终端,包括移动设备等
2、单位
在css
单位中,可以分为长度单位、绝对单位,如下表所指示
CSS单位 | |
---|---|
相对长度单位 | em、ex、ch、rem、vw、vh、vmin、vmax、% |
绝对长度单位 | cm、mm、in、px、pt、pc |
这里我们主要讲述px、em、rem、vh、vw
px
px,表示像素,所谓像素就是呈现在我们显示器上的一个个小点,每个像素点都是大小等同的,所以像素为计量单位被分在了绝对长度单位中
有些人会把px
认为是相对长度,原因在于在移动端中存在设备像素比,px
实际显示的大小是不确定
这里之所以认为px
为绝对单位,在于px
的大小和元素的其他属性无关
em
em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸(1em = 16px
)
为了简化 font-size
的换算,我们需要在css
中的 body
选择器中声明font-size
= 62.5%
,这就使 em 值变为 16px*62.5% = 10px
这样 12px = 1.2em
, 10px = 1em
, 也就是说只需要将你的原来的 px
数值除以 10,然后换上 em
作为单位就行了
特点:
- em 的值并不是固定的
- em 会继承父级元素的字体大小
- em 是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸
- 任意浏览器的默认字体高都是 16px
rem
rem,相对单位,相对的只是HTML根元素font-size
的值
同理,如果想要简化font-size
的转化,我们可以在根元素html
中加入font-size: 62.5%
1html {font-size: 62.5%; } /* 公式16px*62.5%=10px */
这样页面中1rem=10px、1.2rem=12px、1.4rem=14px、1.6rem=16px;使得视觉、使用、书写都得到了极大的帮助
特点:
- rem单位可谓集相对大小和绝对大小的优点于一身
- 和em不同的是rem总是相对于根元素,而不像em一样使用级联的方式来计算尺寸
vh、vw
vw ,就是根据窗口的宽度,分成100等份,100vw就表示满宽,50vw就表示一半宽。(vw 始终是针对窗口的宽),同理,vh
则为窗口的高度
这里的窗口分成几种情况:
- 在桌面端,指的是浏览器的可视区域
- 移动端指的就是布局视口
像vw
、vh
,比较容易混淆的一个单位是%
,不过百分比宽泛的讲是相对于父元素:
对于普通定位元素就是我们理解的父元素
- 对于position: absolute;的元素是相对于已定位的父元素
- 对于position: fixed;的元素是相对于 ViewPort(可视窗口)
3、总结
px:绝对单位,页面按精确像素展示
em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size
按自身来计算,整个页面内1em
不是一个固定的值
rem:相对单位,可理解为root em
, 相对根节点html
的字体大小来计算
vh、vw:主要用于页面视口大小布局,在页面布局上更加方便简单
五、设备像素、css像素、设备独立像素、dpr、ppi 之间有什么区别?
1、背景
在css
中我们通常使用px作为单位,在PC浏览器中css
的1个像素都是对应着电脑屏幕的1个物理像素
这会造成一种错觉,我们会认为css
中的像素就是设备的物理像素
但实际情况却并非如此,css
中的像素只是一个抽象的单位,在不同的设备或不同的环境中,css
中的1px所代表的设备物理像素是不同的
当我们做移动端开发时,同为1px的设置,在不同分辨率的移动设备上显示效果却有很大差异
这背后就涉及了css像素、设备像素、设备独立像素、dpr、ppi的概念
2、介绍
CSS像素
CSS像素(css pixel, px): 适用于web编程,在 CSS 中以 px 为后缀,是一个长度单位
在 CSS 规范中,长度单位可以分为两类,绝对单位以及相对单位
px是一个相对单位,相对的是设备像素(device pixel)
一般情况,页面缩放比为1,1个CSS像素等于1个设备独立像素
CSS
像素又具有两个方面的相对性:
- 在同一个设备上,每1个 CSS 像素所代表的设备像素是可以变化的(比如调整屏幕的分辨率)
- 在不同的设备之间,每1个 CSS 像素所代表的设备像素是可以变化的(比如两个不同型号的手机)
在页面进行缩放操作也会 引起css
中px
的变化,假设页面放大一倍,原来的 1px 的东西变成 2px,在实际宽度不变的情况下1px 变得跟原来的 2px 的长度(长宽)一样了(元素会占据更多的设备像素)
假设原来需要 320px 才能填满的宽度现在只需要 160px
px会受到下面的因素的影响而变化:
- 每英寸像素(PPI)
- 设备像素比(DPR)
设备像素(device pixels),又称为物理像素
指设备能控制显示的最小物理单位,不一定是一个小正方形区块,也没有标准的宽高,只是用于显示丰富色彩的一个“点”而已
可以参考公园里的景观变色彩灯,一个彩灯(物理像素)由红、蓝、绿小灯组成,三盏小灯不同的亮度混合出各种色彩
预览
从屏幕在工厂生产出的那天起,它上面设备像素点就固定不变了,单位为pt
设备独立像素
设备独立像素(Device Independent Pixel):与设备无关的逻辑像素,代表可以通过程序控制使用的虚拟像素,是一个总体概念,包括了CSS像素
在javaScript
中可以通过window.screen.width/ window.screen.height
查看
比如我们会说“电脑屏幕在 2560x1600分辨率下不适合玩游戏,我们把它调为 1440x900”,这里的“分辨率”(非严谨说法)指的就是设备独立像素
一个设备独立像素里可能包含1个或者多个物理像素点,包含的越多则屏幕看起来越清晰
至于为什么出现设备独立像素这种虚拟像素单位概念,下面举个例子:
iPhone 3GS 和 iPhone 4/4s 的尺寸都是 3.5 寸,但 iPhone 3GS 的分辨率是 320x480,iPhone 4/4s 的分辨率是 640x960
这意味着,iPhone 3GS 有 320 个物理像素,iPhone 4/4s 有 640 个物理像素
如果我们按照真实的物理像素进行布局,比如说我们按照 320 物理像素进行布局,到了 640 物理像素的手机上就会有一半的空白,为了避免这种问题,就产生了虚拟像素单位
我们统一 iPhone 3GS 和 iPhone 4/4s 都是 320 个虚拟像素,只是在 iPhone 3GS 上,最终 1 个虚拟像素换算成 1 个物理像素,在 iphone 4s 中,1 个虚拟像素最终换算成 2 个物理像素
至于 1 个虚拟像素被换算成几个物理像素,这个数值我们称之为设备像素比,也就是下面介绍的dpr
dpr
dpr(device pixel ratio),设备像素比,代表设备独立像素到设备像素的转换关系,在JavaScript
中可以通过 window.devicePixelRatio
获取
计算公式如下:
预览
当设备像素比为1:1时,使用1(1×1)个设备像素显示1个CSS像素
当设备像素比为2:1时,使用4(2×2)个设备像素显示1个CSS像素
当设备像素比为3:1时,使用9(3×3)个设备像素显示1个CSS像素
如下图所示:
预览
当dpr
为3,那么1px
的CSS
像素宽度对应3px
的物理像素的宽度,1px的CSS
像素高度对应3px
的物理像素高度
ppi
ppi (pixel per inch),每英寸像素,表示每英寸所包含的像素点数目,更确切的说法应该是像素密度。数值越高,说明屏幕能以更高密度显示图像
计算公式如下:
3、总结
无缩放情况下,1个CSS像素等于1个设备独立像素
设备像素由屏幕生产之后就不发生改变,而设备独立像素是一个虚拟单位会发生改变
PC端中,1个设备独立像素 = 1个设备像素 (在100%,未缩放的情况下)
在移动端中,标准屏幕(160ppi)下 1个设备独立像素 = 1个设备像素
设备像素比(dpr) = 设备像素 / 设备独立像素
每英寸像素(ppi),值越大,图像越清晰
六、CSS中,有哪些方式可以隐藏页面元素?有什么区别?
1、实现方式
- display:none
- visibility:hidden
- opacity:0
- 设置height、width模型属性为0
- position:absolute
- clip-path
display:none
设置元素的display
为none
是最常用的隐藏元素的方法
将元素设置为display:none
后,元素在页面上将彻底消失
元素本身占有的空间就会被其他元素占有,也就是说它会导致浏览器的重排和重绘
消失后,自身绑定的事件不会触发,也不会有过渡效果
特点:元素不可见,不占据空间,无法响应点击事件
visibility:hidden
设置元素的visibility
为hidden
也是一种常用的隐藏元素的方法
从页面上仅仅是隐藏该元素,DOM结果均会存在,只是当时在一个不可见的状态,不会触发重排,但是会触发重绘
1.hidden{ 2 visibility:hidden 3}
给人的效果是隐藏了,所以他自身的事件不会触发
特点:元素不可见,占据页面空间,无法响应点击事件
opacity:0
opacity
属性表示元素的透明度,将元素的透明度设置为0后,在我们用户眼中,元素也是隐藏的
不会引发重排,一般情况下也会引发重绘
如果利用 animation 动画,对 opacity 做变化(animation会默认触发GPU加速),则只会触发 GPU 层面的 composite,不会触发重绘
由于其仍然是存在于页面上的,所以他自身的的事件仍然是可以触发的,但被他遮挡的元素是不能触发其事件的
需要注意的是:其子元素不能设置opacity来达到显示的效果
特点:改变元素透明度,元素不可见,占据页面空间,可以响应点击事件
设置height、width属性为0
将元素的margin
,border
,padding
,height
和width
等影响元素盒模型的属性设置成0,如果元素内有子元素或内容,还应该设置其overflow:hidden
来隐藏其子元素
特点:元素不可见,不占据页面空间,无法响应点击事件
position:absolute
将元素移出可视区域
特点:元素不可见,不影响页面布局
clip-path
特点:元素不可见,占据页面空间,无法响应点击事件
2、小结
最常用的还是display:none
和visibility:hidden
,其他的方式只能认为是奇招,它们的真正用途并不是用于隐藏元素,所以并不推荐使用它们
3、区别
关于display: none
、 visibility: hidden
、opacity: 0
的区别,如下表所示:
display: none | visibility: hidden | opacity: 0 | |
---|---|---|---|
页面中 | 不存在 | 存在 | 存在 |
重排 | 会 | 不会 | 不会 |
重绘 | 会 | 会 | 不一定 |
自身绑定事件 | 不触发 | 不触发 | 可触发 |
transition | 不支持 | 支持 | 支持 |
子元素可复原 | 不能 | 能 | 不能 |
被遮挡的元素可触发事件 | 能 | 能 | 不能 |
七、怎么使用 CSS3 实现动画?
1、实现方式
transition 实现渐变动画
transition
的属性如下:
- property:填写需要变化的css属性
- duration:完成过渡效果需要的时间单位(s或者ms)
- timing-function:完成效果的速度曲线
- delay: 动画效果的延迟触发时间
其中timing-function
的值有如下:
值 | 描述 |
---|---|
linear | 匀速(等于 cubic-bezier(0,0,1,1)) |
ease | 从慢到快再到慢(cubic-bezier(0.25,0.1,0.25,1)) |
ease-in | 慢慢变快(等于 cubic-bezier(0.42,0,1,1)) |
ease-out | 慢慢变慢(等于 cubic-bezier(0,0,0.58,1)) |
ease-in-out | 先变快再到慢(等于 cubic-bezier(0.42,0,0.58,1)),渐显渐隐效果 |
cubic-bezier(n,n,n,n) | 在 cubic-bezier 函数中定义自己的值。可能的值是 0 至 1 之间的数值 |
注意:并不是所有的属性都能使用过渡的,如display:none<->display:block
举个例子,实现鼠标移动上去发生变化动画效果
<style>.base {width: 100px;height: 100px;display: inline-block;background-color: #0EA9FF;border-width: 5px;border-style: solid;border-color: #5daf34;transition-property: width, height, background-color, border-width;transition-duration: 2s;transition-timing-function: ease-in;transition-delay: 500ms;}/*简写*//*transition: all 2s ease-in 500ms;*/.base:hover {width: 200px;height: 200px;background-color: #5daf34;border-width: 10px;border-color: #3a8ee6;}
</style>
<div class="base"></div>
transform 转变动画
包含四个常用的功能:
- translate:位移
- scale:缩放
- rotate:旋转
- skew:倾斜
一般配合transition
过度使用
注意的是,transform
不支持inline
元素,使用前把它变成block
举个例子
<style>.base {width: 100px;height: 100px;display: inline-block;background-color: #0EA9FF;border-width: 5px;border-style: solid;border-color: #5daf34;transition-property: width, height, background-color, border-width;transition-duration: 2s;transition-timing-function: ease-in;transition-delay: 500ms;}.base2 {transform: none;transition-property: transform;transition-delay: 5ms;}.base2:hover {transform: scale(0.8, 1.5) rotate(35deg) skew(5deg) translate(15px, 25px);}
</style><div class="base base2"></div>
可以看到盒子发生了旋转,倾斜,平移,放大
animation 实现自定义动画
animation
是由 8 个属性的简写,分别如下:
属性 | 描述 | 属性值 |
---|---|---|
animation-duration | 指定动画完成一个周期所需要时间,单位秒(s)或毫秒(ms),默认是 0 | |
animation-timing-function | 指定动画计时函数,即动画的速度曲线,默认是 "ease" | linear、ease、ease-in、ease-out、ease-in-out |
animation-delay | 指定动画延迟时间,即动画何时开始,默认是 0 | |
animation-iteration-count | 指定动画播放的次数,默认是 1 | |
animation-direction 指定动画播放的方向 | 默认是 normal | normal、reverse、alternate、alternate-reverse |
animation-fill-mode | 指定动画填充模式。默认是 none | forwards、backwards、both |
animation-play-state | 指定动画播放状态,正在运行或暂停。默认是 running | running、pauser |
animation-name | 指定 @keyframes 动画的名称 |
CSS
动画只需要定义一些关键的帧,而其余的帧,浏览器会根据计时函数插值计算出来,
通过 @keyframes
来定义关键帧
因此,如果我们想要让元素旋转一圈,只需要定义开始和结束两帧即可:
@keyframes rotate{from{transform: rotate(0deg);}to{transform: rotate(360deg);}
}
from
表示最开始的那一帧,to
表示结束时的那一帧
也可以使用百分比刻画生命周期
@keyframes rotate{0%{transform: rotate(0deg);}50%{transform: rotate(180deg);}100%{transform: rotate(360deg);}
}
定义好了关键帧后,下来就可以直接用它了:
animation: rotate 2s;
2、总结
属性 | 含义 |
---|---|
transition(过度) | 用于设置元素的样式过度,和animation有着类似的效果,但细节上有很大的不同 |
transform(变形) | 用于元素进行旋转、缩放、移动或倾斜,和设置样式的动画并没有什么关系,就相当于color一样用来设置元素的“外表” |
translate(移动) | 只是transform的一个属性值,即移动 |
animation(动画) | 用于设置动画属性,他是一个简写的属性,包含6个属性 |
八、怎么理解回流跟重绘?什么场景下会触发?
1、是什么
在HTML
中,每个元素都可以理解成一个盒子,在浏览器解析过程中,会涉及到回流与重绘:
回流:布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制
具体的浏览器解析渲染机制如下所示:
解析HTML,生成DOM树,解析CSS,生成CSSOM树
将DOM树和CSSOM树结合,生成渲染树(Render Tree)
Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
Display:将像素发送给GPU,展示在页面上
在页面初始渲染阶段,回流不可避免的触发,可以理解成页面一开始是空白的元素,后面添加了新的元素使页面布局发生改变
当我们对 DOM
的修改引发了 DOM
几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性,然后再将计算的结果绘制出来
当我们对 DOM
的修改导致了样式的变化(color
或background-color
),却并未影响其几何属性时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式,这里就仅仅触发了回流
2、如何触发
要想减少回流和重绘的次数,首先要了解回流和重绘是如何触发的
回流触发时机
回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流,如下面情况:
- 添加或删除可见的DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
- 页面一开始渲染的时候(这避免不了)
- 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
还有一些容易被忽略的操作:获取一些特定属性的值
offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight
这些属性有一个共性,就是需要通过即时计算得到。因此浏览器为了获取这些值,也会进行回流
除此还包括getComputedStyle
方法,原理是一样的
重绘触发时机
触发回流一定会触发重绘
可以把页面理解为一个黑板,黑板上有一朵画好的小花。现在我们要把这朵从左边移到了右边,那我们要先确定好右边的具体位置,画好形状(回流),再画上它原有的颜色(重绘)
除此之外还有一些其他引起重绘行为:
颜色的修改
文本方向的修改
阴影的修改
浏览器优化机制
由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列
当你获取布局信息的操作的时候,会强制队列刷新,包括前面讲到的offsetTop
等方法都会返回最新的数据
因此浏览器不得不清空队列,触发回流重绘来返回正确的值
3、如何减少
我们了解了如何触发回流和重绘的场景,下面给出避免回流的经验:
- 如果想设定元素的样式,通过改变元素的
class
类名 (尽可能在 DOM 树的最里层) - 避免设置多项内联样式
- 应用元素的动画,使用
position
属性的fixed
值或absolute
值(如前文示例所提) - 避免使用
table
布局,table
中每个元素的大小以及内容的改动,都会导致整个table
的重新计算 - 对于那些复杂的动画,对其设置
position: fixed/absolute
,尽可能地使元素脱离文档流,从而减少对其他元素的影响 - 使用css3硬件加速,可以让
transform
、opacity
、filters
这些动画不会引起回流重绘 - 避免使用 CSS 的
JavaScript
表达式
在使用 JavaScript
动态插入多个节点时, 可以使用DocumentFragment
. 创建后一次插入. 就能避免多次的渲染性能
但有时候,我们会无可避免地进行回流或者重绘,我们可以更好使用它们
例如,多次修改一个把元素布局的时候,我们很可能会如下操作
const el = document.getElementById('el')
for(let i=0;i<10;i++) {el.style.top = el.offsetTop + 10 + "px";el.style.left = el.offsetLeft + 10 + "px";
}
每次循环都需要获取多次offset
属性,比较糟糕,可以使用变量的形式缓存起来,待计算完毕再提交给浏览器发出重计算请求
// 缓存offsetLeft与offsetTop的值
const el = document.getElementById('el')
let offLeft = el.offsetLeft, offTop = el.offsetTop// 在JS层面进行计算
for(let i=0;i<10;i++) {offLeft += 10offTop += 10
}// 一次性将计算结果应用到DOM上
el.style.left = offLeft + "px"
el.style.top = offTop + "px"
我们还可避免改变样式,使用类名去合并样式
const container = document.getElementById('container')
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'
使用类名去合并样式
<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>
前者每次单独操作,都去触发一次渲染树更改(新浏览器不会),都去触发一次渲染树更改,从而导致相应的回流与重绘过程合并之后,等于我们将所有的更改一次性发出
我们还可以通过设置元素属性display: none
,将其从页面上去掉,然后再进行后续操作,这些后续操作也不会触发回流与重绘,这个过程称为离线操作
const container = document.getElementById('container')
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'
离线操作后
let container = document.getElementById('container')
container.style.display = 'none'
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'
...(省略了许多类似的后续操作)
container.style.display = 'block'
九、如何使用CSS提高页面性能?
实现方式
实现方式有很多种,主要有如下:
- 内联首屏关键CSS
- 异步加载CSS
- 资源压缩
- 合理使用选择器
- 减少使用昂贵的属性
- 不要使用@import
内联首屏关键CSS
在打开一个页面,页面首要内容出现在屏幕的时间影响着用户的体验,而通过内联css
关键代码能够使浏览器在下载完html
后就能立刻渲染
而如果外部引用css
代码,在解析html
结构过程中遇到外部css
文件,才会开始下载css
代码,再渲染
所以,CSS
内联使用使渲染时间提前
注意:但是较大的css
代码并不合适内联(初始拥塞窗口、没有缓存),而其余代码则采取外部引用方式
异步加载CSS
在CSS
文件请求、下载、解析完成之前,CSS
会阻塞渲染,浏览器将不会渲染任何已处理的内容
前面加载内联代码后,后面的外部引用css
则没必要阻塞浏览器渲染。这时候就可以采取异步加载的方案,主要有如下:
- 使用javascript将link标签插到head标签最后
// 创建link标签
const myCSS = document.createElement( "link" );
myCSS.rel = "stylesheet";
myCSS.href = "mystyles.css";
// 插入到header的最后位置
document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );
- 设置link标签media属性为noexis,浏览器会认为当前样式表不适用当前类型,会在不阻塞页面渲染的情况下再进行下载。加载完成后,将
media
的值设为screen
或all
,从而让浏览器开始解析CSS
<link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media='all'">
- 通过rel属性将link元素标记为alternate可选样式表,也能实现浏览器异步加载。同样别忘了加载完成之后,将rel设回stylesheet
<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">
资源压缩
利用webpack
、gulp/grunt
、rollup
等模块化工具,将css
代码进行压缩,使文件变小,大大降低了浏览器的加载时间
合理使用选择器
css
匹配的规则是从右往左开始匹配,例如#markdown .content h3
匹配规则如下:
- 先找到h3标签元素
- 然后去除祖先不是.content的元素
- 最后去除祖先不是#markdown的元素
如果嵌套的层级更多,页面中的元素更多,那么匹配所要花费的时间代价自然更高
所以我们在编写选择器的时候,可以遵循以下规则:
- 不要嵌套使用过多复杂选择器,最好不要三层以上
- 使用id选择器就没必要再进行嵌套
- 通配符和属性选择器效率最低,避免使用
减少使用昂贵的属性
在页面发生重绘的时候,昂贵属性如box-shadow
/border-radius
/filter
/透明度/:nth-child
等,会降低浏览器的渲染性能
不要使用@import
css样式文件有两种引入方式,一种是link
元素,另一种是@import
@import
会影响浏览器的并行下载,使得页面在加载时增加额外的延迟,增添了额外的往返耗时
而且多个@import
可能会导致下载顺序紊乱
比如一个css文件index.css
包含了以下内容:@import url("reset.css")
那么浏览器就必须先把index.css
下载、解析和执行后,才下载、解析和执行第二个文件reset.css
其他
- 减少重排操作,以及减少不必要的重绘
- 了解哪些属性可以继承而来,避免对这些属性重复编写
- cssSprite,合成所有icon图片,用宽高加上backgroud-position的背景图方式显现出我们要的icon图,减少了http请求
- 把小的icon图片转成base64编码
- CSS3动画或者过渡尽量使用transform和opacity来实现动画,不要使用left和top属性
3、总结
css
实现性能的方式可以从选择器嵌套、属性特性、减少http
这三面考虑,同时还要注意css
代码的加载顺序
十、CSS3新增了哪些特性?
1、选择器
2、新样式
边框
css3
新增了三个边框属性,分别是:
border-radius:创建圆角边框
box-shadow:为元素添加阴影
border-image:使用图片来绘制边框
box-shadow
设置元素阴影,设置属性如下:
- 水平阴影
- 垂直阴影
- 模糊距离(虚实)
- 阴影尺寸(影子大小)
- 阴影颜色
- 内/外阴影
其中水平阴影和垂直阴影是必须设置的
背景
新增了几个关于背景的属性,分别是background-clip
、background-origin
、background-size
和background-break
background-clip
用于确定背景画区,有以下几种可能的属性:
- background-clip: border-box; 背景从border开始显示
- background-clip: padding-box; 背景从padding开始显示
- background-clip: content-box; 背景显content区域开始显示
- background-clip: no-clip; 默认属性,等同于border-box
通常情况,背景都是覆盖整个元素的,利用这个属性可以设定背景颜色或图片的覆盖范围
background-origin
当我们设置背景图片时,图片是会以左上角对齐,但是是以border
的左上角对齐还是以padding
的左上角或者content
的左上角对齐? border-origin
正是用来设置这个的
- background-origin: border-box; 从border开始计算background-position
- background-origin: padding-box; 从padding开始计算background-position
- background-origin: content-box; 从content开始计算background-position
默认情况是padding-box
,即以padding
的左上角为原点
background-size
background-size属性常用来调整背景图片的大小,主要用于设定图片本身。有以下可能的属性:
- background-size: contain; 缩小图片以适合元素(维持像素长宽比)
- background-size: cover; 扩展元素以填补元素(维持像素长宽比)
- background-size: 100px 100px; 缩小图片至指定的大小
- background-size: 50% 100%; 缩小图片至指定的大小,百分比是相对包 含元素的尺寸
background-break
元素可以被分成几个独立的盒子(如使内联元素span跨越多行),background-break
属性用来控制背景怎样在这些不同的盒子中显示
- background-break: continuous; 默认值。忽略盒之间的距离(也就是像元素没有分成多个盒子,依然是一个整体一样)
- background-break: bounding-box; 把盒之间的距离计算在内;
- background-break: each-box; 为每个盒子单独重绘背景
文字
word-wrap
语法:word-wrap: normal|break-word
- normal:使用浏览器默认的换行
- break-all:允许在单词内换行
text-overflow
text-overflow
设置或检索当当前行超过指定容器的边界时如何显示,属性有两个值选择:
- clip:修剪文本
- ellipsis:显示省略符号来代表被修剪的文本
text-shadow
text-shadow
可向文本应用阴影。能够规定水平阴影、垂直阴影、模糊距离,以及阴影的颜色
text-decoration
CSS3里面开始支持对文字的更深层次的渲染,具体有三个属性可供设置:
text-fill-color: 设置文字内部填充颜色
text-stroke-color: 设置文字边界填充颜色
text-stroke-width: 设置文字边界宽度
颜色
css3
新增了新的颜色表示方式rgba
与hsla
- rgba分为两部分,rgb为颜色值,a为透明度
- hala分为四部分,h为色相,s为饱和度,l为亮度,a为透明度
3、transition 过渡
transition
属性可以被指定为一个或多个CSS
属性的过渡效果,多个属性之间用逗号进行分隔,必须规定两项内容:
- 过度效果
- 持续时间
语法如下:
transition: CSS属性,花费时间,效果曲线(默认ease),延迟时间(默认0)
上面为简写模式,也可以分开写各个属性
transition-property: width;
transition-duration: 1s;
transition-timing-function: linear;
transition-delay: 2s;
4、transform 转换
transform
属性允许你旋转,缩放,倾斜或平移给定元素
transform-origin
:转换元素的位置(围绕那个点进行转换),默认值为(x,y,z):(50%,50%,0)
使用方式:
- transform: translate(120px, 50%):位移
- transform: scale(2, 0.5):缩放
- transform: rotate(0.5turn):旋转
- transform: skew(30deg, 20deg):倾斜
5、animation 动画
动画这个平常用的也很多,主要是做一个预设的动画。和一些页面交互的动画效果,结果和过渡应该一样,让页面不会那么生硬
animation也有很多的属性
- animation-name:动画名称
- animation-duration:动画持续时间
- animation-timing-function:动画时间函数
- animation-delay:动画延迟时间
- animation-iteration-count:动画执行次数,可以设置为一个整数,也可以设置为infinite,意思是无限循环
- animation-direction:动画执行方向
- animation-paly-state:动画播放状态
- animation-fill-mode:动画填充模式
6、渐变
颜色渐变是指在两个颜色之间平稳的过渡,css3
渐变包括
- linear-gradient:线性渐变
background-image: linear-gradient(direction, color-stop1, color-stop2, ...);
- radial-gradient:径向渐变
linear-gradient(0deg, red, green);
7、其他
关于css3
其他的新特性还包括flex
弹性布局、Grid
栅格布局
本文所有内容均参考首页 - 前端面试题宝典《前端面试题宝典》的目标是做全网最专业的的前端面试题库,为初、中级前端工程师提供面试题的刷题及面试技巧指导服务https://fe.ecool.fun/
每天10个前端小知识(1day)相关推荐
- 每天10个前端小知识 【Day 13】
- 每天10个前端小知识(6day)
一.JavaScript中的分号问题 还是来看下面的例子 function nums(a, b) {if(a > b)console.log('a is bigger')else console ...
- 每天10个前端小知识 【Day 16】
- 每天10个前端小知识 【Day 11】
- html前端小知识:制作简单的纯文字图标按钮
今天分享下"html前端小知识:制作简单的纯文字图标按钮"这篇文章,文中根据实例编码详细介绍,或许对大家的编程之路有着一定的参考空间与使用价值,需要的朋友接下来跟着云南仟龙Mark ...
- 原生js绑定click为什么点一次执行两次_前端小知识10点(2020.10.8)
1.redux的compose实现 例: const add = num => num + 10 const multiply = num => num * 2 const foo = c ...
- 前端基础知识点-每天一个基本知识点(100+个前端小知识,你是否都知道?)
文章目录 前言 第一回合 一.知识点:cookie(21/09/06) 二.知识点:节流和防抖(21/09/07) 三.知识点:var和let以及const(21/09/08) 四:知识点:深拷贝和浅 ...
- 30+ 个工作中常用到的前端小知识
1. JS为什么单线程 一个简单的原因就是,js在设计之初只是进行一些简单的表单校验,这完全不需要多线程,单线程完全可以胜任这项工作.即便后来前端发展迅速,承载的能力越来越多,也没有发展到非多线程不可 ...
- 你不一定知道的几个前端小知识
1 大家都知道js在进行小数运算时会有丢失精度问题(其他语言也是),比如: 0.1+0.2 //0.30000000000000004 有一种比较快捷的方式是先把小数乘以10的整数倍,然后再运算,如: ...
最新文章
- Google 出品的 Java 编码规范,值得借鉴!
- lua元表和元方法 《lua程序设计》 13章 读书笔记
- 自旋表达的到底是什么?
- Linux下C++的多线程编程---(转载)
- char java 回文_LeetCode刷题笔记(Java)---第1-18题
- LoadRunner如何调用外部函数
- 开源贡献 计算_现在贡献开源的3个理由
- 《精通并发与Netty》学习笔记(02 - 服务端程序编写)
- 【python】Python基础语法及规范
- Android图片控件,跟随列表(recyclerView)的上下滚动而同步平移。
- 《NLTK基础教程——用NLTK和Python库构建机器学习应用》——2.10 练习
- 三部曲打造无路由器破解闪讯WiFi共享 经好几个同学验证
- 云运维管家服务器,云平台随身管理-我的“运维管家”
- 21. 合并两个有序链表
- Centos7.5软硬件、IP地址及主机名称配置详细教程
- 破晓博客-自定义标签的开发
- 解决浏览器被好123劫持主页的问题。
- Vue Router 路由中 this.$router 与this.$route区别
- synopsys tcl语言
- unix程序员手册_推荐几本实惠电子书,程序员读的经典书都有,比如deep learning...
热门文章
- matplotlib.widgets简单上手
- 单片机学习笔记9--常见的通信方式(基于百问网STM32F103系列教程)
- 论文翻译-Three Stream 3D CNN with SE Block for Micro- Expression Recognition
- 一台笔记本只有一个显卡,如何同时连接两台显示器
- BIN,S19,M0T,SREC,HEX文件解析;FileParse(二)之源码解析
- 在vant组件下阻止手机自带键盘弹起
- rand()和srand()函数的用法
- 软件测试技术之iOS 单元测试—逻辑测试
- 计算机专业调研报告图片,计算机专业毕业设计论文(计算机专业调研报告范文)...
- Graylog 中文手册 常用功能和问题整理