# CSS3 动画面试题答案解析

关于答案解析

CSS3 动画相关面试题答案解析过程是根据自身项目实践以及查阅官方文档等最终的得出结论。 仅供学习参考,评论区感谢补充和纠错 !

# 1、css3 的动画了解多少? (广联达)

答案解析

css3 实现动画主要有 3 种方式

  • transition 过渡动画
  • transform 2D 和 3D 转换
  • animation 自定义动画

接下来针对这种动画形式来展开讲解

① transition 过渡动画

详细解读

  • 只有两个状态:开始和结束状态。我们只需要定义过渡属性的起始和结束值就 ok。
  • transition 不能在网页加载时自动发生,需用事件触发,一般与:hover 搭配使用。
  • 一次性,不能重复发生,除非一再触发

语法:

transition: transition-property transition-duration transition-timing-function
  transition-delay;
  • property:需要变化的 css 属性,如 width、height、color、font-size 等(display 属性没有过渡效果)
  • duration:完成过渡效果所需要的时间(单位 s 或 ms)
  • timing-function:时间函数,完成效果的速度曲线。具体值见下(表 1)
  • transition-delay:动画延时多长时间才开始执行(单位 s 或 ms)

timing-function 时间函数值(表 1)

说明
linear 匀速
ease 从慢到快再到慢的
ease-in 从慢-快
ease-out 从慢到慢结束
ease-in-out 慢到快到慢
cubic-bezier(n,n,n,n) 在 cubic-bezier 函数中定义自己的值。可能的值是 0 至 1 之间的数值。

② transform 2D 和 3D 转换

详细解读

  • transform 属性应用于 2D 和 3D 转换,该 属性允许我们对元素进行 rotate 旋转、scale 缩放、skew 倾斜、translate 移动这四类操作。
  • 一般是配合 transition 的属性一起使用

语法

transform: none | transform-functions;
  • none 默认值 不进行任何转换 一般用于删除掉之前加上的转换
  • transform-functions:定义要进行转换的类型函数,如(rotate、scale 等)

rotate 旋转函数

描述
rotate(angle) 定义 2D 旋转,在参数中规定角度。 如:rotate(30deg)
rotateX(angle) 定义沿着 X 轴的 3D 旋转。
rotateY(angle) 定义沿着 Y 轴的 3D 旋转。
rotateZ(angle) 定义沿着 Z 轴的 3D 旋转。
rotate3d(x,y,z,angle) 定义 3D 旋转。

scale 缩放函数

描述
scale(x[,y]?) 2D 缩放,如果只有 1 个值,表示 x,y 轴缩放比例
scaleX(x) 通过设置 X 轴的值来定义缩放转换。
scaleY(y) 通过设置 Y 轴的值来定义缩放转换。
scaleZ(z) 通过设置 Z 轴的值来定义缩放转换。
scale3d(x,y,z) 3D 缩放转换

skew 斜切 函数

描述
skew(x-angle,y-angle) 定义沿着 X 和 Y 轴的 2D 倾斜转换。
skewX(angle) 定义沿着 X 轴的 2D 倾斜转换。
skewY(angle) 定义沿着 Y 轴的 2D 倾斜转换。

translate 位移函数

描述
translate(x,y) x,y 轴平移
translateX(x) 沿 X 轴平移
translateY(y) 沿 Y 轴平移
translateZ(z) 沿 Z 轴平移 3D
translate3d(x,y,z) 沿 x,y,z 3D 下平移

其它下性

属性 描述
perspective(n) 3D 场景下的透视视距 如:perspective(800px)
transform-style 在 3D 空间中如何呈现子元素。
flat:所有子元素在 2D 平面呈现
preserve-3d:所有子元素在 3D 空间中呈现
transform-origin 设置旋转元素的基点位置
属性值可以是百分比、em、px 等具体的值,也可以是 top、right、bottom、left 和 center 这样的关键词。

特别注意

  • transform 先平移再旋转和先旋转再平移是有区别 ?
  • 如果先旋转再平移,会改变元素的平移的方向。(我们在下问题中来深度剖析)

③ animation 自定义动画

详细解读

  • 如果想要实现更加灵活和复杂的动画效果,可以利用 animation 来自定义动画
  • animation 需要调用 @keyframes 定义好的动画。

语法:

animation: name duration timing-function delay iteration-count direction
  fill-mode play-state;

@keyframes 定义动动画

@keyframes animation-name {keyframes-selector {css-styles;}}
  • animation-name:声明动画的名称。
  • keyframes-selector:用来划分动画的时长,可以使用百分比形式
  • 也可以使用 "from" 和 "to"的形式。
  • "from" 和 "to"的形式等价于 0% 和 100%。建议始终使用百分比形式。
属性 描述
animation-name 用来调用@keyframes 定义好的动画,与@keyframes 定义的动画名称一致
animation-duration 规定动画完成一个周期所花费的秒或毫秒。默认是 0
animation-timing-function 速度曲线,和 transition-timing-function 一样,可用的类型有 liner(匀速)、ease-in(减速)、ease-out(加速)ease-in-out(先加速再减速)、cubic-bezier:三次贝塞尔曲线,可以定制
steps()阶梯函数
animation-delay 规定动画何时开始,默认是 0
animation-iteration-count 规定动画被播放的次数。默认是 1
animation-direction normal 默认值,如果设置为 normal 时,动画每次循环都是向前(即按顺序)播放,alternate(轮流),动画播放在第偶数次向前播放,第奇数次向反方向播放(animation-iteration-count 取值大于 1 时设置有效)
animation-play-state running,可以通过该值将暂停的动画重新播放,这里的重新播放不是从元素动画的开始播放,而是从暂停的那个位置开始播放,paused,暂停播放
animation-fill-mode 默认情况下,动画结束后,元素的样式将回到起始状态,animation-fill-mode 属性可以控制动画结束后元素的样式。主要具有四个属性值:none(默认,回到动画没开始时的状态。),forwards(动画结束后动画停留在结束状态),backwords(动画回到第一帧的状态),both(根据 animation-direction 轮流应用 forwards 和 backwards 规则)

steps()阶梯函数

steps(numbers,direction)
  • numbers 指定了时间函数中的间隔数量(步长)
  • direction 有两值 start 和 end。
    • start 表示动画的第一帧会被立即执行,直接从第二帧开始
    • end 则表示动画从第一帧开始;

总结:transition 过渡动画与 animation 动画的比较

区别 transition animation
是否能自动执行 不能,需要事件触发,比如:hover
能否重复发生 不能,除非再一次触发
能否包含多个状态 不能,只有开始和结束状态 能,比如从 0% 到 100%,任意指定过渡状态
能否暂停 不能,一次性 能,比如 hover 事件触发暂停
能否定义速度曲线
能否定义某个属性值过渡

# 2、说一下 transform 的原理,先平移在旋转和先旋转再平移有什么区别(字节)

答案解析

  • 先平移后旋转,并不会改变坐标轴方向
  • 但是如果先旋转后平移,在旋转时坐标轴的方向也随着发生了改变
  • 然后再平移,移动的方向也就发生了改变了
<style>
  .box {
    width: 300px;
    height: 200px;
    background-color: pink;
    margin: 100px auto;
  }
  .item {
    width: 50px;
    height: 50px;
    background-color: #ddd;
    border-top: 5px solid blue;
    border-right: 5px solid skyblue;
    /*先平移,后旋转*/
    /* transform:translateX(100px) rotate(90deg)  ; */
    /*先旋转,后平移*/
    transform: rotate(90deg) translateX(100px);
  }
</style>
<body>
  <div class="box">
    <div class="item"></div>
  </div>
</body>

如果先平移,后旋转,得到的效果如下:

image-20220516173734039

如果先旋转,后平移,得到的效果如下:

image-20220516173705132

我们在实际开发中,要根据实际的效果来选择是先平移还是先旋转。

# 3、所有 css3 的动画都能用 GPU 加速么 ?(广联达)

答案解析

在 css 中,只有 3D 转换、opacity 透明、filter 滤镜和添加了 will-change 属性的元素,浏览器才会开启硬件(GPU)加速。

  • 不过如果我们想要 2D、过渡等动画也能开启硬件加速,我们可以通过给这些元素加上transform: translateZ(0); 或transform: translate3d(0,0,0);来诱导浏览器开启硬件加速,但是我们不能滥用。
  • 也可能通过添加 will-change 来实现。

接下来我们关于 GPU 加速做相关的知识普及

① 为什么需要 GPU 硬件加速 ?

详细解读

  • CSS3 动画在移动多终端设备场景下,相⽐ PC 会⾯对更多的性能问题,主要体现在动画的卡顿与闪烁。
  • 我们可以通过 GPU 硬件加速来解决这个问题

② CPU 、GPU、硬件加速的关系?

详细解读

  • 硬件加速意味着图形处理单元(GPU)会协助你的浏览器渲染网页,做一些繁重的工作,而不是把这些工作全部丢给中央处理单元(CPU)来完成。
  • 当一个 CSS 操作被硬件加速时,它的速度也会因为页面的渲染速度变快而得到提升。

CPU 和 GPU 都是处理单元

  • CPU 位于计算机的主板上,它被称为计算机的大脑。GPU 位于计算机的显卡上,负责处理和渲染图像
  • 此外,GPU 是专门为执行复杂的数学和几何计算而设计的,这些计算也是图形渲染的必要条件
  • 因此,将操作丢给 GPU 处理可以产生巨大的性能提升,也可以减少移动设备上的 CPU 争用。

硬件加速(又称 GPU 加速)

  • 依赖于浏览器渲染页面时使用的分层模型。
  • 当对页面上的元素进行某些操作(比如 3D 变换)时,该元素会被移动到属于它自己的“图层”,在那里它可以独立于页面的其他部分进行渲染,并在之后被合成(画到屏幕上)。
  • 这样就隔离了内容的渲染,如果该元素的变换是帧之间唯一的变化,那么页面的其他部分就不必重新渲染,这样往往能够提供明显的速度优势。
  • 不过这里需要说明一下:只有 3D 变换拥有属于自己的图层,2D 变换没有。

CSS 的 animation、transform 和 transition 不会自动进行 GPU 加速,一般是由浏览器缓慢的软件渲染引擎执行。
然而有些浏览器通过某些属性提供硬件加速,以获得更好的渲染性能

③ 在 css 中以下几个属性能触发硬件(GPU)加速

能触发硬件(GPU)加速的 CSS 属性

  • transform
  • opacity
  • filter
  • will-change

opacity不透明度就是少数可以适当加速的 CSS 属性之一,因为 GPU 可以很容易地操纵它。

  • 基本上,如果你在 transition 或 animation 里淡化不透明度,浏览器会智能地把它丢给 GPU 操作,速度会非常快。
  • 不透明度是所有 CSS 属性里性能最好的之一,你使用它不会出现任何问题。
  • 其他常见的硬件加速操作是 CSS 的 3D 变换。

④ will-change 用法及注意事项

详细解读

为了避免图层创建的黑客行为,我们引入了一个新的 CSS 属性will-change,它允许我们提前告知浏览器我们可能会对一个元素做出什么样的改变,从而使浏览器可以提前为元素做一些适当的优化。

  • 当在一个元素上使用 CSS 三维变换时,该元素及其内容可能会升到一个新的图层,就像前面提到的那样,之后才会被合成(绘制到屏幕上)。
  • 然而,在一个新的图层中设置元素是一个代价相对昂贵的操作,这可能会使变换动画的开始时间延迟几分之一秒,导致明显的“闪烁”。
  • 为了避免这种延迟,你可以在变化实际发生前的一段时间通知浏览器
  • 这样,浏览器就会有一些时间为这些变化做准备,当这些变化发生时,元素的图层就会准备好,变换动画就可以执行,然后元素就可以被渲染,页面就会迅速更新。

以下是在具体使用时的注意事项

a、不要将 will-change 应用到太多元素上

TIP

这种方式是非常有害的,因为更多的操作是无效的,而且有可能占用机器大量的资 源,过度使用,会导致页面变慢甚至崩溃。

  • 换句话说,让浏览器对可能发生也可能不发生的变化保持准备状态而不是什么好事,不要这样做。
  • 我们只需要对那些真正能提升性能的地方加上 will-change,而不要滥用 will-change 造成不该有的性能问题。
* {
  will-change: all;
}
/* 或 */
.box {
  will-change: all;
}

b、给浏览器留足时间准备

案例:鼠标滑动到元素上时,元素的透明度发生改变

  • 我们可以在鼠标滑动到他的祖先元素时就做好提醒,而不是在鼠标滑动到元素上时再做提醒。
  • 如果滑动到元素上时做提醒其实是没有意义的。
.box:hover .item {
  /*当鼠标进入或悬停到其祖先时,声明该元素接下来要发生的变化,让浏览器做好准备*/
  will-change: opacity;
}
.item:hover {
  /* will-change: opacity; 直接写在这里是无效的,并不会带来什么作用*/
  opacity: 0.5; /*鼠标悬停到元素时发生的变化*/
}

c、在样式表中谨慎使用

TIP

通常,当元素恢复到初始状态时,浏览器会丢弃掉之前做的优化工作。

  • 但是如果直接在样式表中显式声明了 will-change 属性,则表示目标元素可能会经常变化,浏览器会将优化工作保存得比之前更久。
  • 所以最佳实践是当元素变化之前和之后通过 js 脚本来切换 will-change 的值。除非某个应用会
.sidebar {
  will-change: transform;
}

d、更改完成后要删除 will-change

TIP

浏览器为即将发生的变化所做的优化通常会占用机器的很多资源,通常要删除这些优化尽快恢复到正常行为。

  • 然而,will-change 覆盖了这一行为,它维持优化的时间比浏览器所做的要长很多。
  • 因此,你应该始终记得在元素变化完成后删除will-change,这样浏览器就可以恢复优化所占用的资源。
  • 如果在样式表中声明了will-change,就不可能删除它,这就是为什么建议你用 JavaScript 设置和取消它。
  • 通过 js 脚本,你可以向浏览器声明你的修改,然后在修改完成后,通过监听这些修改完成的时间来删除will-change

如何使用 js 脚本来正确的使用 will-change 属性,如下

点击查看源代码
var el = document.getElementById("element");

// 当鼠标移动到该元素上时给该元素设置 will-change 属性
el.addEventListener("mouseenter", hintBrowser);
// 当 CSS 动画结束后清除 will-change 属性
el.addEventListener("animationEnd", removeHint);

function hintBrowser() {
  // 填写上那些你知道的,会在 CSS 动画中发生改变的 CSS 属性名们
  this.style.willChange = "transform, opacity";
}

function removeHint() {
  this.style.willChange = "auto";
}

will-change 的四个属性

TIP

<custom-ident> 值用于指定你期望改变的一个或多个属性的名称。多个属性用逗号隔开。

will-change: transform opacity;
  • auto并没有特别的意思,除了通常的优化外,浏览器不会设置任何特别的优化。

  • scroll-position:顾名思义,表示你希望在不久的将来随时改变一个元素的滚动位置。

    • 这个值很有用,在使用时浏览器会准备并渲染可滚动元素上滚动窗口中可见内容之外的内容。
    • 浏览器通常只渲染滚动窗口中的内容,以及超过该窗口的部分内容,以平衡因跳过渲染而节省的内存和时间以及使滚动看起来更漂亮。
    • 使用 will-change: scroll-position; 它可以做进一步的渲染优化,从而使更长或更快的内容滚动可以顺利地完成。
  • contents:预计该元素的内容会发生变化。

    • 浏览器通常会随着时间的推移缓存元素的渲染,因为大多数东西并不经常改变,或者只改变它们的位置。
    • 这个值会被浏览器解读为一个信号,即减少对该元素的缓存,或者完全避免对该元素的缓存
    • 因为如果该元素的内容经常变化,那么保持对内容的缓存将是无用且浪费时间的,所以浏览器会直接停止缓存,只要该元素的内容发生变化,就继续从头渲染

⑤ 开启 GPU 硬件加速可能触发的问题:

详细解读

硬件加速操作会创建一个所谓的合成渲染层(compositor layer),并上传到 GPU 进行合成。
然而,强行创造一个图层并不能解决某些页面上的性能瓶颈。

  • 虽然图层创建技术可以提升页面速度,但有一定代价:它们会占用系统 RAM 和 GPU 上的内存(在移动设备上很有限),而且拥有大量的图层会产生不好的影响(尤其是在移动设备上)
  • 所以必须明智地使用它们,确保其可以真正帮助页面性能,而且性能瓶颈不是由你页面上的其他操作造成的。

经过-webkit-transform: transition3d/translateZ 开启 GPU 硬件加速以后,有些时候可能会致使浏览器频繁闪烁或抖动,能够尝试如下办法解决之:

-webkit-backface-visibility: hidden; /* 各种前缀都要考虑,此处省略 */
-webkit-perspective: 1000; /* 各种前缀都要考虑,此处省略 */

# 4、怎么让 Chrome 支持小于 12px 的文字 ?

p {
  font-size: 10px;
  /* 0.8是缩放比例 */
  transform: scale(0.8);
  -webkit-transform: scale(0.8);
}

# 5、CSS3 如何实现 0.5px 的细线 ?

<style>
  .line {
    position: relative;
  }
  .line:after {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 1px;
    background-color: skyblue;
    /* 在Y轴方向上缩放 0.5 */
    transform: scaleY(0.5);
    -webkit-transform: scaleY(0.5);
  }
</style>

# 6、如果需要手动写动画,你认为最小时间间隔是多久,为什么?

答案解析

  • 多数显示器默认频率是60Hz,即 1秒刷新60次
  • 所以理论上最小间隔为 1/60*1000ms = 16.7ms
上次更新时间: 6/8/2023, 9:23:17 PM

大厂最新技术学习分享群

大厂最新技术学习分享群

微信扫一扫进群,获取资料

X