이 글에서는 독자들이 CSS 애니메이션 효과에 대해 더 깊이 이해할 수 있도록 일반적으로 사용되지 않는 몇 가지 CSS 기술을 소개하고, 필요한 친구들이 참고할 수 있기를 바랍니다. 제목이 좀 크네요. 다음 기술을 마스터했다면 한 번 살펴보시기 바랍니다. 이 기사에서는 일반적으로 사용되지 않는 몇 가지 CSS 기술을 소개하고 독자들이 이를 보완할 수 있기를 바랍니다. CSS 애니메이션에 대해 더 깊이 이해할 수 있습니다.
더 이상 말도 안 되는 소리는 하지 말고 바로 본론으로 들어가겠습니다. 이 글에서 언급된 애니메이션은 특별한 설명 없이 모두 CSS 애니메이션을 참조합니다.
양의 회전과 음의 회전은 서로 상쇄됩니다흠. 수학적 개념처럼 이름이 참 이상해요.
애니메이션에서 회전은 매우 일반적으로 사용되는 속성입니다.
{ transform: rotate(90deg); }
transfrom-origin
을 변경하고 회전 중심점을 변경할 수도 있습니다. 농담입니다. 회전 중심점 변경에 대해 다들 알고 계실 겁니다. 제가 여기서 소개하고 싶은 기술은 상위 요소의 양수 회전과 음수 회전을 사용하여 멋진 3D 효과를 만드는 것입니다. 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 默认提供的 linear
、ease-in
、ease-out
之类缓动函数的,可以自定义 cubic-bezier(1, 1, 0, 0)
<p class="container">
<p class="swiper">轮播图</p>
<ul class="list">
<li>列表li</li>
<li>列表li</li>
<li>列表li</li>
<li>列表li</li>
</ul>
</p>
.content
가 우리의 주요 콘텐츠입니다. 좋습니다. 이제 상상해보세요. 상위 요소 .rotate
는 순방향 선형 360° 회전을 수행하고 상위 요소 .reverseRotate
는 역방향 선형 360° 회전을 수행합니다. 효과는 어떻게 될까요? 🎜🎜CSS 코드는 다음과 같습니다: 🎜🎜🎜🎜.swiper { position: static; animation: 10s move infinite; } .list { position: relative; } @keyframes move { 100% { transform: translate3d(10px, 0, 0); } }
콘텐츠
는 여전히 🎜정지된🎜 것처럼 보입니다! 여기에서는 전체 콘텐츠
가 정적이라는 것이 매우 중요합니다. 🎜🎜이거 보면 욕하는 분들도 계실 텐데요, 작가님, 멈추면 애니메이션이 안 나오는 거 아닌가요? 애니메이션 기술은 어디서 얻었나요? 🎜🎜걱정하지 마세요! 정지해 있는 것처럼 보이지만 두 조상 요소는 실제로 회전하고 있습니다! 이는 차분한 효과처럼 보일 수 있지만 그 밑에는 실제로 저류가 있습니다. 개발자 도구를 사용하여 가장 바깥쪽 조상 요소를 선택하는 방법은 다음과 같습니다: 🎜🎜🎜이 경우, 회전하는 조상 요소에 다른 애니메이션을 추가하면 어떤 효과가 있을지 계속 생각해 볼까요? 생각만 해도 신난다. 🎜🎜복사본의 3D 애니메이션과 연관시키기 위해 먼저 다음 요소에 3D 변형을 추가합니다. 🎜🎜🎜🎜
.swiper { position: relative; z-index: 100; } .list { position: relative; }
🎜🎜와, 이건 잘 이해해야 해요. 콘텐츠 content
레이어는 정적이지만 두 개의 외부 레이어가 실제로 회전하기 때문에 추가 rotateX(40deg)
를 설정하면 앞으로 애니메이션을 하나 더 겹쳐놓는 것과 같습니다. 역회전이 오프셋되면 전체 애니메이션은 위의 효과를 생성하는 회전된 rotateX(40deg)
애니메이션만 볼 수 있습니다. 🎜🎜CodePen 데모 -- CSS 포지티브 및 네거티브 회전 파괴 애니메이션🎜🎜애니메이션은 동일하지만 이징이 다릅니다🎜🎜좋아요, 다음 팁으로 넘어가겠습니다. 🎜🎜때때로 페이지에 동일한 애니메이션이 포함된 요소가 있을 수 있습니다. 애니메이션의 경직성을 완화하기 위해 동일한 애니메이션에 다양한 완화 기능을 제공하여 애니메이션 효과를 얻을 수 있습니다. 🎜🎜다음과 같은 구조가 있다고 가정합니다: 🎜🎜🎜🎜rrreee🎜스타일은 다음과 같습니다: 🎜
🎜🎜다음과 같이 동일한 애니메이션을 제공하지만 다른 여유 기능(애니메이션-타이밍-함수)을 제공합니다. 🎜🎜🎜 🎜rrreee🎜이렇게 하면 간단한 로딩 효과가 생성됩니다. (물론 이 기술은 상대적으로 간단하므로 올바르게 사용하는 방법을 배우는 것이 핵심입니다) 🎜
🎜🎜CodePen 데모 -- 애니메이션은 동일하지만 이징은 다릅니다🎜🎜🎜🎜멋진 이징🎜🎜🎜🎜이징 기능 타이밍- 기능은 애니메이션 상태에서 매우 중요한 역할을 합니다. 🎜🎜CSS에서 제공하는 linear
, ease-in
, ease-out
등의 easing 기능을 사용하고 싶지 않을 때 기본적으로 cubic-bezier(1, 1, 0, 0)
을 사용자 정의할 수 있습니다. 여기에 매우 유용한 도구 권장 사항이 있습니다. 다음 웹사이트에서 필요한 여유 기능을 쉽게 호출하고 해당 기능을 얻을 수 있습니다. 입방 베 지어. 🎜🎜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 较低且包含一个复合层的兄弟元素。
这里是存在坑的地方,首先我们要明确两点:
我们希望我们的动画得到 GPU 硬件加速,所以我们会利用类似 transform: translate3d()
这样的方式生成一个 Graphics Layer 层。
Graphics Layer 虽好,但不是越多越好,每一帧的渲染内核都会去遍历计算当前所有的 Graphics Layer ,并计算他们下一帧的重绘区域,所以过量的 Graphics Layer 计算也会给渲染造成性能影响。
记住这两点之后,回到上面我们说的坑。
假设我们有一个轮播图,有一个 ul 列表,结构如下:
<p class="container"> <p class="swiper">轮播图</p> <ul class="list"> <li>列表li</li> <li>列表li</li> <li>列表li</li> <li>列表li</li> </ul> </p>
假设给他们定义如下 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!