浏览器渲染原理:

步骤:

  1. 根据HTML构建HTML树(DOM)
  2. 根据CSS构建CSS树(CSSOM)
  3. 将两棵树合并成一颗渲染树(render tree)
  4. Layout布局(文档流、盒模型、计算大小和位置)
  5. Paint绘制(把边框颜色、文字颜色、阴影等画出来)
  6. Compose合成(根据层叠关系展示画面)

具体可参考图:
render-tree-construction.png
如果 DOM 或 CSSOM 被修改,只能再执行一遍以上所有步骤,以确定哪些像素需要在屏幕上进行重新渲染。优化关键渲染路径就是指最大限度缩短执行上述第 1 步至第6 步耗费的总时间。当我们更新网页样式或者设置一些动画效果后,网页内容就会发生更新,而三种渲染方式分别是:

  • JS / CSS > 样式 > 布局 > 绘制 > 合成

frame-full.jpg
如果修改元素的“layout”属性,也就是改变了元素的几何属性(例如宽度、高度、左侧或顶部位置等),那么浏览器将必须检查所有其他元素,然后“自动重排”页面。任何受影响的部分都需要重新绘制,而且最终绘制的元素需进行合成。

  • JS / CSS > 样式 > 绘制 > 合成

frame-no-layout.jpg
如果修改“paint only”属性(例如背景图片、文字颜色或阴影等),即不会影响页面布局的属性,则浏览器会跳过布局,但仍将执行绘制。

  • JS / CSS > 样式 > 合成

frame-no-layout-paint.jpg
如果更改一个既不要布局也不要绘制的属性,则浏览器将跳到只执行合成。
至于更改哪些属性会影响布局、绘制、合成,可以参考CSS trigggers


CSS动画的两种做法

transition:

transition作用是补充中间帧,可以为一个元素在不同状态之间切换的时候定义不同的过渡效果。比如在不同的伪元素之间切换,像是 :hover,:active 或者通过 JavaScript 实现的状态变化。
比如如下代码:

  1. img{
  2. height:100px;
  3. width:100px;
  4. }
  5. img:hover{
  6. height: 200px;
  7. width: 200px;
  8. }

当鼠标放置于缩略图之上,缩略图会迅速变大,几乎是瞬间实现的。但是,通过添加transition属性,可以为变化指定所需时间以及过度的方式等。

语法:

  • transition: 属性名 时长 过渡方式 延迟,属性名(transition-property),时长(transition-duration),过渡方式(transition-timing-function) 和 延迟(transition-delay)
  • transition-property: none | all | IDENT ,相当于指定适用的属性,具体参考MDN: transition-property
  • transition-duration:
  • transition-timing-function: ,状态的变化速度,默认不是匀速的,而是逐渐放慢,这叫做ease。其他模式还包括linear:匀速,ease-in:加速,ease-out:减速,cubic-bezier函数:自定义速度模式,具体参考MDN: transition-timing-function
  • transition-delay:

可以为上面的img标签增加transition属性:

  1. img{
  2. transition: 1s 1s all ease;
  3. }

这是简写模式,还可以单独定义各个属性:

  1. img{
  2. transition-property: all;
  3. transition-duration: 1s;
  4. transition-delay: 1s;
  5. transition-timing-function: ease;
  6. }

代码实现的效果就是鼠标放置于缩略图之上,缩略图在延迟1s后以逐渐放慢的速度变大为原来的两倍。

transition的局限:

  • transition需要事件触发,所以没法在网页加载时自动发生
  • transition是一次性的,不能重复发生,除非一再触发
  • transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态
  • 一条transition规则,只能定义一个属性的变化,不能涉及多个属性
  • display: none => block没法过渡

    animation:

    animation用来指定一组或者多组动画,每组之间用逗号分隔。比如:

    1. div:hover {
    2. animation: 1s xxx;
    3. }

    代码表示,当鼠标悬停在div元素上时,会产生名为xxx的动画效果,持续时间为1秒。为此,我们还需要用keyframes关键字,定义xxx效果。
    @keyframes 规则通过在动画序列中定义关键帧(或waypoints)的样式来控制CSS动画序列中的中间步骤。关键帧的常用写法如下:

    1. /*第一种写法*/
    2. @keyframes xxx {
    3. from { background: red; }
    4. to { background: yellow; }
    5. }

    或者:

    1. /*第二种写法*/
    2. @keyframes xxx {
    3. 0% { background: red; }
    4. 100% { background: yellow; }
    5. }

    from等效于 0%,to等效于 100%,第二种写法可以用百分数表示触发关键帧的时间点,可以描述更多状态,推荐这种写法。上面代码表示xxx效果一共有两个状态,分别为起始(0%)和结束(100%)。

    语法:

    animation 属性是 animation-name,animation-duration, animation-timing-function,animation-delay,animation-iteration-count,animation-direction,animation-fill-mode 和 animation-play-state 属性的一个简写属性形式。具体参考MDN: animation

  • animation-name: none | IDENT,指定应用的一系列动画,每个名称代表一个由@keyframes定义的动画序列。

  • animation-duration:
  • animation-timing-function:, 默认值为ease。
  • animation-delay:
  • animation-iteration-count: infinite | , 定义动画在结束前运行的次数 可以是1次,也可以是无限循环。
  • animation-direction,动画循环播放时,每次都是从结束状态跳回到起始状态,再开始播放。animation-direction属性,可以改变这种行为。默认情况是,animation-direction等于normal。还可以等于取alternate(动画在奇数次正向播放,在偶数次反向播放)、reverse(动画反向播放)、alternate-reverse(动画在奇数次反向播放,在偶数次正向播放)等值。
  • animation-fill-mode,动画结束以后,会立即从结束状态跳回到起始状态。如果想让动画保持在结束状态,需要使用该属性。取值为none:默认值,回到动画没开始时的状态,forwards表示让动画停留在结束状态,backwards:让动画回到第一帧的状态,both: 根据animation-direction轮流应用forwards和backwards规则。
  • animation-play-state: pauesd | running,定义一个动画是否运行或者暂停。比如:
    1. div {
    2. animation: xxx 1s linear infinite;
    3. animation-play-state: paused;
    4. }
    5. div:hover {
    6. animation-play-state: running;
    7. }
    上面的代码表示,没有鼠标没有悬停时,动画状态是暂停;一旦悬停,动画状态改为继续播放。
    animation属性可以简写,并且各属性次序不重要,具体实现示例可参考跳动的心