FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
362 stars 39 forks source link

CSS动画之transition #185

Open FrankKai opened 4 years ago

FrankKai commented 4 years ago

css的transition属性其实远远比看起来复杂或者说蕴含着细节。想在工作中更加熟练的运用transition的话,看完这篇博文你就知道了···

不增加transition属性的css属性就不存在”transition“吗?

CSS transitions是提供了一种通过CSS属性控制动画速度的方式。不同于改变属性立刻生效,你可以在一段时间里去完成变化。 例如,如果你想改变元素的颜色,从白变为黑,通常改变是瞬间的。开启了CSS transitions之后,变化发生的时间间隔遵循一个加速度曲线,所有这些都可以定制。

涉及在两种状态之间转换的动画通常被称作隐式转换(implicit transitions),因为在开始和结束状态之间的状态是浏览器定义的。①

注①:这里的隐式动画可以是普通css属性的改变。

image

CSS transition使你决定动画化哪一个属性。(显式地列举出来),当动画开始时(可以设置delay),转化持续多久(可以设置duration),以及transition如何运行(定义一个时间函数,开始线性或者快速,结束慢。)

哪些CSS属性可以被转换呢?

Web作者可以定义哪个属性动画化,以哪种方式动画化。这也就是说可以制作出复杂的转换。因为transition属性对于某些属性不生效,可动画的属性列表有限集。

这个有限集会所规范变化。 auto的行为是复杂的,在不同浏览器可能有不同表现,不建议设置transition的auto属性。

如何定义transitions?

CSS Transitions由缩写属性transition属性控制。这是配置transition的最好方式,因为这样可以避免不同步的参数,调试css时这可能是非常令人沮丧的。

通过以下的子属性,你能控制transition的独立组件:

注意,这些transition无限循环只对我们的例子有用;CSS transition s只能可视化属性从开始到结束的变化。如果你想可视化一个循环,请查看CSS的animation属性。

transition包含哪些属性:一共只有四个。

transition-property

应用transition到的css属性,列出这些属性的一个name或者多个names。只有在这里列举出的属性可以transition;其他属性的改变还是瞬间的。

transition-duration

transition-duration: 1s 指定transition的持续时间。你可以为素有属性指定一个duration,或者为每个属性指定一个属性。

transition-timing-function

transition-timing-function: ease transition-timing-function: linear transition-timing-function: step-end transition-timing-function: steps(4, end) 指定一个函数去定义如何计算属性的中间值。Timing functions决定了transition计算中间值的过程。大多数timing functions可以通过提供提供相应函数的图形来指定,建议另一一个三次贝塞尔的四个点来定义。这里有一个Easing Functions Cheat Sheet

transition-delay

transition-delay: 0.5s 定义了transition隔多久开始执行动画。

缩写属性transition
div {
     transition: <property> <duration><timing-function><delay>
}
简单例子
<h1 id="delay">This is an about page</h1>

#delay {
  font-size: 14px;
  transition-property: font-size;
  // 经过性能分析工具发现,这里的duration使得动画从start->end和end->start都是4秒
  transition-duration: 4s;
  transition-delay: 2s;
  &:hover {
    font-size: 30px;
  }
}

image

transition中断会如何表现? 给定时间内终止悬浮,观察到动画沿着原来的轨迹返回。当再次悬浮上来时,可以接着上一次继续进行动画直到完成动画。

例如在上面的动画中,悬浮时font-size逐渐增大,突然移开鼠标,font-size增长停止,如果2秒内再悬浮上去,可以继续增大,如果2秒内移开,那么会自动缩小到原始尺寸。

多个属性一起动画的例子

首先想一个问题,如何为transition定义多个过渡的动画? 逗号分隔即可,transition: {foo},{bar}

.box {
    border-style: solid;
    border-width: 1px;
    display: block;
    width: 100px;
    height: 100px;
    background-color: #0000FF;
    transition: width 2s,height 2s,background-color 2s,transform 2s;
}
.box:hover {
  background-color: #ffcccc;
  width: 200px;
  height: 200px;
  transform: rotate(180deg);
}

transition属性给元素和伪元素使用效果一样吗?

不一样。 写在元素内部可以实现过渡效果,中断时贝塞尔曲线缓慢回退,而如果写在伪元素内部的话,伪元素活动终止立即终止动画。 transion属性想要实现平滑过渡效果的话,写在元素内部更好,不要写在伪元素内部。

transition定义多个属性的动画时,一定要时间相同吗?

可以不相同。 时间短的先执行完,时间长的后执行完。 互不影响。

transiton定义多个动画时如果4个参数都写上过长怎么办?

可以拆开写。而且可以仅写一次。 拿上面的例子来说。

.box {
    transition-property: width,height,background-color,transform;
    transition-duration: 2s;
    transition-timing-function: ease-in-out;
    transition-delay: 1s;
}

上面的例子会被解析为:

.box {
    transition-property: width,height,background-color,transform;
    transition-duration: 2s,2s,2s,2s;
    transition-timing-function: ease-in-out,ease-in-out,ease-in-out,ease-in-out;
    transition-delay: 1s,1s,1s,1s;
}

上一个问题有没有更加简便的写法?

.box {
    transition: all 2s ease-in-out 1s;
}

如果说所有属性都要增加过渡效果,可以使用all去指代。 但其实如果不是所有属性都加transition动画,部分加也可以使用all,因为只有发生变化的属性才会触发transition动画。

如果所有属性的缓动动画效果要同步,用all是最简洁快捷的。

有没有需要注意的触发transition的情况?

做了上面的事情以后,如果想修改css属性值,触发css属性的transition的话,最好加一个几毫秒的setTimeout 。留几毫秒后再修改,是为了确保DOM的css属性被渲染到CSS树上,从而做到过渡。 否则,其初始状态和结束状态是一样的,因为如果不延时执行的话,状态直接被修改为final状态。

transition结合javascript实现动画路径效果

<template>
    <div id="foo"></div>
</template>

<script>
export default {
  mounted() {
    const f = document.getElementById("foo");
    document.addEventListener(
      "click",
      function(ev) {
        console.log(ev.clientX, ev.clientY);
        f.style.transform = "translateY(" + (ev.clientY - 25) + "px)";
        f.style.transform += "translateX(" + (ev.clientX - 25) + "px)";
      },
      false
    );
  }
};
</script>

<style lang="scss" scoped>
#foo {
  border-radius: 50px;
  width: 50px;
  height: 50px;
  background: #c00;
  position: absolute;
  top: 0;
  left: 0;
  transition: transform 1s; // 这一行代码可以实现小球动画轨迹,一种过渡效果
}
</style>

可以检测到transition的start和finish吗?

可以为发生transition的元素增加事件。

el.addEventListener('transitionrun', (event)=>{
    // event.propertyName 发生transition的css属性名
    // event.elapsedTime transition动画发生的时长
}, true);

如果transition在完成前取消的话,transitionend事件不会触发。因为display既没有变为none,动画的属性也没有发生改变。

参考资料:Using CSS transitions