精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深入淺出談 CSS 動畫

開發 前端
本文將比較全面細致的梳理一下 CSS 動畫的方方面面,針對每個屬性用法的講解及進階用法的示意,希望能成為一個比較好的從入門到進階的教程。

本文將比較全面細致的梳理一下 CSS 動畫的方方面面,針對每個屬性用法的講解及進階用法的示意,希望能成為一個比較好的從入門到進階的教程。

CSS 動畫介紹及語法

首先,我們來簡單介紹一下 CSS 動畫。

最新版本的 CSS 動畫由規范 -- CSS Animations Level 1[1] 定義。

CSS 動畫用于實現元素從一個 CSS 樣式配置轉換到另一個 CSS 樣式配置。

動畫包括兩個部分: 描述動畫的樣式規則和用于指定動畫開始、結束以及中間點樣式的關鍵幀。

簡單來說,看下面的例子:

  1. div { 
  2.     animation: change 3s; 
  3.  
  4. @keyframes change { 
  5.     0% { 
  6.         color: #f00; 
  7.     } 
  8.     100% { 
  9.         color: #000; 
  10.     } 
  1. animation: move 1s 部分就是動畫的第一部分,用于描述動畫的各個規則;
  2. @keyframes move {} 部分就是動畫的第二部分,用于指定動畫開始、結束以及中間點樣式的關鍵幀;

一個 CSS 動畫一定要由上述兩部分組成。

CSS 動畫的語法

接下來,我們簡單看看 CSS 動畫的語法。

創建動畫序列,需要使用 animation 屬性或其子屬性,該屬性允許配置動畫時間、時長以及其他動畫細節,但該屬性不能配置動畫的實際表現,動畫的實際表現是由 @keyframes 規則實現。

animation 的子屬性有:

  • animation-name:指定由 @keyframes 描述的關鍵幀名稱。
  • animation-duration:設置動畫一個周期的時長。
  • animation-delay:設置延時,即從元素加載完成之后到動畫序列開始執行的這段時間。
  • animation-direction:設置動畫在每次運行完后是反向運行還是重新回到開始位置重復運行。
  • animation-iteration-count:設置動畫重復次數, 可以指定 infinite 無限次重復動畫
  • animation-play-state:允許暫停和恢復動畫。
  • animation-timing-function:設置動畫速度, 即通過建立加速度曲線,設置動畫在關鍵幀之間是如何變化。
  • animation-fill-mode:指定動畫執行前后如何為目標元素應用樣式
  • @keyframes 規則,當然,一個動畫想要運行,還應該包括 @keyframes 規則,在內部設定動畫關鍵幀

其中,對于一個動畫:

  • 必須項:animation-name、animation-duration 和 @keyframes規則
  • 非必須項:animation-delay、animation-direction、animation-iteration-count、animation-play-state、animation-timing-function、animation-fill-mode,當然不是說它們不重要,只是不設置時,它們都有默認值

上面已經給了一個簡單的 DEMO, 就用上述的 DEMO,看看結果:

這就是一個最基本的 CSS 動畫,本文將從 animation 的各個子屬性入手,探究 CSS 動畫的方方面面。

animation-name / animation-duration 詳解

整體而言,單個的 animation-name 和 animation-duration 沒有太多的技巧,非常好理解,放在一起。

首先介紹一下 animation-name,通過 animation-name,CSS 引擎將會找到對應的 @keyframes 規則。

當然,它和 CSS 規則命名一樣,也存在一些騷操作。譬如,他是支持 emoji 表情的,所以代碼中的 animation-name 命名也可以這樣寫:

  1. div { 
  2.     animation: 😄 3s; 
  3.  
  4. @keyframes 😄 { 
  5.     0% { 
  6.         color: #f00; 
  7.     } 
  8.     100% { 
  9.         color: #000; 
  10.     } 

而 animation-duration 設置動畫一個周期的時長,上述 DEMO 中,就是設定動畫整體持續 3s,這個也非常好理解。

animation-delay 詳解

animation-delay 就比較有意思了,它可以設置動畫延時,即從元素加載完成之后到動畫序列開始執行的這段時間。

簡單的一個 DEMO:

  1. <div></div> 
  2. <div></div> 
  1. div { 
  2.     width: 100px; 
  3.     height: 100px; 
  4.     background: #000; 
  5.     animation-namemove
  6.     animation-duration: 2s; 
  7.  
  8. div:nth-child(2) { 
  9.     animation-delay: 1s; 
  10. @keyframes move { 
  11.     0% { 
  12.         transform: translate(0); 
  13.     } 
  14.     100% { 
  15.         transform: translate(200px); 
  16.     } 

比較下列兩個動畫,一個添加了 animation-delay,一個沒有,非常直觀:

上述第二個 div,關于 animation 屬性,也可以簡寫為 animation: move 2s 1s,第一個時間值表示持續時間,第二個時間值表示延遲時間。

animation-delay 可以為負值

關于 animation-delay,最有意思的技巧在于,它可以是負數。也就是說,雖然屬性名是動畫延遲時間,但是運用了負數之后,動畫可以提前進行。

假設我們要實現這樣一個 loading 動畫效果:

圖片

有幾種思路:

  1. 初始 3 個球的位置就是間隔 120°,同時開始旋轉,但是這樣代碼量會稍微多一點
  2. 另外一種思路,同一個動畫,3 個元素的其中兩個延遲整個動畫的 1/3,2/3 時間出發

方案 2 的核心偽代碼如下:

  1. .item:nth-child(1) { 
  2.     animation: rotate 3s infinite linear; 
  3. .item:nth-child(2) { 
  4.     animation: rotate 3s infinite 1s linear; 
  5. .item:nth-child(3) { 
  6.     animation: rotate 3s infinite 2s linear; 

但是,在動畫的前 2s,另外兩個元素是不會動的,只有 2s 過后,整個動畫才是我們想要的:

此時,我們可以讓第 2、3 個元素的延遲時間,改為負值,這樣可以讓動畫延遲進行 -1s、-2s,也就是提前進行 1s、2s:

  1. .item:nth-child(1) { 
  2.     animation: rotate 3s infinite linear; 
  3. .item:nth-child(2) { 
  4.     animation: rotate 3s infinite -1s linear; 
  5. .item:nth-child(3) { 
  6.     animation: rotate 3s infinite -2s linear; 

這樣,每個元素都無需等待,直接就是運動狀態中的,并且元素間隔位置是我們想要的結果:

利用 animation-duration 和 animation-delay 構建隨機效果

還有一個有意思的小技巧。

同一個動畫,我們利用一定范圍內隨機的 animation-duration 和一定范圍內隨機的 animation-delay,可以有效的構建更為隨機的動畫效果,讓動畫更加的自然。

我在下述兩個純 CSS 動畫中,都使用了這樣的技巧:

純 CSS 實現華為充電動畫[2]:

純 CSS 實現華為充電動畫

純 CSS 實現火焰動畫[3]:

純 CSS 實現火焰動畫

以純 CSS 實現華為充電動畫為例子,簡單講解一下。

仔細觀察這一部分,上升的一個一個圓球,拋去這里的一些融合效果,只關注不斷上升的圓球,看著像是沒有什么規律可言:

圖片

 我們來模擬一下,如果是使用 10 個 animation-duration 和 animation-delay 都一致的圓的話,核心偽代碼:

  1. <ul> 
  2.     <li></li> 
  3.     <!--共 10 個...-->  
  4.     <li></li> 
  5. </ul> 

  1. ul { 
  2.     display: flex; 
  3.     flex-wrap: nowrap; 
  4.     gap: 5px; 
  5. li { 
  6.     background: #000; 
  7.     animation: move 3s infinite 1s linear; 
  8. @keyframes move { 
  9.     0% { 
  10.         transform: translate(0, 0); 
  11.     } 
  12.     100% { 
  13.         transform: translate(0, -100px); 
  14.     } 

 這樣,小球的運動會是這樣的整齊劃一:

要讓小球的運動顯得非常的隨機,只需要讓 animation-duration 和 animation-delay 都在一定范圍內浮動即可,改造下 CSS:

  1. @for $i from 1 to 11 { 
  2.     li:nth-child(#{$i}) { 
  3.         animation-duration: #{random(2000)/1000 + 2}s; 
  4.         animation-delay: #{random(1000)/1000 + 1}s; 
  5.     } 

我們利用 SASS 的循環和 random() 函數,讓 animation-duration 在 2-4 秒范圍內隨機,讓 animation-delay 在 1-2 秒范圍內隨機,這樣,我們就可以得到非常自然且不同的上升動畫效果,基本不會出現重復的畫面,很好的模擬了隨機效果:

CodePen Demo -- 利用范圍隨機 animation-duration 和 animation-delay 實現隨機動畫效果[4]

animation-timing-function 緩動函數

緩動函數在動畫中非常重要,它定義了動畫在每一動畫周期中執行的節奏。

緩動主要分為兩類:

  1. cubic-bezier-timing-function 三次貝塞爾曲線緩動函數
  2. step-timing-function 步驟緩動函數(這個翻譯是我自己翻的,可能有點奇怪)

三次貝塞爾曲線緩動函數

首先先看看三次貝塞爾曲線緩動函數。在 CSS 中,支持一些緩動函數關鍵字。

  1. /* Keyword values */ 
  2. animation-timing-function: ease;  // 動畫以低速開始,然后加快,在結束前變慢 
  3. animation-timing-function: ease-in;  // 動畫以低速開始 
  4. animation-timing-function: ease-out; // 動畫以低速結束 
  5. animation-timing-function: ease-in-out; // 動畫以低速開始和結束 
  6. animation-timing-function: linear; // 勻速,動畫從頭到尾的速度是相同的 

關于它們之間的效果對比:

除了 CSS 支持的這 5 個關鍵字,我們還可以使用 cubic-bezier() 方法自定義三次貝塞爾曲線:

  1. animation-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1); 

這里有個非常好用的網站 -- cubic-bezier[5] 用于創建和調試生成不同的貝塞爾曲線參數。

三次貝塞爾曲線緩動對動畫的影響

關于緩動函數對動畫的影響,這里有一個非常好的示例。這里我們使用了純 CSS 實現了一個鐘的效果,對于其中的動畫的運動,如果是 animation-timing-function: linear,效果如下:

而如果我們我把緩動函數替換一下,變成 animation-timing-function: cubic-bezier(1,-0.21,.85,1.29),它的曲線對應如下:

整個鐘的動畫律動效果將變成這樣,完全不一樣的感覺:

CodePen Demo - 緩動不同效果不同[6]

對于許多精益求精的動畫,在設計中其實都考慮到了緩動函數。我很久之前看到過一篇《基于物理學的動畫用戶體驗設計》,可惜如今已經無法找到原文。其中傳達出的一些概念是,動畫的設計依據實際在生活中的表現去考量。

譬如 linear 這個緩動,實際應用于某些動畫中會顯得很不自然,因為由于空氣阻力的存在,程序模擬的勻速直線運動在現實生活中是很難實現的。因此對于這樣一個用戶平時很少感知到的運動是很難建立信任感的。這樣的勻速直線運動也是我們在進行動效設計時需要極力避免的。

步驟緩動函數

接下來再講講步驟緩動函數。在 CSS 的 animation-timing-function 中,它有如下幾種表現形態:

  1.     /* Keyword values */ 
  2.     animation-timing-function: step-start; 
  3.     animation-timing-function: step-end
  4.  
  5.     /* Function values */ 
  6.     animation-timing-function: steps(6, start) 
  7.     animation-timing-function: steps(4, end); 

在 CSS 中,使用步驟緩動函數最多的,就是利用其來實現逐幀動畫。假設我們有這樣一張圖(圖片大小為 1536 x 256,圖片來源于網絡):

可以發現它其實是一個人物行進過程中的 6 種狀態,或者可以為 6 幀,我們利用 animation-timing-function: steps(6) 可以將其用一個 CSS 動畫串聯起來,代碼非常的簡單:

  1. <div class="box"></div> 
  1. .box { 
  2.   width: 256px; 
  3.   height: 256px; 
  4.   background: url('https://github.com/iamalperen/playground/blob/main/SpriteSheetAnimation/sprite.png?raw=true'); 
  5.   animation: sprite .6s steps(6, end) infinite; 
  6. @keyframes sprite { 
  7.   0% {  
  8.     background-position: 0 0; 
  9.   } 
  10.   100% {  
  11.     background-position: -1536px 0; 
  12.   } 

簡單解釋一下上述代碼,首先要知道,剛好 256 x 6 = 1536,所以上述圖片其實可以剛好均分為 6 段:

  1. 我們設定了一個大小都為 256px 的 div,給這個 div 賦予了一個 animation: sprite .6s steps(6) infinite 動畫;
  2. 其中 steps(6) 的意思就是將設定的 @keyframes 動畫分為 6 次(6幀)執行,而整體的動畫時間是 0.6s,所以每一幀的停頓時長為 0.1s;
  3. 動畫效果是由 background-position: 0 0 到 background-position: -1536px 0,由于上述的 CSS 代碼沒有設置 background-repeat,所以其實 background-position: 0 0 是等價于 background-position: -1536px 0,就是圖片在整個動畫過程中推進了一輪,只不過每一幀停在了特點的地方,一共 6 幀。

將上述 1、2、3,3 個步驟畫在圖上簡單示意:

從上圖可知,其實在動畫過程中,background-position 的取值其實只有 background-position: 0 0,background-position: -256px 0,background-position: -512px 0 依次類推一直到 background-position: -1536px 0,由于背景的 repeat 的特性,其實剛好回到原點,由此又重新開始新一輪同樣的動畫。

所以,整個動畫就會是這樣,每一幀停留 0.1s 后切換到下一幀(注意這里是個無限循環動畫),:

完整的代碼你可以戳這里 -- CodePen Demo -- Sprite Animation with steps() [7]

animation-duration 動畫長短對動畫的影響

在這里再插入一個小章節,animation-duration 動畫長短對動畫的影響也是非常明顯的。

在上述代碼的基礎上,我們再修改 animation-duration,縮短每一幀的時間就可以讓步行的效果變成跑步的效果,同理,也可以增加每一幀的停留時間。讓每一步變得緩慢,就像是在步行一樣。

需要提出的是,上文說的每一幀,和瀏覽器渲染過程中的 FPS 的每一幀不是同一個概念。

看看效果,設置不同的 animation-duration 的效果(這里是 0.6s -> 0.2s),GIF 錄屏丟失了一些關鍵幀,實際效果會更好點:

當然,在 steps() 中,還有 steps(6, start) 和 steps(6, end) 的差異,也就是其中關鍵字 start 和 end 的差異。對于上述的無限動畫而言,其實基本是可以忽略不計的,它主要是控制動畫第一幀的開始和持續時長,比較小的一個知識點但是想講明白需要比較長的篇幅,限于本文的內容,在這里不做展開,讀者可以自行了解。

同個動畫效果的補間動畫和逐幀動畫演繹對比

上述的三次貝塞爾曲線緩動和步驟緩動,其實就是對應的補間動畫和逐幀動畫。

對于同個動畫而言,有的時候兩種緩動都是適用的。我們在具體使用的時候需要具體分析選取。

假設我們用 CSS 實現了這樣一個圖形:

現在想利用這個圖形制作一個 Loading 效果,如果利用補間動畫,也就是三次貝塞爾曲線緩動的話,讓它旋轉起來,得到的效果非常的一般:

  1. .g-container{ 
  2.     animation: rotate 2s linear infinite; 
  3. @keyframes rotate { 
  4.     0% { 
  5.         transform: rotate(0); 
  6.     } 
  7.     100% { 
  8.         transform: rotate(360deg); 
  9.     } 

動畫效果如下:

但是如果這里,我們將補間動畫換成逐幀動畫,因為有 20 個點,所以設置成 steps(20),再看看效果,會得到完全不一樣的感覺:

  1. .g-container{ 
  2.     animation: rotate 2s steps(20) infinite; 
  3. @keyframes rotate { 
  4.     0% { 
  5.         transform: rotate(0); 
  6.     } 
  7.     100% { 
  8.         transform: rotate(360deg); 
  9.     } 

動畫效果如下:

整個 loading 的圈圈看上去好像也在旋轉,實際上只是 20 幀關鍵幀在切換,整體的效果感覺更適合 Loading 的效果。

因此,兩種動畫效果都是很有必要掌握的,在實際使用的時候靈活嘗試,選擇更適合的。

上述 DEMO 效果完整的代碼:CodePen Demo -- Scale Loading steps vs linear[8]

animation-play-state

接下來,我們講講 animation-play-state,顧名思義,它可以控制動畫的狀態 -- 運行或者暫停。類似于視頻播放器的開始和暫停。是 CSS 動畫中有限的控制動畫狀態的手段之一。

它的取值只有兩個(默認為 running):

  1.     animation-play-state: paused | running; 

使用起來也非常簡單,看下面這個例子,我們在 hover 按鈕的時候,實現動畫的暫停:

  1. <div class="btn stop">stop</div> 
  2. <div class="animation"></div> 
  1. .animation { 
  2.     width: 100px; 
  3.     height: 100px; 
  4.     background: deeppink; 
  5.     animation: move 2s linear infinite alternate; 
  6.  
  7. @keyframes move { 
  8.     100% { 
  9.         transform: translate(100px, 0); 
  10.     } 
  11.  
  12. .stop:hover ~ .animation { 
  13.     animation-play-state: paused; 

一個簡單的 CSS 動畫,但是當我們 hover 按鈕的時候,給動畫元素添加上 animation-play-state: paused:

animation-play-state 小技巧,默認暫停,點擊運行

正常而言,按照正常思路使用 animation-play-state: paused 是非常簡單的。

但是,如果我們想創造一些有意思的 CSS 動畫效果,不如反其道而行之。

我們都知道,正常情況下,動畫應該是運行狀態,那如果我們將一些動畫的默認狀態設置為暫停,只有當鼠標點擊或者 hover 的時候,才設置其 animation-play-state: running,這樣就可以得到很多有趣的 CSS 效果。

看個倒酒的例子,這是一個純 CSS 動畫,但是默認狀態下,動畫處于 animation-play-state: paused,也就是暫停狀態,只有當鼠標點擊杯子的時,才設置 animation-play-state: running,讓酒倒下,

完整的 DEMO 你可以戳這里:CodePen Demo -- CSS Beer![9]

在非常多 Web 創意交互動畫我們都可以看到這個技巧的身影。

  1. 頁面 render 后,無任何操作,動畫不會開始。只有當鼠標對元素進行 click ,通過觸發元素的 :active 偽類效果的時候,賦予動畫 animation-play-state: running,動畫才開始進行;
  2. 動畫進行到任意時刻,鼠標停止點擊,偽類消失,則動畫停止;

animation-fill-mode 控制元素在各個階段的狀態

下一個屬性 animation-fill-mode,很多人會誤認為它只是用于控制元素在動畫結束后是否復位。這個其實是不準確的,不全面的。

看看它的取值:

  1.     // 默認值,當動畫未執行時,動畫將不會將任何樣式應用于目標,而是使用賦予給該元素的 CSS 規則來顯示該元素的狀態 
  2.     animation-fill-mode: none; 
  3.     // 動畫將在應用于目標時立即應用第一個關鍵幀中定義的值,并在 `animation-delay` 期間保留此值, 
  4.     animation-fill-mode: backwards;  
  5.     // 目標將保留由執行期間遇到的最后一個關鍵幀計算值。 最后一個關鍵幀取決于 `animation-direction` 和 `animation-iteration-count
  6.     animation-fill-mode: forwards;     
  7.     // 動畫將遵循 `forwards` 和 `backwards` 的規則,從而在兩個方向上擴展動畫屬性 
  8.     animation-fill-mode: both;  

對于 animation-fill-mode 的解讀,我在 Segment Fault 上的一個問答中(SF - 如何理解 animation-fill-mode[10])看到了 4 副很好的解讀圖,這里借用一下:

假設 HTML 如下:

  1. <div class="box"></div> 

CSS如下:

  1. .box{ 
  2.     transform: translateY(0); 
  3. .box.on
  4.     animation: move 1s; 
  5.  
  6. @keyframes move
  7.     from{transform: translateY(-50px)} 
  8.     to  {transform: translateY( 50px)} 

使用圖片來表示 translateY 的值與 時間 的關系:

  • 橫軸為表示 時間,為 0 時表示動畫開始的時間,也就是向 box 加上 on 類名的時間,橫軸一格表示 0.5s
  • 縱軸表示 translateY 的值,為 0 時表示 translateY 的值為 0,縱軸一格表示 50px

animation-fill-mode: none 表現如圖:

一句話總結,元素在動畫時間之外,樣式只受到它的 CSS 規則限制,與 @keyframes 內的關鍵幀定義無關。

animation-fill-mode: backwards 表現如圖:

一句話總結,元素在動畫開始之前(包含未觸發動畫階段及 animation-delay 期間)的樣式為動畫運行時的第一幀,而動畫結束后的樣式則恢復為 CSS 規則設定的樣式。

animation-fill-mode: forwards 表現如圖:

一句話總結,元素在動畫開始之前的樣式為 CSS 規則設定的樣式,而動畫結束后的樣式則表現為由執行期間遇到的最后一個關鍵幀計算值(也就是停在最后一幀)。

animation-fill-mode: both 表現如圖: 

一句話總結,綜合了 animation-fill-mode: backwards 和 animation-fill-mode: forwards 的設定。動畫開始前的樣式為動畫運行時的第一幀,動畫結束后停在最后一幀。

animation-iteration-count/animation-direction 動畫循環次數和方向

講到了 animation-fill-mode,我們就可以順帶講講這個兩個比較好理解的屬性 -- animation-iteration-count 和 animation-direction

  • animation-iteration-count 控制動畫運行的次數,可以是數字或者 infinite,注意,數字可以是小數
  • animation-direction 控制動畫的方向,正向、反向、正向交替與反向交替

在上面講述 animation-fill-mode 時,我使用了動畫運行時的第一幀替代了@keyframes 中定義的第一幀這種說法,因為動畫運行的第一幀和最后一幀的實際狀態還會受到動畫運行方向 animation-direction 和 animation-iteration-count 的影響。

在 CSS 動畫中,由 animation-iteration-count 和 animation-direction 共同決定動畫運行時的第一幀和最后一幀的狀態。

  1. 動畫運行的第一幀由 animation-direction 決定
  2. 動畫運行的最后一幀由 animation-iteration-count 和 animation-direction 決定

動畫的最后一幀,也就是動畫運行的最終狀態,并且我們可以利用 animation-fill-mode: forwards 讓動畫在結束后停留在這一幀,這個還是比較好理解的,但是 animation-fill-mode: backwards 和 animation-direction 的關系很容易弄不清楚,這里簡答講解下。

設置一個 100px x 100px 的滑塊,在一個 400px x 100px 的容器中,其代碼如下:

  1. <div class="g-father"
  2.     <div class="g-box"></div> 
  3. </div> 
  1. .g-father { 
  2.     width: 400px; 
  3.     height: 100px; 
  4.     border: 1px solid #000; 
  5. .g-box { 
  6.     width: 100px; 
  7.     height: 100px; 
  8.     background: #333; 

表現如下:

那么,加入 animation 之后,在不同的 animation-iteration-count 和 animation-direction 作用下,動畫的初始和結束狀態都不一樣。

如果設置了 animation-fill-mode: backwards,則元素在動畫未開始前的狀態由 animation-direction 決定:

  1. .g-box { 
  2.     ... 
  3.     animation: move 4s linear; 
  4.     animation-play-state: paused; 
  5.     transform: translate(0, 0); 
  6. @keyframes move { 
  7.     0% { 
  8.         transform: translate(100px, 0); 
  9.     } 
  10.     100% { 
  11.         transform: translate(300px, 0); 
  12.     } 

注意這里 CSS 規則中,元素沒有設置位移 transform: translate(0, 0),而在動畫中,第一個關鍵幀和最后一個關鍵的 translateX 分別是 100px、300px,配合不同的 animation-direction 初始狀態如下。

下圖假設我們設置了動畫默認是暫停的 -- animation-play-state: paused,那么動畫在開始前的狀態為:

動畫的分治與復用

講完了每一個屬性,我們再來看看一些動畫使用過程中的細節。

看這樣一個動畫:

  1. <div></div> 
  1. div { 
  2.     width: 100px; 
  3.     height: 100px; 
  4.     background: #000; 
  5.     animation: combine 2s; 
  6. @keyframes combine { 
  7.     100% { 
  8.         transform: translate(0, 150px); 
  9.         opacity: 0; 
  10.     } 

這里我們實現了一個 div 塊下落動畫,下落的同時產生透明度的變化:

對于這樣一個多個屬性變化的動畫,它其實等價于:

  1. div { 
  2.     animation: falldown 2s, fadeIn 2s; 
  3.  
  4. @keyframes falldown { 
  5.     100% { 
  6.         transform: translate(0, 150px); 
  7.     } 
  8. @keyframes fadeIn { 
  9.     100% { 
  10.         opacity: 0; 
  11.     } 

在 CSS 動畫規則中,animation 是可以接收多個動畫的,這樣做的目的不僅僅只是為了復用,同時也是為了分治,我們對每一個屬性層面的動畫能夠有著更為精確的控制。

keyframes 規則的設定

我們經常能夠在各種不同的 CSS 代碼見到如下兩種 CSS @keyframes 的設定:

使用百分比

  1. @keyframes fadeIn { 
  2.     0% { 
  3.         opacity: 1; 
  4.     } 
  5.     100% { 
  6.         opacity: 0; 
  7.     } 

使用 from 及 to

  1. @keyframes fadeIn { 
  2.     from { 
  3.         opacity: 1; 
  4.     } 
  5.     to { 
  6.         opacity: 0; 
  7.     } 

在 CSS 動畫 @keyframes 的定義中,from 等同于 0%,而 to 等同于 100%。

當然,當我們的關鍵幀不止 2 幀的時,更推薦使用百分比定義的方式。

除此之外,當動畫的起始幀等同于 CSS 規則中賦予的值并且沒有設定 animation-fill-mode,0% 和 from 這一幀是可以刪除的。

動畫狀態的高優先級性

我曾經在這篇文章中 -- 深入理解 CSS(Cascading Style Sheets)中的層疊(Cascading)[11] 講過一個很有意思的 CSS 現象。

這也是很多人對 CSS 優先級的一個認知誤區,在 CSS 中,優先級還需要考慮選擇器的層疊(級聯)順序。

只有在層疊順序相等時,使用哪個值才取決于樣式的優先級。

那什么是層疊順序呢?

根據 CSS Cascading 4 最新標準:

CSS Cascading and Inheritance Level 5(Current Work)[12]

定義的當前規范下申明的層疊順序優先級如下(越往下的優先級越高,下面的規則按升序排列):

  • Normal user agent declarations
  • Normal user declarations
  • Normal author declarations
  • Animation declarations
  • Important author declarations
  • Important user declarations
  • Important user agent declarations
  • Transition declarations

簡單翻譯一下:

按照上述算法,大概是這樣:

過渡動畫過程中每一幀的樣式 > 用戶代理、用戶、頁面作者設置的!important樣式 > 動畫過程中每一幀的樣式優先級 > 頁面作者、用戶、用戶代理普通樣式。

然而,經過多個瀏覽器的測試,實際上并不是這樣。(尷尬了)

舉個例子,我們可以通過這個特性,覆蓋掉行內樣式中的 !important 樣式:

  1. <p class="txt" style="color:red!important">123456789</p> 
  1. .txt { 
  2.     animation: colorGreen 2s infinite; 
  3. @keyframes colorGreen { 
  4.     0%, 
  5.     100% { 
  6.         color: green; 
  7.     } 

在 Safari 瀏覽器下,上述 DEMO 文本的顏色為綠色,也就是說,處于動畫狀態中的樣式,能夠覆蓋掉行內樣式中的 !important 樣式,屬于最最高優先級的一種樣式,我們可以通過無限動畫、或者 animation-fill-mode: forwards,利用這個技巧,覆蓋掉本來應該是優先級非常非常高的行內樣式中的 !important 樣式。

我在早兩年的 Chrome 中也能得到同樣的結果,但是到今天(2022-01-10),最新版的 Chrome 已經不支持動畫過程中關鍵幀樣式優先級覆蓋行內樣式 !important 的特性。

對于不同瀏覽器,感興趣的同學可以利用我這個 DEMO 自行嘗試,CodePen Demo - the priority of CSS Animation[13]

CSS 動畫的優化

這也是非常多人非常關心的一個重點。

我的 CSS 動畫很卡,我應該如何去優化它?

動畫元素生成獨立的 GraphicsLayer,強制開始 GPU 加速

CSS 動畫很卡,其實是一個現象描述,它的本質其實是在動畫過程中,瀏覽器刷新渲染頁面的幀率過低。通常而言,目前大多數瀏覽器刷新率為 60 次/秒,所以通常來講 FPS 為 60 frame/s 時動畫效果較好,也就是每幀的消耗時間為 16.67ms。

頁面處于動畫變化時,當幀率低于一定數值時,我們就感覺到頁面的卡頓。

而造成幀率低的原因就是瀏覽器在一幀之間處理的事情太多了,超過了 16.67ms,要優化每一幀的時間,又需要完整地知道瀏覽器在每一幀干了什么,這個就又涉及到了老生常談的瀏覽器渲染頁面。

到今天,雖然不同瀏覽器的渲染過程不完全相同,但是基本上大同小異,基本上都是:

簡化一下也就是這個圖:

這兩張圖,你可以在非常多不同的文章中看到。

回歸本文的重點,Web 動畫很大一部分開銷在于層的重繪,以層為基礎的復合模型對渲染性能有著深遠的影響。當不需要繪制時,復合操作的開銷可以忽略不計,因此在試著調試渲染性能問題時,首要目標就是要避免層的重繪。那么這就給動畫的性能優化提供了方向,減少元素的重繪與回流。

這其中,如何減少頁面的回流與重繪呢,這里就會運用到我們常說的** GPU 加速**。

GPU 加速的本質其實是減少瀏覽器渲染頁面每一幀過程中的 reflow 和 repaint,其根本,就是讓需要進行動畫的元素,生成自己的 GraphicsLayer。

瀏覽器渲染一個頁面時,它使用了許多沒有暴露給開發者的中間表現形式,其中最重要的結構便是層(layer)。

在 Chrome 中,存在有不同類型的層:RenderLayer(負責 DOM 子樹),GraphicsLayer(負責 RenderLayer 的子樹)。

GraphicsLayer ,它對于我們的 Web 動畫而言非常重要,通常,Chrome 會將一個層的內容在作為紋理上傳到 GPU 前先繪制(paint)進一個位圖中。如果內容不會改變,那么就沒有必要重繪(repaint)層。

而當元素生成了自己的 GraphicsLayer 之后,在動畫過程中,Chrome 并不會始終重繪整個層,它會嘗試智能地去重繪 DOM 中失效的部分,也就是發生動畫的部分,在 Composite 之前,頁面是處于一種分層狀態,借助 GPU,瀏覽器僅僅在每一幀對生成了自己獨立 GraphicsLayer 元素層進行重繪,如此,大大的降低了整個頁面重排重繪的開銷,提升了頁面渲染的效率。

因此,CSS 動畫(Web 動畫同理)優化的第一條準則就是讓需要動畫的元素生成了自己獨立的 GraphicsLayer,強制開始 GPU 加速,而我們需要知道是,GPU 加速的本質是利用讓元素生成了自己獨立的 GraphicsLayer,降低了頁面在渲染過程中重繪重排的開銷。

當然,生成自己的獨立的 GraphicsLayer,不僅僅只有 transform3d api,還有非常多的方式。在 CSS 中,包括但不限于(找了很多文檔,沒有很全面的,需要一個一個去嘗試,通過開啟 Chrome 的 Layer border 選項):

  • 3D 或透視變換(perspective、transform) CSS 屬性
  • 使用加速視頻解碼的
  • 擁有 3D (WebGL) 上下文或加速的 2D 上下文的 元素
  • 混合插件(如 Flash)
  • 對自己的 opacity 做 CSS 動畫或使用一個動畫變換的元素
  • 擁有加速 CSS 過濾器的元素
  • 元素有一個包含復合層的后代節點(換句話說,就是一個元素擁有一個子元素,該子元素在自己的層里)
  • 元素有一個 z-index 較低且包含一個復合層的兄弟元素(換句話說就是該元素在復合層上面渲染)

對于上述一大段非常繞的內容,你可以再看看這幾篇文章:

  • 【Web動畫】CSS3 3D 行星運轉 && 瀏覽器渲染原理[14]
  • Accelerated Rendering in Chrome[15]

除了上述準則之外,還有一些提升 CSS 動畫性能的建議:

減少使用耗性能樣式

不同樣式在消耗性能方面是不同的,改變一些屬性的開銷比改變其他屬性要多,因此更可能使動畫卡頓。

例如,與改變元素的文本顏色相比,改變元素的 box-shadow 將需要開銷大很多的繪圖操作。box-shadow 屬性,從渲染角度來講十分耗性能,原因就是與其他樣式相比,它們的繪制代碼執行時間過長。這就是說,如果一個耗性能嚴重的樣式經常需要重繪,那么你就會遇到性能問題。

類似的還有 CSS 3D 變換、mix-blend-mode、filter,這些樣式相比其他一些簡單的操作,會更加的消耗性能。我們應該盡可能的在動畫過程中降低其使用的頻率或者尋找替代方案。

當然,沒有不變的事情,在今天性能很差的樣式,可能明天就被優化,并且瀏覽器之間也存在差異。

因此關鍵在于,我們需要針對每一起卡頓的例子,借助開發工具來分辨出性能瓶頸所在,然后設法減少瀏覽器的工作量。學會 Chrome 開發者工具的 Performance 面板及其他渲染相關的面板非常重要,當然這不是本文的重點。大家可以自行探索。

使用 will-change 提高頁面滾動、動畫等渲染性能

will-change 為 Web 開發者提供了一種告知瀏覽器該元素會有哪些變化的方法,這樣瀏覽器可以在元素屬性真正發生變化之前提前做好對應的優化準備工作。這種優化可以將一部分復雜的計算工作提前準備好,使頁面的反應更為快速靈敏。

值得注意的是,用好這個屬性并不是很容易:

  • 不要將 will-change 應用到太多元素上:瀏覽器已經盡力嘗試去優化一切可以優化的東西了。有一些更強力的優化,如果與 will-change 結合在一起的話,有可能會消耗很多機器資源,如果過度使用的話,可能導致頁面響應緩慢或者消耗非常多的資源。
  • 有節制地使用:通常,當元素恢復到初始狀態時,瀏覽器會丟棄掉之前做的優化工作。但是如果直接在樣式表中顯式聲明了 will-change 屬性,則表示目標元素可能會經常變化,瀏覽器會將優化工作保存得比之前更久。所以最佳實踐是當元素變化之前和之后通過腳本來切換 will-change 的值。
  • 不要過早應用 will-change 優化:如果你的頁面在性能方面沒什么問題,則不要添加 will-change 屬性來榨取一丁點的速度。will-change 的設計初衷是作為最后的優化手段,用來嘗試解決現有的性能問題。它不應該被用來預防性能問題。過度使用 will-change 會導致大量的內存占用,并會導致更復雜的渲染過程,因為瀏覽器會試圖準備可能存在的變化過程。這會導致更嚴重的性能問題。
  • 給它足夠的工作時間:這個屬性是用來讓頁面開發者告知瀏覽器哪些屬性可能會變化的。然后瀏覽器可以選擇在變化發生前提前去做一些優化工作。所以給瀏覽器一點時間去真正做這些優化工作是非常重要的。使用時需要嘗試去找到一些方法提前一定時間獲知元素可能發生的變化,然后為它加上 will-change 屬性。

有人說 will-change 是良藥,也有人說是毒藥,在具體使用的時候,可以多測試一下。

最后

好了,本文從多個方面,由淺入深地描述了 CSS 動畫我認為的一些比較重要、值得一講、需要注意的點。當然很多地方點到即止,或者限于篇幅沒有完全展開,很多細節還需要讀者進一步閱讀規范或者自行嘗試驗證,實踐出真知,紙上得來終覺淺。

OK,本文到此結束,希望本文對你有所幫助 :)

想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 😄

更多精彩 CSS 技術文章匯總在我的 Github -- iCSS[16] ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

參考資料

[1]CSS Animations Level 1:

https://www.w3.org/TR/2018/WD-css-animations-1-20181011/

[2]純 CSS 實現華為充電動畫:

https://codepen.io/Chokcoco/pen/vYExwvm

[3]純 CSS 實現火焰動畫:

https://codepen.io/Chokcoco/pen/jJJbmz

[4]CodePen Demo -- 利用范圍隨機 animation-duration 和 animation-delay 實現隨機動畫效果:

https://codepen.io/Chokcoco/pen/JjyRYyR

[5]cubic-bezier:

https://cubic-bezier.com/#.25,.1,.25,1

[6]CodePen Demo - 緩動不同效果不同:

https://codepen.io/Chokcoco/pen/JjyxLMY

[7]CodePen Demo -- Sprite Animation with steps() :

https://codepen.io/Chokcoco/pen/JjrBqJZ

[8]CodePen Demo -- Scale Loading steps vs linear:

https://codepen.io/Chokcoco/pen/oNGMROO

[9]CodePen Demo -- CSS Beer!:

https://codepen.io/mikegolus/pen/jJzRwJ

[10]SF - 如何理解 animation-fill-mode:

https://segmentfault.com/q/1010000003867335

[11]深入理解 CSS(Cascading Style Sheets)中的層疊(Cascading):

https://github.com/chokcoco/iCSS/issues/76

[12]CSS Cascading and Inheritance Level 5(Current Work):

https://www.w3.org/TR/css-cascade-5/#cascade-sort

[13]CodePen Demo - the priority of CSS Animation:

https://codepen.io/Chokcoco/pen/PowaXjM

[14]【Web動畫】CSS3 3D 行星運轉 && 瀏覽器渲染原理:

https://www.cnblogs.com/coco1s/p/5439619.html

[15]Accelerated Rendering in Chrome:

https://www.html5rocks.com/zh/tutorials/speed/layers/#disqus_thread

[16]Github -- iCSS:

https://github.com/chokcoco/iCSS

 

責任編輯:姜華 來源: iCSS前端趣聞
相關推薦

2009-08-17 15:52:42

C#多態

2009-06-18 10:23:03

Javascript 基本框架

2021-03-16 08:54:35

AQSAbstractQueJava

2011-07-04 10:39:57

Web

2021-07-20 15:20:02

FlatBuffers阿里云Java

2019-01-07 15:29:07

HadoopYarn架構調度器

2012-05-21 10:06:26

FrameworkCocoa

2017-07-02 18:04:53

塊加密算法AES算法

2022-09-26 09:01:15

語言數據JavaScript

2019-11-11 14:51:19

Java數據結構Properties

2009-11-30 16:46:29

學習Linux

2022-11-09 08:06:15

GreatSQLMGR模式

2021-04-27 08:54:43

ConcurrentH數據結構JDK8

2019-12-04 10:13:58

Kubernetes存儲Docker

2018-11-09 16:24:25

物聯網云計算云系統

2009-11-18 13:30:37

Oracle Sequ

2022-10-31 09:00:24

Promise數組參數

2012-02-21 13:55:45

JavaScript

2022-12-02 09:13:28

SeataAT模式

2025-03-27 09:38:35

點贊
收藏

51CTO技術棧公眾號

亚洲精品按摩视频| 一区二区三区成人| 国产精品视频中文字幕91| 国产精品麻豆免费版现看视频| 国产精品久久久久77777丨| 中文字幕av在线一区二区三区| 91免费看国产| 国产做受高潮漫动| 深爱激情综合| 制服丝袜中文字幕亚洲| 久久国产精品网| 国产对白叫床清晰在线播放| 黑人精品欧美一区二区蜜桃| 97婷婷涩涩精品一区| 69xxx免费| 精品女人视频| 欧美久久一二区| 亚洲 欧美 日韩 国产综合 在线| 91精彩视频在线观看| 丰满少妇久久久久久久| 日本韩国一区二区| 日本一级淫片演员| 国产一级二级三级在线观看| 国产二区国产一区在线观看| 国产成人在线视频| 国产亚洲精品久久久久久无几年桃 | 色天使色偷偷av一区二区| 婷婷久久伊人| 精品国产无码AV| 日韩vs国产vs欧美| 97精品一区二区三区| 青青操在线视频观看| 综合综合综合综合综合网| 日韩三级视频在线看| 久久久国产欧美| 日本不良网站在线观看| 亚洲一区二区欧美日韩| 天天成人综合网| 二区三区在线播放| 国产校园另类小说区| 精品久久一区二区三区蜜桃| www.五月婷婷| 国产一区二区美女| 国产日韩欧美在线视频观看| 国产伦精品一区二区三区视频我| 99国产成+人+综合+亚洲欧美| 欧美黑人巨大精品一区二区| 1024手机在线视频| 亚洲国产一区二区在线观看| 精品国产一区二区三区久久久 | 私拍精品福利视频在线一区| 精品免费一区二区三区| 蜜桃色一区二区三区| 日韩中文一区二区| 日韩欧美一区二区不卡| 佐山爱在线视频| 激情五月综合婷婷| 欧美一级夜夜爽| 色黄视频免费看| 一区二区三区亚洲变态调教大结局| 欧美一区日本一区韩国一区| a级大片免费看| 99这里只有精品视频| 日韩精品一区国产麻豆| av免费观看不卡| 成人在线tv视频| 亚洲成色777777在线观看影院| 野战少妇38p| 欧美电影在线观看免费| 亚洲女人天堂成人av在线| 3d动漫精品啪啪一区二区下载 | 亚洲四色影视在线观看| 中文字幕第24页| 日韩国产专区| 久久视频在线视频| 国产一卡二卡在线播放| av成人毛片| 国产精品成人观看视频国产奇米| 最好看的日本字幕mv视频大全| 理论电影国产精品| 91久色国产| 天堂在线观看免费视频| 久久综合999| 亚洲韩国在线| 最爽无遮挡行房视频在线| 亚洲成人中文在线| 免费男同深夜夜行网站| 欧美成人免费全部网站| 日韩精品一区二区三区在线播放| 久久久久久久久免费看无码| 日韩欧美网站| 久久久久久国产精品| 四虎成人在线观看| 精品亚洲成av人在线观看| 国产精品久久久久av福利动漫| 欧美视频免费一区二区三区| 亚洲色图视频免费播放| 日韩欧美视频网站| 日韩欧美三区| 亚洲国产精品久久91精品| 国产91丝袜美女在线播放| 欧美日韩精选| 国产精品成人播放| 神马午夜电影一区二区三区在线观看| 97久久精品人人澡人人爽| 在线观看日本一区| 在线观看的黄色| 日韩欧美精品三级| 中字幕一区二区三区乱码| 黑人一区二区| 国产在线观看精品| 欧美日韩国产亚洲沙发| 一级做a爱片久久| 日本xxxx黄色| 亚洲传媒在线| 久久91亚洲精品中文字幕| 无码人妻精品一区二区三区蜜桃91| 国产一区二区不卡| 亚洲国产欧洲综合997久久 | 91日韩欧美| 国产91av在线| 日本黄色三级视频| 成人免费在线视频观看| 中文字幕第21页| 色综合久久中文| 欧美精品成人在线| 国产日韩欧美一区二区东京热| 久久久久国产精品麻豆| 妞干网在线视频观看| 国产一区二区视频在线看| 一区二区三区高清国产| 国产a∨精品一区二区三区仙踪林| 国产精一品亚洲二区在线视频| 亚洲成人午夜在线| 裤袜国产欧美精品一区| 亚洲精品国产精品乱码不99按摩| 日本天堂中文字幕| 国产一区二三区| 亚洲一区精品视频| 国产精品一区二区免费福利视频| 亚洲视频一区二区| 欧美一级淫片免费视频黄| 99re热这里只有精品视频| 97在线国产视频| 中文久久电影小说| 欧美激情影音先锋| 黄色aaa大片| 亚洲国产美国国产综合一区二区| 欧美xxxxxbbbbb| 久久久久久美女精品 | 国产精品欧美亚洲| 国产精品久久午夜夜伦鲁鲁| 亚洲一级免费观看| 成人6969www免费视频| 国产精品久久97| 第一福利在线| 欧美日韩中文字幕一区二区| 日本性高潮视频| 免费在线看成人av| 亚洲电影免费| 国产精品国产亚洲精品| 久久成人免费视频| 国产成人自拍一区| 天天综合天天综合色| 一本色道综合久久欧美日韩精品| 乱码第一页成人| 日韩免费av一区二区三区| 秋霞国产精品| 久久精品国产欧美激情| www.亚洲天堂.com| 亚洲成精国产精品女| 亚洲天堂美女视频| 日韩二区三区四区| 自拍偷拍视频在线| 超碰一区二区三区| 日本成熟性欧美| 成a人片在线观看www视频| 欧美裸体一区二区三区| 欧美高清视频一区二区三区| 成a人片亚洲日本久久| 国产美女三级视频| 欧美hd在线| 国产91aaa| 日韩三区免费| 毛片精品免费在线观看| 午夜18视频在线观看| 欧美性大战久久| 九九热只有精品| 久久精品一区八戒影视| 手机在线国产视频| 中文国产一区| 亚洲欧洲久久| 卡一精品卡二卡三网站乱码| 国产精品久久9| 91超碰在线免费| 中文字幕视频一区二区在线有码| 国产手机av在线| 日韩欧美在线视频日韩欧美在线视频| 小早川怜子一区二区的演员表| 成人av电影在线观看| 亚洲高清在线免费观看| 国产中文一区| 亚洲精品8mav| 欧美亚洲tv| 99超碰麻豆| 久久久久久久性潮| 国内精品小视频在线观看| 欧美一区二区三区在线观看免费| 亚洲成人网在线| 国产精品羞羞答答在线| 91福利在线看| 日韩av一区二区在线播放| ...中文天堂在线一区| 香蕉网在线播放| 国产成人av网站| 日本黄大片一区二区三区| 国产精品毛片| 久久这里只有精品18| 91综合网人人| 日本一区视频在线观看| 牛牛精品成人免费视频| 91在线中文字幕| 国产成人免费| 国产成人+综合亚洲+天堂| av蜜臀在线| 欧美精品在线免费播放| 午夜视频在线观看网站| 亚洲香蕉成视频在线观看| 婷婷丁香花五月天| 日韩精品一区二区三区视频| 国产又粗又长视频| 欧美午夜电影在线播放| 日本视频网站在线观看| 午夜精品福利一区二区蜜股av| 国产乱国产乱老熟300| 亚洲色图制服丝袜| 久久福利免费视频| 国产精品久久久久久久久久久免费看| 成人午夜福利一区二区| 91在线观看污| 日本japanese极品少妇| 99久久精品费精品国产一区二区| 中文字幕制服丝袜| 国产suv一区二区三区88区| 九九九久久久久久久| 国产中文字幕精品| 国产又粗又猛大又黄又爽| 国产一本一道久久香蕉| 国产高清av片| 国产麻豆精品一区二区| 亚洲第一成肉网| 国产精品夜夜爽| 国产ts在线观看| 国产成人精品免费一区二区| 又色又爽又黄18网站| 成人精品免费视频| 在线观看国产三级| 久久综合中文字幕| 韩国女同性做爰三级| 中文一区在线播放 | 亚洲成人免费视| 97免费在线观看视频| 欧美性猛交xxxxx水多| 亚洲欧美日韩激情| 欧美三级日韩三级国产三级| 91福利免费视频| 日韩三区在线观看| 日韩一卡二卡在线| 亚洲日韩中文字幕| 五月香视频在线观看| 免费91在线视频| www.超碰在线| 国产精品精品久久久| 国产精品一区二区精品视频观看| 99视频日韩| 亚洲婷婷丁香| 在线看视频不卡| 亚洲视频狠狠| 蜜臀久久99精品久久久酒店新书| 免费精品视频最新在线| 国产在线视频三区| 97久久超碰精品国产| 你懂得视频在线观看| 一区二区三区不卡在线观看| 欧美一区二区三区不卡视频| 欧美日韩国产欧美日美国产精品| 亚洲大尺度视频| 亚洲美女视频网| 蜜芽在线免费观看| 91成人在线观看国产| 久久久久久久性潮| 久久国产精品一区二区三区| 手机亚洲手机国产手机日韩| 久久综合久久网| 老司机午夜精品| 久久久久亚洲AV成人无码国产| 欧美激情一区二区三区蜜桃视频| 麻豆亚洲av熟女国产一区二| 欧美影院午夜播放| 粉嫩av一区二区夜夜嗨| 国产亚洲欧洲在线| heyzo一区| 成人h视频在线| 亚洲综合小说图片| 成人午夜免费剧场| 视频一区中文字幕国产| 国产人妖在线观看| 中文字幕日本不卡| 无码aⅴ精品一区二区三区| 日韩一区二区电影在线| 国产香蕉在线| 97香蕉久久超级碰碰高清版| 久久三级中文| 婷婷亚洲婷婷综合色香五月| 亚洲国产日本| 中文字幕第10页| 中文字幕久久午夜不卡| 国产成人在线视频观看| 日韩欧美国产1| 免费高清在线观看| 国产精品女主播| 日本三级久久| 成人精品视频在线播放| 国产乱码精品一区二区三| 中文字幕免费高清| 欧美日韩一区二区三区在线免费观看| 性欧美18一19性猛交| 久久精品电影一区二区| 97精品国产综合久久久动漫日韩| 蜜桃免费一区二区三区| 亚洲高清激情| 亚洲成年人av| 一区二区三区国产精品| 国产黄色一级大片| 久久亚洲私人国产精品va| 日韩欧美专区| 一区二区三区欧美成人| 奇米精品一区二区三区四区| 国产高潮呻吟久久| 色综合久久久久久久久| 日本一卡二卡四卡精品| 2018日韩中文字幕| 日韩av不卡一区| 无码人妻丰满熟妇区96| 97精品国产露脸对白| 日本一级片免费看| 精品无码久久久久久国产| 免费成人在线电影| 欧美lavv| 日韩精品福利网| 免费看91的网站| 欧美日韩久久久一区| 日本综合在线| 成人精品一区二区三区| 欧美va天堂在线| 女女调教被c哭捆绑喷水百合| 亚洲电影激情视频网站| 四虎在线视频免费观看| 欧美一级淫片丝袜脚交| 精品一区免费| 校园春色 亚洲色图| 中文字幕一区二区三区不卡| 国产色在线视频| 欧美极品少妇xxxxⅹ喷水| 国产精品对白久久久久粗| 日日橹狠狠爱欧美超碰| 国产天堂亚洲国产碰碰| 伊人免费在线观看高清版| 久久精品成人欧美大片| 97色成人综合网站| 一本大道熟女人妻中文字幕在线| 国产色产综合产在线视频| 亚洲一区精品在线观看| 久热精品视频在线免费观看| 国产福利资源一区| 嫩草av久久伊人妇女超级a| 亚洲视频免费看| 天天射,天天干| 国产精品精品一区二区三区午夜版| 91精品国产自产在线观看永久∴| 美女流白浆视频| 狠狠躁夜夜躁人人躁婷婷91| 日韩大片在线永久免费观看网站| 成人一区二区三区四区| 午夜在线视频观看日韩17c| 永久免费观看片现看| 337p日本欧洲亚洲大胆精品| 欧美电影h版| 777久久精品一区二区三区无码| 99久久精品国产毛片| 国产毛片在线视频| 欧美一级成年大片在线观看| 天天天综合网| 人妻丰满熟妇aⅴ无码| 欧美一级在线视频| 欧美大片高清| www.夜夜爱| 国产精品护士白丝一区av| 深爱五月激情五月| 91在线观看免费高清完整版在线观看|