1. 程式人生 > 前端設計 >瀏覽器渲染原理與 CSS 動畫

瀏覽器渲染原理與 CSS 動畫

1. 瀏覽器渲染

1.1 瀏覽器渲染的步驟

瀏覽器渲染流程大致分為以下幾個步驟:

  1. 根據 HTML 構建 HTML 樹(DOM);
  2. 根據 CSS 構建 CSS 樹(CSSOM);
  3. 將兩棵樹合併成一棵渲染樹(render tree);
  4. Layout 佈局(文件流、盒模型、計算大小和位置);
  5. Paint 繪製(把邊框顏色,文字顏色陰影等畫出來);
  6. Composite 合成(根據層疊關係展示畫面)。

HTML樹CSS樹合併

1.2 更新 CSS 樣式的方法和步驟

一般用 JavaScript 更新樣式,可以修改樣式或者新增類,新增類更為方便常用。使用 JavaScript 更新樣式要經過佈局、繪製、合成這幾個步驟中的一步、二步或者全部。

  • 經過佈局、繪製、合成全部過程,如刪除某 div 元素;
  • 經過繪製、合成過程,如改變某元素背景顏色,因為位置、大小未改變,不影響佈局;
  • 經過合成過程,如改變 transform 屬性,在 Chrome 瀏覽器只需要合成。

JS更新樣式三種方式

1.3 各屬性觸發相應流程的查詢方式

通過 csstriggers.com 查詢各屬性改變時在各瀏覽器觸發了哪些的流程。

各主要瀏覽器核心標識如下:

  • Blink:Chrome 瀏覽器
  • Geckko:Firefox 瀏覽器
  • Webkit:Safari 瀏覽器
  • EdgeHTML:IE 最新版

1.4 瀏覽器渲染與 CSS 動畫優化的關係

開啟 Chrome 開發者工具,按 ESC,點選 Rendering,勾選 Paint flashing,此時頁面會出現綠色部分閃爍,綠色閃爍代表重新渲染,就相當於在螢幕上這塊區域重新畫一下。

通過 JavaScript 定時器設定每秒移動固定位移實現的動畫,對應元素一直在重新渲染。而通過設定 transform 實現的動畫,在 Chrome 瀏覽器測試,元素只在起始位置渲染,優化了 CSS 效能。

CSS 動畫優化經常採用以下方式

  • JS 優化:使用 requestAnimationFrame 代替 setTimeout 或 setInterval;
  • CSS 優化:使用 will-change 或 transform。

2. CSS 動畫

每個靜止的畫面都是幀,連續的幀形成了動畫。影視通常每秒 24 幀,遊戲每秒 30 幀以上,有追求畫面的遊戲達到 120 ~ 140 幀甚至更高。

2.1 transform 變形

四個常用功能:

  • 位移 translate
  • 縮放 scale
  • 旋轉 rotate
  • 傾斜 skew

transform 一般需要配合 transition 使用。inline-block 元素不支援 transform,需要先變成 block。

針對 translateZ 的移動,需要設定 perspective(透視原點位置)才能觀察到效果。如 perspective: 1000px,即透視原點位於距元素正中心 1000px 遠處。

/* 通過 transform 實現絕對定位元素居中,不支援 IE */
 .demo {
     width: 200px;
     height: 200px;
     border: 1px solid red;
     position: absolute;
     left: 50%;
     top: 50%;
     /* 回半個身位 */
     /* transform: translateX(-50%) translateY(-50%);*/
     transform: translate(-50%,-50%);
 }
複製程式碼

2.2 transition 過渡

  • 作用:補充中間幀
  • 語法: transition: 屬性名 時長 過渡方式 延遲時間

可拆分設定 transition-property: width,background,transition-duration: 2s,10s。
可自定義貝塞爾曲線 cubic-bezier(0,0.95,1,0.07)
延遲時間 transition-delay: 3s;
所有屬性同樣過渡 transition: all 2s;

  • 過渡方式:linear(線性) | ease(緩動)| ease in(緩入,從慢到快)| ease out(緩出,從快到慢)| ease-in-out(緩入緩出)| ...
  • display:none --> block 沒辦法過渡,一般改為 visibility:hidden --> visible
  • visibility: hidden 仍然佔用域的空間
  • 過渡必須要有起始

2.3 animation 動畫

宣告關鍵幀,新增動畫。@keyframes 兩種寫法。

.demo.strat {
    animation: moveExample 1s;
}

/* 寫法一 */
@keyframes moveExample {
    from {
        transform: translateX(0%);
    }
    to {
        transform: translateX(100%);
    }
}

/* 寫法二 */
@keyframes moveExample {
    0% {
        transform: translateX(0%);
    }
    30% {
        transform: rotate(45deg);
    }
    60%,70% {
        transform: scale(1.2);
    }
    100% {
        transform: translateX(100%);
    }
}
複製程式碼

animation 簡寫

  • animation: 時長 | 過渡方式 | 延遲 | 次數 | 方向 | 填充方式 | 是否暫停 | 動畫名
  • animation-name: moveExample —— 動畫名稱
  • animation-duration: 3s —— 動畫時間週期
  • animation-timing-function: ease —— 動畫速度曲線
  • animation-delay: 1s —— 動畫延遲時間
  • animation-iteration-count: 3(3次) | infinite(無限次)—— 動畫迴圈次數
  • animation-direction: normal —— 運動的方向。

alternate交替運動(奇數次正常運動,偶數次反向),reverse 反向運動,alternate-reverse 奇數次反向偶數次正向運動。

  • animation-fill-mode: fowards; —— 使得動畫保留最後一幀的效果

3. 小案例

  • 使用 transform、transition 和 :hover 實現會動的紅心
  * {
    padding: 0;
    margin: 0;
  }
  .wrap {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
  }
  #heart {
    position: relative;
    transition: all 1s;
  }
  #heart:hover {
    transform: scale(1.2);
    transition: all 1s;
  }
  .left {
    position: absolute;
    bottom: 100%;
    right: 100%;
    width: 200px;
    height: 200px;
    background: red;
    border-radius: 50% 0 0 50%;
    transform: rotate(45deg) translateX(170px);
  }
  .right {
    position: absolute;
    bottom: 100%;
    left: 100%;
    width: 200px;
    height: 200px;
    background: red;
    border-radius: 50% 50% 0 0;
    transform: rotate(45deg) translateY(170px);
  }
  .bottom {
    width: 200px;
    height: 200px;
    background: red;
    transform: rotate(45deg);
  }
複製程式碼
<body>
  <div class="wrap">
    <div id="heart">
      <div class="left"></div>
      <div class="right"></div>
      <div class="bottom"></div>
    </div>
  </div>
</body>
複製程式碼
  • 使用 animation 實現會動的紅心。
#heart {
  position: relative;
  animation: heart 0.7s ease infinite alternate;
}
@keyframes heart {
  0% {
    transform: scale(1);
  }
  100% {
    transform: scale(1.2);
  }
}
複製程式碼

跳動紅心