首頁  >  文章  >  web前端  >  CSS動畫技巧與細節

CSS動畫技巧與細節

巴扎黑
巴扎黑原創
2017-09-20 09:45:191830瀏覽

本文希望透過介紹一些CSS 不太常用的技巧,輔以一些實踐,讓讀者可以更深入的理解掌握CSS 動畫效果,非常不錯,具有參考借鑒價值,需要的朋友參考下吧

害怕標題起的有點大,下述技巧如果你已經掌握了看看就好,歡迎斧正,本文希望透過介紹一些CSS 不太常用的技巧,輔以一些實踐,讓讀者可以更加深入的理解掌握CSS 動畫。

廢話少說,直接進入正題,本文提到的動畫不加特殊說明,皆指 CSS 動畫。

正負旋轉相消

嗯。名字取的很奇怪,好像數學概念一樣。

在動畫中,旋轉是非常常用的屬性,


{
  transform: rotate(90deg);
}

那旋轉有一些什麼高級點的技巧呢?當然是可以改變 transfrom-origin ,改變旋轉中心點啦。

開個玩笑,改變旋轉中心點這個估計大家都知道了,這裡要介紹的技巧是利用父級元素正反兩個方向的旋轉,來製作一些酷炫的 3d 效果。

先假設場景,我們有這樣的一層HTML 結構:


<p class="reverseRotate">
    <p class="rotate">
        <p class="content">正负旋转相消3D动画</p>
    </p>
</p>

樣式如下:

.content 內是我們的主要內容,好了,現在想像一下,如果祖先元素.rotate 進行正向linear 360° 旋轉,父級元素.reverseRotate 進行反向linear 360° 旋轉,效果回是啥樣?

CSS 程式碼如下:


.rotate {
    animation: rotate 5s linear infinite; 
}
.reverseRotate {
    animation: reverseRotate 5s linear infinite; 
}
@keyframes rotate {
    100% {
        transform: rotate(360deg);
    }
}
@keyframes reverseRotate {
    100% {
        transform: rotate(-360deg);
    }
}

神奇!因為一正一反的旋轉,且緩動函數一樣,所以整個 content 看上去依然是靜止的!注意,這裡整個 content 靜止的非常重要。

有讀者看到這裡就要罵街了,作者你個智障,靜止了不就沒動畫了嗎?哪來的動畫技巧?

別急!雖然看起來是靜止的,但其實祖先兩個元素都是在旋轉的!這會看起來風平浪靜的效果底下其實是暗流湧動。用開發者工具選取最外層祖先元素是這樣的:

既然如此,我們繼續思考,如果我在其中旋轉的一個祖先元素上,添加一些別的動畫會是什麼效果?想想就很刺激啊。

為了跟文案裡面的3D 動畫扯上關係,我們先為這幾個元素加入3D 轉換:


p {
    transform-style: preserve-3d;
    perspective: 500px;
}

接著,試著修改上面的旋轉動畫,在內層旋轉上額外新增一個rotateX:


@keyframes rotate {
    0% {
        transform: rotateX(0deg) rotateZ(0deg);
    }
    50% {
        transform: rotateX(40deg) rotateZ(180deg);
    }
    100% {
        transform: rotateX(0deg) rotateZ(360deg);
    }
}

效果如下:

##Wow,這裡需要好好理解一下。由於內容

content 層是靜止的但其實外層兩個圖層都在旋轉,透過設定額外的rotateX(40deg) ,相當於疊加多了一個動畫,由於正反旋轉抵消了,所有整個動畫只能看到旋轉的rotateX(40deg) 這個動畫,產生了上述的效果。

CodePen Demo -- Css正負旋轉相消動畫

動畫相同,緩動不同

好的,繼續下一個小技巧。

有的時候我們頁面存在一些具有相同動畫的元素,為了讓動畫不那麼死板,我們可以給相同的動畫,賦予不同的緩動函數,來達到動畫效果。

假設我們有如下的結構:


<p class="container">
    <p class="ball ball1"></p>
    <p class="ball ball2"></p>
    <p class="ball ball3"></p>
</p>

樣式如下:

我們給它們相同的動畫,但賦予不一樣的緩動函數(animation-timing-function),就像這樣:


.ball1 {
    animation: move 1s ease-in infinite alternate;
}
.ball2 {
    animation: move 1s linear infinite alternate;
}
.ball3 {
    animation: move 1s ease-out infinite alternate;
}
@keyframes move {
    100% {
        transform: translateY(5vw);
    }
}

這樣,一個簡單的loading 效果就製作好了。 (當然這個技巧比較簡單,學會合理運用是關鍵)

CodePen Demo -- 動畫相同,緩動不同

奇妙的緩動

緩動函數timing-function 在動畫中佔據了非常重要的地位。

當你不想使用CSS 預設提供的

linearease-inease-out 之類緩動函數的,可以自定義cubic-bezier(1, 1, 0, 0),這裡有個非常好用的工具推薦,下面這個網站,可以方便的調出你需要的緩動函數並且拿到對應的cubic-bezier 。

cubic-bezier.com

過渡取消

我们在制作页面的时候,为了让页面更加有交互感,会给按钮,阴影,颜色等样式添加过渡效果,配合 hover 一起使用。

这个是常规思维,如果我们的元素一开始是没有过渡效果,只有 hover 上去才给它添加一个过渡,又或者一开始元素是有过渡效果的,当我们 hover 上去时,取消它的过渡,会碰撞出什么样的火花呢?

使用这个技巧(也许算不上技巧,纯粹好玩),我们可以制作出一些有趣的效果,例如下面这个感觉是利用就 JS 才完成的动画,其实是纯 CSS 动画:

其实就小圆圈是元素默认是带有 transition 的,只有在 hover 上去的时候,取消它的过渡,简单的过程:

  • 由于一开始它的颜色的透明的,而 hover 的时候会赋予它颜色值,但是由于 hover 时过渡被取消了,所有它会直接显示。

  • hover 离开的时候,它的原本的过渡又回来了,这个时候它会从有颜色到透明值缓慢渐变消失。

可以戳这里感受一下:

CodePen Demo -- Cancle transition

动画层级的控制,保持动画层级在最上方

这个问题可能有一点难理解。需要了解 CSS 动画渲染优化的相关知识。

先说结论,动画层级的控制的意思是尽量让需要进行 CSS 动画的元素的 z-index 保持在页面最上方,避免浏览器创建不必要的图形层(GraphicsLayer),能够很好的提升渲染性能。

OK,再一次提到了图形层(GraphicsLayer),这是一个浏览器渲染原理相关的知识(WebKit/blink内核下)。

简单来说,浏览器为了提升动画的性能,为了在动画的每一帧的过程中不必每次都重新绘制整个页面。在特定方式下可以触发生成一个合成层,合成层拥有单独的 GraphicsLayer。

需要进行动画的元素包含在这个合成层之下,这样动画的每一帧只需要去重新绘制这个 Graphics Layer 即可,从而达到提升动画性能的目的。

那么一个元素什么时候会触发创建一个 Graphics Layer 层?从目前来说,满足以下任意情况便会创建层:

  • 硬件加速的 iframe 元素(比如 iframe 嵌入的页面中有合成层)

  • 硬件加速的插件,比如 flash 等等

  • 使用加速视频解码的 元素

  • 3D 或者 硬件加速的 2D Canvas 元素

  • 3D 或透视变换(perspective、transform) 的 CSS 属性

  • 对自己的 opacity 做 CSS 动画或使用一个动画变换的元素

  • 拥有加速 CSS 过滤器的元素

  • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)

  • 元素有一个 z-index 较低且包含一个复合层的兄弟元素

本题中说到的动画层级的控制,原因就在于上面生成层的最后一条:

元素有一个 z-index 较低且包含一个复合层的兄弟元素。

这里是存在坑的地方,首先我们要明确两点:

  1. 我们希望我们的动画得到 GPU 硬件加速,所以我们会利用类似 transform: translate3d() 这样的方式生成一个 Graphics Layer 层。

  2. Graphics Layer 虽好,但不是越多越好,每一帧的渲染内核都会去遍历计算当前所有的 Graphics Layer ,并计算他们下一帧的重绘区域,所以过量的 Graphics Layer 计算也会给渲染造成性能影响。

记住这两点之后,回到上面我们说的坑。

假设我们有一个轮播图,有一个 ul 列表,结构如下:


e8f5c74c2e445a663d1be11ec1ea30fb
    ab7863aa92413627b6d3a3f990074b6f轮播图94b3e26ee717c64999d7867364b1b4a3
    74208dc2409290cdfcb863d04dbdcf53
        25edfb22a4f469ecb59f1190150159c6列表libed06894275b65c1ab86501b08a632eb
        25edfb22a4f469ecb59f1190150159c6列表libed06894275b65c1ab86501b08a632eb
        25edfb22a4f469ecb59f1190150159c6列表libed06894275b65c1ab86501b08a632eb
        25edfb22a4f469ecb59f1190150159c6列表libed06894275b65c1ab86501b08a632eb
    929d1f5ca49e04fdcb27f9465b944689
94b3e26ee717c64999d7867364b1b4a3

假设给他们定义如下 CSS:


.swiper {
    position: static;
    animation: 10s move infinite;
} 
.list {
    position: relative;
}
@keyframes move {
    100% {
        transform: translate3d(10px, 0, 0);
    }
}

由于给 .swiper 添加了 translate3d(10px, 0, 0) 动画,所以它会生成一个 Graphics Layer,如下图所示,用开发者工具可以打开层的展示,图形外的黄色边框即代表生成了一个独立的复合层,拥有独立的 Graphics Layer 。

<

但是!在上面的图中,我们并没有给下面的 list 也添加任何能触发生成 Graphics Layer 的属性,但是它也同样也有黄色的边框,生成了一个独立的复合层。

原因在于上面那条元素有一个 z-index 较低且包含一个复合层的兄弟元素。我们并不希望 list 元素也生成 Graphics Layer ,但是由于 CSS 层级定义原因,下面的 list 的层级高于上面的 swiper,所以它被动的也生成了一个 Graphics Layer 。

使用 Chrome,我们也可以观察到这种层级关系,可以看到 .list 的层级高于 .swiper

所以,下面我们修改一下 CSS ,改成:


.swiper {
    position: relative;
    z-index: 100;
}   
.list {
    position: relative;
}

这里,我们明确使得 .swiper 的层级高于 .list ,再打开开发者工具观察一下:

可以看到,这一次,.list 元素已经没有了黄色外边框,说明此时没有生成 Graphics Layer 。再看看层级图:

此时,层级关系才是我们希望看到的,.list 元素没有触发生成 Graphics Layer 。而我们希望需要硬件加速的 .swiper 保持在最上方,每次动画过程中只会独立重绘这部分的区域。

总结

  • GPU 硬件加速也会有坑,当我们希望使用利用类似 transform: translate3d() 这样的方式开启 GPU 硬件加速,一定要注意元素层级的关系,尽量保持让需要进行 CSS 动画的元素的 z-index 保持在页面最上方。

  • Graphics Layer 不是越多越好,每一帧的渲染内核都会去遍历计算当前所有的 Graphics Layer ,并计算他们下一帧的重绘区域,所以过量的 Graphics Layer 计算也会给渲染造成性能影响。

  • 可以使用 Chrome ,用上面介绍的两个工具对自己的页面生成的 Graphics Layer 和元素层级进行观察然后进行相应修改。

  • 上面观察页面层级的 chrome 工具非常吃内存?好像还是一个处于实验室的功能,分析稍微大一点的页面容易直接卡死,所以要多学会使用第一种观察黄色边框的方式查看页面生成的 Graphics Layer 这种方式。

数字动画

很多技巧单独拿出来可能都显得比较单薄,我觉得最重要的是平时多积累,学会融会贯通,在实际项目中灵活组合运用,最近项目需要一个比较富有科技感的数字计数器,展示在线人数的不断增加。因为是内部需求,没有设计稿,靠前端自由发挥。

运用了上面提到的一些小技巧,参考了一些 CodePen 上的效果,整了个下述的 3D 数字计数效果,纯 CSS 实现,效果图如下:

以上是CSS動畫技巧與細節的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn