理解块级元素和行内元素
- 块级元素会独占一行,其宽度自动填满其父元素宽度;行内元素不会独占一行,相邻的行内元素会排列在同一行,直到一行排不下才会换行,其宽度随元素的内容而变化
- 块级元素可以设置width,height属性,行内元素设置width,height无效
- 块级元素可以设置margin/padding,行内元素只能设置水平方向的margin/padding,竖直方向无效
- 块级元素可以容纳行内元素和其他块元素,行内元素只能容纳文本或其他行内元素
- 常见的块级元素有div,p,h1-h6,table,ul,ol,li,form,hr,行内元素有:a,span,sub,sup,u,em,s,i
理解重排和重绘
核心:重排一定会导致重绘,重绘不一定会导致重排,需要频繁移动变换大小的div尽量脱离文档流,减少重排,提升性能,如果要改变p的样式,class不要加在p的父级上,避免通过父元素去影响子元素,尽量避免使用table布局,可能很小的一个改动也会造成整个table的重新布局
减少重排次数:
- 样式集中改变:不要频繁的操作样式,对于一个静态页面来说,明智且可维护的做法是更改类名而不是修改样式,对于动态改变的样式来说,相较每次微小修改都直接触及元素,更好的办法是给一个cssText的样式对象,统一在cssText变量中编辑
//bad
var left = 10
var top = 10
el.style.left = left + 'px'
el.style.top = top + 'px'
//better
el.style.cssText += ';left: ' + left + 'px;top: ' + top + 'px'
- 分离读写操作,DOM的多个读写操作应该放在一起,不要两个读的操作之间,加入一个写的操作
// bad 强制刷新 触发四次重排+重绘
div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';
div.style.right = div.offsetRight + 1 + 'px';
div.style.bottom = div.offsetBottom + 1 + 'px';
// good 缓存布局信息 相当于读写分离 触发一次重排+重绘
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
var curRight = div.offsetRight;
var curBottom = div.offsetBottom;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';
div.style.right = curRight + 1 + 'px';
div.style.bottom = curBottom + 1 + 'px';
原来的操作会导致四次重排,读写分离之后实际上只触发了一次重排,这都得益于浏览器的**渲染队列机制**:当我们修改了元素的几何属性,导致浏览器触发重排或重绘时。它会把该操作放进渲染队列,等到队列中的操作到了一定的数量或者到了一定的时间间隔时,浏览器就会批量执行这些操作。
- 使用absolute或fixed脱离文档流
- 优化动画
重排:当DOM的变化影响了元素的几何信息(元素的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫重排,也叫回流,简单来说就是重新生成布局,重新排列元素
下面情况会发生重排:
- 页面初始渲染,这是开销最大的一次重排
- 添加/删除可见的DOM元素
- 改变元素位置、尺寸(边距/填充/边框/宽度/高度)、内容(文字数量/图片大小)、元素字体大小
- 改变浏览器窗口尺寸,比如resize事件发生时
重排影响的范围:
- 全局范围:从根节点HTML开始对整个渲染树进行重新布局
<body>
<div class="hello">
<h4>hello</h4>
<p><strong>Name</strong></p>
<h5>male</h5>
<ol>
<li>coding</li>
<li>loving</li>
</ol>
</div>
</body>
当p节点上发生reflow时,hello和body也会重新渲染,甚至h5和ol都会受到影响
- 局部范围:对渲染树的某部分或某一个渲染对象进行重新布局(把一个DOM的宽高之类的几何信息定死,然后在DOM内部触发重排,就只会重新渲染该DOM内部的元素,而不会影响到外界)
重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘