CSS权威指南第五版-第18章 过渡

CSS 过渡允许属性值在一定时间内平滑变化,而非瞬间完成。过渡属性包括 transition-property, transition-duration, transition-timing-function 和 transition-delay,以及简写属性 transition。通过 transition-property 定义过渡的CSS属性,transition-duration 设置过渡时间,transition-timing-function 控制过渡速度曲线,transition-delay 设置延迟开始。过渡在鼠标悬停、焦点变化等交互时生效,过渡效果会在鼠标离开时反向应用,但持续时间缩短。CSS 中并非所有属性都支持过渡,只有可内插的属性值才能过渡,例如长度、颜色等。过渡事件 transitionend 在过渡结束时触发。" 107095903,9495450,Linux初学者:模拟与修复MBR故障指南,"['Linux系统管理', '系统引导', '硬盘修复', 'GRUB修复', 'Linux故障排查']
摘要由CSDN通过智能技术生成

CSS过渡允许我们对CSS属性进行动画处理,使其随着时间的推移从一个原始值变成一个新的值。这些变化使一个元素从一个状态过渡到另一个状态,以响应某种变化。这通常涉及到用户的交互,但也可能是由于类、ID或其他状态的改变而引起。

通常,当一个CSS属性值发生变化时--当一个样式变化事件发生时,变化瞬间完成。新的属性值在重新绘制页面(或在必要时重排布局再重新绘制)所需的几毫秒内取代了旧的属性。多数情况下,值的变化是瞬间完成的,整个过程不到16毫秒。即使变化的时间比这个长,它仍然是从一个值直接变为下一个值。例如,当在鼠标悬停时改变背景颜色时,背景立即从一种颜色变为另一种颜色,没有渐进的过渡。

18.1 CSS 过渡

CSS过渡提供了一种方法来控制一个属性在一段时间内从一个值到另一个值的变化。因此,我们可以使属性值逐渐变化,自然一些,不那么突兀。例如:

button {color: magenta;
    transition: color 200ms ease-in 50ms;
}
button:hover {color: rebeccapurple;
    transition: color 200ms ease-out 50ms;
}

在这个例子中,该过渡属性并不是在悬停时瞬间改变按钮文本的颜色,而是让按钮文本的颜色在200毫秒内从magenta逐渐淡化到rebeccapurple,而且在开始过渡之前还添加了50毫秒的延迟。

即使在工作中仍然要支持Internet Explorer或其他旧的浏览器,现在也可以使用CSS过渡。当一个浏览器不支持CSS过渡属性时,变化是立即完成,而不是逐渐过渡,对最终结果完全没有影响。如果一个给定的属性或一些属性值不支持动画,同样,变化是立即完成,而不是逐渐过渡。

注意

这里所说的"支持动画",指的是属性可以通过过渡或动画(下一章的主题,第19章)以动画的形式表示值的变化。本书中的属性定义表指出了支持动画的属性。

通常情况下,你会希望瞬间改变值。例如,链接的颜色通常在悬停或聚焦时立即改变,通知视力好的用户正在发生交互,表明悬停或聚焦的内容是一个链接。同样地,在自动补全的列表框中,不能慢慢显现选项,而是希望选项立即显示出来,不能比用户输入的速度慢。立即改变值往往是最好的用户体验。

在其他时候,你会希望一个属性的值更多地逐渐改变,使人们注意到正在发生的事情。例如,你可能想让一个纸牌游戏更加真实,用200毫秒的时间将一张牌的翻转做成动画,因为如果没有动画,用户可能不会意识到发生了什么。(请点击,查看示例)

小贴士

本章中所有的例子都可以在这个页面获取:https://meyerweb.github.io/csstdg4figs/17-transitions/。

再举个例子,你可能想让一些下拉菜单在200毫秒内展开或变得可见(而不是立即出现,这可能会让人感到不协调)。通过过渡,可以使下拉菜单慢慢出现。在图18-1中 (请点击,查看示例), 我们通过缩放变形来过渡对子菜单高度的改变。这是CSS变形的一个常见用途,详情参见本章后文。

图18-1. 过渡初期、过渡中期和最终状态

警告

特别是快速的过渡,尤其是那些在大范围内移动或占据页面主要部分的过渡,有可能导致一些用户的癫痫发作。为了减少或消除这种风险,请使用prefers-reduced-motion media query(见第21章)。始终牢记这些问题,并确保你的设计对癫痫和其他发作性疾病患者的可用性。

18.2 过渡属性

在CSS中,过渡是用四个属性来定义的:transition-property, transition-duration, transition-timing-function和transition-delay。此外,还有个简写属性transition,可一次性声明全部四个属性。

为了创建图18-1中的下拉导航栏,我们使用了所有四个CSS过渡属性,以及一些定义过渡的开始和结束状态的变形属性。下面的代码定义了图18-1中的例子的过渡:

nav li ul {
    transition-property: transform;
    transition-duration: 200ms;
    transition-timing-function: ease-in;
    transition-delay: 50ms;
    transform: scale(1, 0);
    transform-origin: top center;
}
nav li:is(:hover, :focus) ul {
    transform: scale(1, 1);
}

请注意,虽然我们在这个例子中使用了 :hover 和 :focus 的状态来触发样式改变事件,除此之外还可以通过其它方式触发。例如,可以添加或删除类,或以其他方式改变状态,例如,将一个输入框从:invalid改为:valid,或从:checked改为:not(:checked)。或者可以利用:nth-last-of-type 选择器在一个斑马纹表格的末尾追加一行,或者在列表的末尾追加一个列表项。

在图 18-1 所示的场景中,嵌套列表的初始状态是 transform: scale(1, 0) ,而且使用 transform-origin: top center设置了原点。最终状态是 transform: scale(1, 1),而 transform-origin (变形原点)保持不变。(关于变形属性的更多信息,请看第17章。)

在这个例子中,过渡的属性是transform,触发hover事件时,在200毫秒的时段内由旧值transform:scale(1,0)平滑过渡到新值transform:scale(1,1),即嵌套的无序列表放大到默认的原始尺寸。这个过渡在50毫秒的延迟后开始,整个过程是“渐入式”的,这意味着它一开始进行得很慢,然后随着时间的推移而加快速度。

每当目标属性发生变化时,如果在该属性上设置了过渡,浏览器就会应用一个过渡来使变化渐进。

请注意,所有的过渡属性都是为ul元素的非悬停/非聚焦状态上声明。这些状态只被用来改变变形效果,而不是过渡效果。这有一个很好的理由:这意味着悬停/聚焦时目录将下拉打开,而且悬停状态结束后目录还会上拉关闭。

如果像下面这样把过渡相关的属性应用到悬停状态上:        

nav li ul {
    transform: scale(1, 0);
    transform-origin: top center;
}
nav li:is(:hover, :focus) ul {
    transition-property: transform;
    transition-duration: 200ms;
    transition-timing-function: ease-in;
    transition-delay: 50ms;
    transform: scale(1, 1);
}

这意味着当没有悬停或聚焦时,该元素将有默认的过渡值—即瞬时过渡。这意味着我们前面的例子中的菜单会滑动打开,但当交互状态结束时就会立即消失--因为如果不处于交互状态,过渡属性不再应用到元素上。

也许你想要的正是这种效果:即慢慢下拉打开,但是立即消失。如果是这样,那就过渡效果应用到悬停状态上。否则,应该把过渡属性直接应用到元素上,这样,当交互状态进入和退出时都有过渡效果。退出状态时,过渡时序是反过来的。反向过渡是默认行为,如果想覆盖,可以在初始状态和最终状态声明不同的过渡效果。

这里所说的 "初始状态",指的是在页面加载时元素所处的状态。它可以指一个可以得到:focus的内容可编辑元素,就像下面这样:(请点击,查看示例)

/* 匹配元素所有状态的选择器 */
p[contenteditable] {
    background-color: rgba(0, 0, 0, 0);
}
/* 匹配元素部分状态的选择器 */
p[contenteditable]:focus {
    /* 覆盖声明 */
    background-color: rgba(0, 0, 0, 0.1);
}

在这个例子中,完全透明的背景始终是初始状态,只有在用户让元素获得焦点时才会改变。这就是我们在本章中所说的初始状态或默认值的意思。在选择器中包含的过渡属性一直与元素相匹配,只要状态发生变化就会影响到该元素,无论是从初始状态到最终状态(在前面的例子中是获得焦点)。

初始状态也可以是一个可变的临时状态,比如复选框的:checked或表单控件的:valid,或者类的增删:

/* 匹配元素部分状态的选择器 */
input:valid {
    border-color: green;
}
/* 前一个选择器不匹配时,匹配元素部分状态的选择器 */
input:invalid {
    border-color: red;
}
/* 匹配元素部分状态的选择器,不管输入框中的内容是否有效 */
input:focus {
    /* alternative declaration */
    border-color: yellow;
}

在这个例子中, :valid 或 :invalid 选择器可以匹配任何给定的元素,但不能同时匹配。:focus选择器,如图18-2所示,匹配任何情况下获得焦点的输入框,就会匹配,不管这个输入是否同时匹配:valid或:invalid选择器。

在这种情况下,当我们提到初始状态时,我们指的是初始值,它可能是:valid ,也可能是 :invalid。对于一个给定的元素,改变后的状态与初始的 :valid 或 :invalid 状态相反。(请点击,查看示例)

​图18-2. 输入框在有效、无效和获得焦点状态下的外观

记住,你可以对初始状态和最终状态应用不同的过渡值,但是进入某一状态时一定会使用当前状态定义的值。以下面的代码为例,过渡被设置为让菜单在2秒内下拉打开菜单,但是上拉关闭只用200毫秒:

nav li ul {
    transition-property: transform;
    transition-duration: 200ms;
    transition-timing-function: ease-in;
    transition-delay: 50ms;
    transform: scale(1, 0);
    transform-origin: top center;
}
nav li:is(:hover, :focus) ul {
    transition-property: transform;
    transition-duration: 2s;
    transition-timing-function: linear;
    transition-delay: 1s;
    transform: scale(1, 1);
}

这样的用户体验非常糟糕,但它说明了一个问题。 当悬停或聚焦时,打开导航需要整整2秒。当关闭时,短短0.2秒就结束了。当列表项被悬停或聚焦时,最终状态中定义的过渡属性就会生效。因此,为这些状态定义的transition-duration: 2s生效。当一个菜单不再被悬停或聚焦时,它返回到默认的缩小状态,使用的是初始状态(nav li ul选择器)定义的的过渡属性,导致菜单耗时200毫秒关闭。

再仔细看看这个例子,特别是默认状态下的过渡样式。当用户停止在父级导航元素或作为子元素的下拉菜单上悬停或聚焦时,下拉菜单会延迟50毫秒才开始200毫秒的过渡。这其实是一种合宜的用户体验,因为它给了用户一个机会(无论多么短暂),把鼠标再移到菜单上。

虽然这四个过渡属性可以单独声明,但是更常用使用简写属性。我们先讨论一下各个单独属性,这样你就能很好地理解每个属性的作用了。

18.2.1 通过属性限制过渡效果

transition-property属性指定了你想要过渡的CSS属性的名称。这允许你将过渡效果限制在某些属性上,而让其他属性值的变化瞬时完成。

TRANSITION-PROPERTY

取值

none | [ all | <property-name> ]#

初始值

all

适用于

所有元素,以及:before和:after伪元素

计算值

指定的值

继承性

动画性

transition-property的值是一个用逗号分隔的属性列表;如果你不希望任何属性被过渡,可以使用关键字none;或者使用默认的all,这意味着 "过渡所有支持动画的属性"。你也可以在一个逗号分隔的属性列表中包括关键字all。

如果你把all作为唯一的关键词,或者默认为all,那么所有支持动画的属性都将一起过渡。比方说,你想在悬停时改变一个框体的外观:

div {
    color: #ff0000;
    border: 1px solid #00ff00;
    border-radius: 0;
    transform: scale(1) rotate(0deg);
    opacity: 1;
    box-shadow: 3px 3px rgba(0, 0, 0, 0.1);
    width: 50px;
    padding: 100px;
}
div:hover {
    color: #000000;
    border: 5px dashed #000000;
    border-radius: 50%;
    transform: scale(2) rotate(-10deg);
    opacity: 0.5;
    box-shadow: -3px -3px rgba(255, 0, 0, 0.5);
    width: 100px;
    padding: 20px;
}

当鼠标指针在 div 上悬停时,在初始状态与悬停(最终)状态下具有不同值的每个属性都将改变为悬停状态的值。transition-property属性用于定义哪些属性的变化以动画形式持续一段时间(而不是瞬间变化)。所有属性都将从默认值变为悬停状态下的值,但只有包含在transition-property列出的支持动画的属性在指定的持续时间内逐渐过渡。像border-style这样的不支持动画的属性会立即从一个值变为另一个值。

如果all是transition-property的唯一值或在逗号分隔的值中的最后一个值,那么所有的支持动画属性将一起过渡。否则,提供一个逗号分隔的列表,列出要受过渡属性影响的属性。

因此,如果想过渡所有的属性,下面的语句几乎是等同的:

div {
    color: #ff0000;
    border: 1px solid #00ff00;
    border-radius: 0;
    opacity: 1;
    width: 50px;
    padding: 100px;
    transition-property: color, border, border-radius, opacity,
        width, padding;
    transition-duration: 1s;
}
div {
    color: #ff0000;
    border: 1px solid #00ff00;
    border-radius: 0;
    opacity: 1;
    width: 50px;
    padding: 100px;
    transition-property: all;
    transition-duration: 1s;
}

两个语句中声明的transition-property属性都会过渡所有列出的属性--但前者只过渡可能发生变化的六个属性。

后者规则中的transition-property: all确保了由样式变化事件导致值有变化的所有支持动画的属性,不管属性的值在哪个CSS规则块中发生变化,都会在一秒钟内过渡。这个过渡适用于选择器所匹配的所有元素的支持动画属性,而不仅仅是与all相同的样式块中所声明的属性。

在这种情况下,第一个版本将过渡限制在所列的六个属性上,不过这样能精确控制过渡哪个属性。单独声明各个属性让我们为每个属性的过渡提供不同的速度、延迟和/或持续时间:

 
div {
    color: #ff0000;
    border: 1px solid #0f0;
    border-radius: 0;
    opacity: 1;
    width: 50px;
    padding: 100px;
}
.foo {
    color: #00ff00;
    transition-property: color, border, border-radius, opacity,
        width, padding;
    transition-duration: 1s;
}

<div class="foo">Hello</div>

如果你想单独定义每个属性的过渡效果,就把它们全部写出来,用逗号把每个属性分开。如果你想用相同的持续时间、延迟和节奏,除了少数属性例外,可以先使用all,然后再为例外的属性单独定义时间、速度或节奏。只要确保使用all作为第一个值,否则all之前的属性将被all覆盖:

div {
    color: #f00;
    border: 1px solid #00ff00;
    border-radius: 0;
    opacity: 1;
    width: 50px;
    padding: 100px;
    transition-property: all, border-radius, opacity;
    transition-duration: 1s, 2s, 3s;
}

在这组逗号分隔的值中,all表示样式规则中列出的所有属性,以及继承的所有CSS属性,还有其他匹配该元素或由该元素继承的其它CSS规则块中的全部属性。

在前面的例子中,所有获得新值的属性都将以相同的持续时间、延迟和时序函数进行过渡,不过单独声明的border-radius和opacity除外。这两个属性在all后面单独列出,所以我们可以把它们和其他属性以相同的时间、延迟和时序函数过渡,或者我们可以为这两个属性提供不同的时间、延迟和时序函数。在这个例子中,除了border-radius和opacity之外的所有属性,过渡的持续时间为1秒,而border-radius属性的持续时间为2秒,opacity属性的持续时间为3秒。(transition-duration将在下一节介绍)。

18.2.1.1禁用过渡效果

虽然默认情况下没有过渡效果,但如果设置了过渡,而后又想在特定的情况下撤销过渡效果,你可以设置transition-property: none来覆盖整个过渡声明,禁用所有属性的过渡效果。

none关键字只能作为该属性的唯一值使用--你不能把它作为逗号分隔的属性列表的一部分。如果想撤销部分属性的过渡效果,只能列出仍然想过渡的属性。transition-property 属性不能排除不想过渡的属性,只能涵盖想过渡的属性。

注意

另一种方法是将该属性的延迟和持续时间设置为0s。这样它就会瞬间显现,就像没有对它应用CSS过渡一样。

18.2.1.2过渡事件

在DOM中,有四个与过渡有关的事件:transitionstart、transitionrun、transitionend和transitioncancel。我们将集中讨论transitionend,因为它是可以被一个单一的CSS触发多次的事件。

无论哪个方向过渡,每个属性在任何时间内或任何延迟后被过渡,过渡结束后都会触发transitionend事件。无论该属性是单独声明还是作为all声明的一部分,这都会发生。对于一些看似简单的属性声明,却会触发多个transitionend事件,因为简写属性中的每个支持动画的属性都会有自己的transitionend事件。以下述样式为例:

 
div {
    color: #f00;
    border: 1px solid #00ff00;
    border-radius: 0;
    opacity: 1;
    width: 50px;
    padding: 100px;
    transition-property: all, border-radius, opacity;
    transition-duration: 1s, 2s, 3s;
}

当过渡结束时,将有远远超过6个transitionend事件。例如,仅border-radius过渡就产生了四个transitionend事件,分别为:

  • border-bottom-left-radius

  • border-bottom-right-radius

  • border-top-right-radius

  • border-top-left-radius

padding属性也是4个独立属性的简写方式:

  • padding-top

  • padding-right

  • padding-bottom

  • padding-left

border属性产生8个transitionend事件:border-width简写属性对应4次,以及border-color简写属性又对应4次:

  • border-left-width

  • border-right-width

  • border-top-width

  • border-bottom-width

  • border-top-color

  • border-left-color

  • border-right-color

  • border-bottom-color

然而,border-style属性没有transitionend事件,因为border-style不是一个支持动画的属性。

这里,将有19次transitionend事件,其中列出了这六个特定的属性,因为这六个属性包括几个简写属性,在过渡前和过渡后的状态下有不同的值。在all情况下,至少会有19个transitionend事件:前后状态涵盖的6个属性中每个独立的属性触发一次,此外可能还有继承或在影响该元素的其它样式块中声明的属性:(请点击,查看示例)

transitionend事件可以像这样监听:

document.querySelector('div').addEventListener('transitionend',
    function (e) {
      console.log(e.propertyName);
});

transitionend事件有三个与该事件有关的属性:

  1. propertyName:这是刚刚完成过渡的CSS属性的名称。

  2. pseudoElement:这是发生过渡的伪元素,前面有两个冒号;如果过渡效果应用到常规的DOM节点上,返回空字符串。

  3. elapsedTime:过渡持续的时间,以秒为单位;返回的值通常是transition-duration属性中声明的时间。

transitionend事件只在属性成功过渡到新值时发生。如果过渡被中断了,例如在其它地方被同一元素上的同一属性的另一个变化打断,则过渡事件不会发生。

如果属性返回初始值,又触发一次transitionend事件。这次事件在过渡开始时就触发,即使原方向的过渡还未结束。

18.2.2 设置过渡持续时间

transition-duration属性将一个以逗号分隔的时间长度列表作为其值,单位为秒(s)或毫秒(ms)。这些时间值描述了从一个状态过渡到另一个状态所需的时间。

TRANSITION-DURATION

取值

<time>#

初始值

0s

适用于

所有属性,以及 :before 和:after 伪元素

计算值

指定的值

继承性

动画性

当在两个状态之间过渡时,如果只为其中一个状态声明了持续时间,那么这个持续时间只在向那个状态过渡时起作用。请看下面两个样式规则:

input:invalid {
    transition-duration: 1s;
    background-color: red;
}
input:valid {
    transition-duration: 0.2s;
    background-color: green;
}

因此,当输入变得无效时,需要一秒钟的时间变为红色背景,而当输入变得有效时,只需要200毫秒就可以过渡到绿色背景。(请点击,查看示例)

transition-duration属性的值是一个正值,单位是秒(s)或毫秒(ms)。规范要求必须带时间单位,就算要设为零秒,也要写成0s。默认情况下,属性从一个值瞬间变为下一个值,看不到动画效果,因此过渡持续时间的默认值是0s。

如果transition-delay属性的值不是正值,而且没有声明transition-duration,那么声明的transition-property不起作用,即不触发transitionend事件。只要一个过渡的总持续时间大于0秒--这可能发生在持续时间为0s或transition-duration被省略从而默认为0s的情况下--过渡仍将被应用,并且当过渡结束时将发生一个transitionend事件。

transition-duration的值不能为负,如果transition-duration列表中有一个是负值,将使整个transition-duration的声明无效。

以前面那个超长的transition-property声明为例,我们可以为所有属性声明一个统一的持续时间,也可以单独为各个属性声明不同的持续时间,还可以为余下的属性使用相同的持续时间。如果想让全部属性使用相同的持续时间,设置过渡时只要声明一个transition-duration值:

div {
    color: #ff0000;
    …
    transition-property: color, border, border-radius, opacity,
        width, padding;
    transition-duration: 200ms;
}

我们也可以为transition-duration属性值声明一组逗号分隔的时间值,与transition-property属性值中所列的CSS属性的数量相同。如果我们想让每个属性在不同的时间长度内过渡,要在一组以逗号分隔的值中设置不同的时长:

div {
    color: #ff0000;
    …
    transition-property: color, border, border-radius, opacity,
        width, padding;
    transition-duration: 200ms, 180ms, 160ms, 120ms, 1s, 2s;
}

如果声明的属性数量与声明的持续时间数量不一致,根据各浏览器指定的规则处理。如果持续时间多于属性,那么额外的持续时间将被忽略。如果属性多于持续时间,则重复使用前面的持续时间。在下面的例子中,color、border-radius和width的持续时间为100毫秒;border、opacity和padding将被设置为200毫秒

div {
    …
    transition-property: color, border, border-radius, opacity,
        width, padding;
    transition-duration: 100ms, 200ms;
}

如果我们正好声明了两个以逗号分隔的持续时间,那么每个奇数位上的属性使用第一个持续时间,而每个偶数位上的属性都将使用第二个持续时间。

小贴士

永远记住,用户体验是很重要的。如果过渡太慢,网站就会显得缓慢或反应迟钝,使人们不愿意关注本应是微妙的效果。如果一个过渡太快,用户可能察觉不到。视觉效果应该持续足够长的时间,但不要太长,以免使自己成为注意力的中心。一般来说,创造一个可见但不分散注意力的过渡的最佳时间范围是100到300毫秒。

18.2.3 调整过渡的内部时序

你想让你的过渡开始时很慢,然后变快;或者开始时很快,结束时很慢;又或者以平缓的速度前进,然后步进甚至弹跳数次?transition-timing-function提供了一种控制过渡节奏的方法。

TRANSITION-TIMING-FUNCTION

取值

<timing-function>#

初始值

ease

适用于

所有元素,以及:before 和:after 伪元素

计算值

指定的值

继承性

动画性

transition-timing-function的值包括ease、linear、ease-in、ease-out、ease-in-out、step-start、step-end、step(n, start)--其中n是步骤数--step(n, end),以及cubic-bezier(x1, y1, x2, y2)。(这些值也是animation-timing-function属性的有效值,在第19章有详细的描述)。

非步骤关键字是渐进时序函数,是描述平滑曲线的立方贝塞尔数学函数的别名。该规范提供了五个预定义的渐进函数,如表18-1所示。

表18-1. 立体贝塞尔时序函数支持的关键字

时序函数

说明

立方贝塞尔值

cubic-bezier()

指定一个立方贝塞尔曲线

cubic-bezier(x1, y1, x2, y2)

ease

慢速开始,然后加速,再慢下来,结束时特别慢

cubic-bezier(0.25, 0.1, 0.25, 1)

linear

整个过渡过程保持相同的速度

cubic-bezier(0, 0, 1, 1)

ease-in

慢速开始,然后加速

cubic-bezier(0.42, 0, 1, 1)

ease-out

快速开始,然后减速

cubic-bezier(0, 0, 0.58, 1)

ease-in-out

与ease类似;中间较快,两端很慢,但不同速

cubic-bezier(0.42, 0, 0.58, 1)

立体贝塞尔曲线函数接受四个数字参数。表18-1中列出的五个具名渐进函数对应的曲线如图18-3所示。例如,linear等同于cubic-bezier(0, 0, 1, 1)。第一个和第三个立方贝塞尔函数参数值需要在0和+1之间。

图18-3. 命名的立方贝塞尔函数的曲线表示方法

cubic-bezier()函数中的四个数字定义了一个方框中两个手柄的x和y坐标。这些手柄是从方框的左下角和右上角延伸出来的两条直线的末端。曲线使用这两个角和两个手柄的坐标,通过贝塞尔函数计算得出。

为了了解这个工作原理,请看一下曲线和它们的对应值,如图18-4所示。

图18-4. 四条贝塞尔曲线及它们的cubic-bezier()值(出自http://cubic-bezier.com)。

先看第一个例子。前两个值对应于x1和y1,分别为0.5和1。这两个值确定第一个手柄的位置,即横向走一半(x1=0.5),纵向走到方框的顶边(y1=1)。x2,y2坐标的值为0.5,0,对应的点在方框底边的中点,第二个手柄就在这个位置。曲线就由这两个手柄的位置确定。

在第二个例子中,手柄的位置被对调了,因此曲线也发生了变化。同理,第三和第四个例子也是如此,它们的位置是相互颠倒的。请注意,当切换手柄位置时,产生的曲线是不同的。

预定义的关键字是相当有限的。若想自由控制动画,使用一个有四个浮点数的立方贝塞尔函数来代替预定义的关键字。如果你能熟练应用微积分,或者经常使用Freehand或Illustrator等程序,也许能在脑中想出立方贝塞尔函数;否则,有一些在线工具,比如http://cubic-bezier.com/,自己尝试不同的值。

如图18-5所示,网站http://easings.net,提供了许多额外的立方贝塞尔函数值,你可以用它来实现令人愉悦的动画。

​图18-5.作者定义的有用的立方贝塞尔函数(来自http://easings.net)

该网站的作者为这些动画命名,但前面的名称并不是CSS规范的一部分,必须写成如下:

非官方名称

立方贝塞尔函数值

easeInSine

cubic-bezier(0.47, 0, 0.745, 0.715)

easeOutSine

cubic-bezier(0.39, 0.575, 0.565, 1)

easeInOutSine

cubic-bezier(0.445, 0.05, 0.55, 0.95)

easeInQuad

cubic-bezier(0.55, 0.085, 0.68, 0.53)

easeOutQuad

cubic-bezier(0.25, 0.46, 0.45, 0.94)

easeInOutQuad

cubic-bezier(0.455, 0.03, 0.515, 0.955)

easeInCubic

cubic-bezier(0.55, 0.055, 0.675, 0.19)

easeOutCubic

cubic-bezier(0.215, 0.61, 0.355, 1)

easeInOutCubic

cubic-bezier(0.645, 0.045, 0.355, 1)

easeInQuart

cubic-bezier(0.895, 0.03, 0.685, 0.22)

easeOutQuart

cubic-bezier(0.165, 0.84, 0.44, 1)

easeInOutQuart

cubic-bezier(0.77, 0, 0.175, 1)

easeInQuint

cubic-bezier(0.755, 0.05, 0.855, 0.06)

easeOutQuint

cubic-bezier(0.23, 1, 0.32, 1)

easeInOutQuint

cubic-bezier(0.86, 0, 0.07, 1)

easeInExpo

cubic-bezier(0.95, 0.05, 0.795, 0.035)

easeOutExpo

cubic-bezier(0.19, 1, 0.22, 1)

easeInOutExpo

cubic-bezier(1, 0, 0, 1)

easeInCirc

cubic-bezier(0.6, 0.04, 0.98, 0.335)

easeOutCirc

cubic-bezier(0.075, 0.82, 0.165, 1)

easeInOutCirc

cubic-bezier(0.785, 0.135, 0.15, 0.86)

easeInBack

cubic-bezier(0.6, -0.28, 0.735, 0.045)

easeOutBack

cubic-bezier(0.175, 0.885, 0.32, 1.275)

easeInOutBack

cubic-bezier(0.68, -0.55, 0.265, 1.55)

18.2.3.1 步进时序

此外,还可以使用步进时序函数。规范预定义了四个步进值:

时序函数

定义

steps(<integer>, jump-start)

显示n个固定镜头,其中最后一个固定镜头占整个过渡的最后百分之n。 start可以用来代替jump-start。

steps(<integer>, jump-end)

显示n个关键帧,在过渡持续时间的前百分之n时间停留在初始状态。这意味着最后一次跳转发生在过渡的最后。可以用end代替jump-end。

steps(<integer>, jump-both)

显示n个关键帧,从立即跳转开始,在过渡持续时间的最末端进行最后的跳转。这实际上是给过渡添加了一个步骤。

steps(<integer>, jump-none)

显示n个关键帧,但在过渡持续时间的开始或结束时都没有跳转,而是在前百分之n的时间内停留在初始值上,在最后百分之n的时间内显示最终值。这就有效地减少了过渡期的一个步骤。

step-start

在整个过渡期间保持在最后的关键帧上。等于step(1, jump-start)。

step-end

在整个过渡时间内保持在初始关键帧上。等于step(1, jump-end)。

如图18-6所示,步进函数以步进方式显示从初始值到最终值的转变过程,而不是平滑曲线。

​图18-6. 步进时序函数

步进函数允许你通过定义步进的次数和方向,将过渡划分为等距离的步进。方向有两个:start和end。使用start时,第一步在动画的开头;使用end时,最后一步在动画的末尾。例如,step(5, jump-end)等距跳跃五步,时间点分别为0%、20%、40%、60%和80%;而step(5, jump-start)等距跳跃的时间点分别为20%、40%、60%、80%和100%。

step-start函数与step(1, jump-start)相同。当使用这个函数时,过渡的属性值从一开始便处于最终值状态。step-end函数与step(1, jump-end)相同,它把过渡的属性设为初始值,在过渡持续的整个时间段内都保持这个值。

注意

第19章将深入讨论步进时序,特别是start和end的确切含义。

继续使用我们之前使用过的超长的transition-property声明,我们可以为所有的属性声明统一的时序函数,或者单独为各属性声明不同的时序函数,等等。下面的样式规则为所有过渡的属性设置统一的时序函数:

div {
    transition-property: color, border-width, border-color, border-radius,
        opacity, width, padding;
    transition-duration: 200ms;
    transition-timing-function: ease-in;
}

谨记,transition-timing-function并不改变属性的过渡时间:那是由transition-duration属性设置的。transition-timing-function只控制设定的时段内过渡的行进节奏。请看下面的样式:

div {
    …
    transition-property: color, border-width, border-color, border-radius,
        opacity, width, padding;
    transition-duration: 200ms;
    transition-timing-function: ease-in, ease-out, ease-in-out,
        step-end, step-start, steps(5, jump-start), steps(3, jump-end);
}

这里,我们为七个不同的属性设置了七个不同的时序函数,只要它们有相同的过渡时间和延迟,所有的属性都是在同一时间开始和完成过渡的。(顺便说一下,前面的过渡将是一个糟糕的用户体验。请不要那样做)。

为了找到最合适的效果,最好的方法是逐个试验不同的时序函数。在测试时,把transition-duration的值设大一些,以便更好地观察各种函数之间的差异。(请点击,查看示例) 如果速度太快,你可能无法分辨不同渐进函数之间的区别。只要别忘了在发布结果前把过渡时间调回较快的速度就可以了!

18.2.4 延迟过渡

transition-delay属性在元素上发生触发过渡的变化与开始过渡之间引入一定的延迟。

TRANSITION-DELAY

取值

<time>#

初始值

0s

适用于

所有属性, :before 和:after 伪元素

计算值

指定的值

继承性

动画性

transition-delay设为 0s(默认值)表示过渡将立即开始;也就是说,一旦元素的状态发生变化,过渡开始执行。例如,这一点从a:hover的即时变化效果中可以看出。

如果transition-delay的<time>值不是0s,定义了从属性值开始变化的那一刻(此时还未应用transition 或 transition-property)到transition 或 transition-property声明的属性开始以动画形式变为最终值之间的时间间隔。

有趣的是,<time>值可以为负。负值的效果将在 "负数延迟值 "一节中描述。

还以前面声明了6个(或19个)属性的transition-property声明为例,我们可以通过省略transition-delay属性,或将其设为0s值,使所有的属性立即开始过渡。另一种可能是立即开始一半属性的过渡,其余的属性在200毫秒后开始,如下所示:

div {
    transition-property: color, border, border-radius, opacity,
        width, padding;
    transition-duration: 200ms;
    transition-timing-function: linear;
    transition-delay: 0s, 200ms;
}

这里,我们把 transition-delay:0s, 200ms应用到一系列属性上,而且每个属性的过渡效果持续200毫秒。在这组过渡的属性中,color, border-radius和 width立即开始过渡。余下的属性设置的transition-delay等于应用于全部过渡属性的transition-duration。

与transition-duration和transition-timing-function一样,如果transition-delay列出的值(以逗号分隔)比transition-property列出的值(以逗号分隔)多,多出的延迟值被忽略。而如果transition-property列出的值(以逗号分隔)比transition-delay列出的值(以逗号分隔)多,将重复使用延迟值。

我们甚至可以声明七个不同的transition-delay值,使每个属性在前一个属性过渡后开始过渡,如下所示:

div {
    …
    transition-property: color, border-width, border-color, border-radius,
        opacity, width, padding;
    transition-duration: 200ms;
    transition-timing-function: linear;
    transition-delay: 0s, 0.2s, 0.4s, 0.6s, 0.8s, 1s, 1.2s;
}

在这个例子中,我们用 transition-duration 属性声明每个过渡持续 200 毫秒。然后我们声明一个transition-delay,为每个属性提供逗号分隔的延迟值,以200毫秒或0.2秒递增,与每个属性的过渡持续时间相同。最终的结果是,每个属性在前一个属性完成后开始过渡。

我们可以用数学方法给每个过渡属性不同的持续时间和延迟,确保它们都在同一时间完成过渡:

div {
    …
    transition-property: color, border-width, border-color, border-radius,
        opacity, width, padding;
    transition-duration: 1.4s, 1.2s, 1s, 0.8s, 0.6s, 0.4s, 0.2s;
    transition-timing-function: linear;
    transition-delay: 0s, 0.2s, 0.4s, 0.6s, 0.8s, 1s, 1.2s;
}

在这个例子中,每个属性都在1.4秒处完成过渡,但每个属性的持续时间和延迟都不同。对于每个属性,transition-duration值加上transition-delay值必须等于1.4秒。

通常,我们希望所有的过渡在同一时间开始。此时,只需为transition-delay属性提供一个值,这个值会被应用到所有的属性上。在图18-1所示的下拉菜单中,我们设置了一个50毫秒的延迟。这个延迟值不太长,不会引起用户的注意,也不会导致应用程序看起来很慢。在某种程度上,50毫秒的延迟能防止导航菜单意外展开,例如用户把鼠标从页面的一部分移到另一部分的过程中可能会不小心经过或悬停在菜单项上。

18.2.5 负的延迟值

如果transition-delay的值为负数,而且绝对值小于transition-duration的值,从中间某个位置立即开始过渡。比如说:(请点击,查看示例)

div {
  transform: translateX(0);
  transition-property: transform;
  transition-duration: 200ms;
  transition-delay: -150ms;
  transition-timing-function: linear;
}
div:hover {
  transform: translateX(200px);
}

这里,我们把transition-delay的值设为-150毫秒,而过渡持续200毫秒,那么过渡将在四分之三处开始,并将持续50毫秒。对本例中的线性时序函数而言,DIV在悬停时立即沿X轴平移150像素,然后在50毫秒的时间范围内慢慢从150像素平移到200像素处。

如果transition-delay的值为负数,但是绝对值大于或等于transition-duration的值,那么属性值的变化是立即的,就像没有应用过渡一样,并且没有transitionend事件发生。

当从悬停状态过渡回到原始状态时,默认情况下,还应用相同的transition-delay值。在上述示例中,由于在悬停状态下没有覆盖transition-delay,因此元素将瞬间平移到整个过渡的四分之三处(即正向过渡的四分之一处),然后慢慢平移到原始状态。鼠标移开后,元素在x轴跳到50像素处,然后用50毫秒的时间返回原位置,即沿x轴平移0像素。

18.2.6简写属性

transition简写属性将到目前为止所涉及的四个属性--transition-property, transition-duration, transition-timing-function,和 transition-delay—合而为一。

TRANSITION

取值

[ [ none | <transition-property> ] ‖ <time> ‖ <transition-timing-function> ‖ <time> ]#

初始值

all 0s ease 0s

适用于

所有属性,以及 :before 和:after 伪元素

计算值

指定的值

继承性

动画性

transition属性的值可以是none,或任何数量的以逗号分隔的单次过渡列表。单次过渡包含:应用过渡效果的一个属性,或者关键字all来过渡所有的属性;过渡的持续时间;时序函数;和过渡延迟。

如果transition简写属性中的单次过渡没有声明要过渡的属性,那么此次过渡默认为all。如果没有声明transition-timing-function值,它将默认为ease。如果只包含一个时间值,那将是持续时间,而没有延迟,就像transition-delay被设置为0s一样。

在每个单次过渡中,持续时间与延迟值的顺序很重要:第一个可以被解析为时间的值将被设置为持续时间。如果在逗号之前或语句末尾还有时间值,那就是延迟。

下面是编写相同过渡效果的三种等效方法:

nav li ul {
    transition: transform 200ms ease-in 50ms,
                  opacity 200ms ease-in 50ms;
}
nav li ul {
    transition: all 200ms ease-in 50ms;
}
nav li ul {
    transition: 200ms ease-in 50ms;
}

在第一个例子中,我们用简写形式为两个属性定义过渡效果。因为我们要过渡所有被改变的属性,我们可以使用关键字all,如第二个例子所示。而且,由于all是默认值,我们可以在简写形式中只提供持续时间、时序函数和延迟。如果时序函数是ease而不是ease-in,还可以省略时序函数,因为ease是默认值。如果我们不想要延迟,我们可以省略第二个时间值,因为0s是默认值。

持续时间必须设定,否则就看不到任何过渡。换句话说,transition属性中唯有transition-duration部分是真正必须的。

如果只想延迟从关闭菜单到打开菜单的变化,而不进行逐渐变化过渡,我们仍然需要包含一个0s的持续时间。记住,第一个可解析为时间的值将被设置为持续时间,而第二个值将被设置为延迟:

nav li ul {
  transition: 0s 200ms;
}

警告

这个过渡将等待200毫秒,然后显示完全打开和不透明的下拉菜单,没有逐渐变化的过渡。这是很糟糕的用户体验,所以请不要这样做。

如果有一个以逗号分隔的过渡列表(而不是只有一个过渡),并且包含none这个值,整个过渡声明是无效的,从而被忽略。

div {
    transition-property: color, border-width, border-color, border-radius,
        opacity, width, padding;
    transition-duration: 200ms, 180ms, 160ms, 140ms, 100ms, 2s, 3s;
    transition-timing-function: ease, ease-in, ease-out, ease-in-out,
        step-end, steps(5, start), steps(3, end);
    transition-delay: 0s, 0.2s, 0.4s, 0.6s, 0.8s, 1s, 1.2s;
}
div {
    transition:
        color 200ms ease,
        border-width 180ms ease-in 200ms,
        border-color 160ms ease-out 400ms,
        border-radius 140ms ease-in-out 600ms,
        opacity 100ms step-end 0.8s,
        width 2s steps(5, start) 1s,
        padding 3s steps(3, end) 1.2s;
}

前面的两个CSS规则块在功能上是等同的:可以使用四个单独的属性分别声明,也可以在简写属性中声明一组以逗号分隔的多个过渡。但是,两种写法不能混在一起:transition: color, opacity 200ms easy-in 50ms将在50毫秒的延迟后在200毫秒内渐进方式改变不透明度,但颜色的变化将是瞬间的,没有transitionend事件。

18.3 逆转中断的过渡

当一个过渡还未结束却被打断了(比如下拉菜单未完全打开之前鼠标移开了),属性值被重置为过渡开始之前的值,而且这个过程也有过渡效果。因为在逆转的部分,过渡时将重复使用持续时间和时序函数,而这会导致奇怪甚至糟糕的用户体验,所以CSS过渡规范规定,逆转的过渡持续的时间较短。

在下拉菜单示例中,在默认状态中设置了50毫秒的transition-delay,而在悬停状态上没有声明过渡相关的属性;因此,浏览器在开始逆转(或结束)过渡之前会等待50毫秒。

如果正向动画完成,过渡到最终值并且触发了transitionend事件;逆转时所有的浏览器都将复用transition-delay值。假设用户在该菜单开始过渡的75毫秒后移开。这意味着该下拉菜单将未完全打开和完全不透明就要慢慢关闭。浏览器在关闭菜单之前应该有50毫秒的延迟,就像它在开始打开菜单之前等待了50毫秒一样。这实际上是一个很好的用户体验,因为它在关闭前提供了几毫秒的延迟,防止在用户不小心离开导航菜单。

在步进时序函数的例子中,如果有个耗时10秒,有10个步骤的过渡,在3.25秒后开始逆转,那么正向过渡停止在第三和第四个步骤之间的四分之一处(完成了3个步骤,即过渡的30%),因此逆转时将耗时3秒。在下面的例子中,我们的div的宽度将增长到130像素宽,然后在鼠标移开时开始恢复到100像素宽:

div {
    width: 100px;
    transition: width 10s steps(10, jump-start);
}
div:hover {
    width: 200px;
}

虽然逆转的持续时间将被四舍五入为已完成的最大步骤所需的时间,但逆转的整个过程仍将被最初声明的步骤数分割,而不是已完成的步骤数。上述示例在3.25秒处中断,因此逆转时将在3秒钟内完成10步。逆转时每一步的持续时间将缩短,每个步骤为300毫秒,而且每个步骤将宽度缩小3个像素,而不是10个像素。

如果时序函数是线性的,那么在两个方向上的持续时间将是相同的。所有其他的cubic-bezier函数,持续时间与中断前已完成的进程成正比。如果transition-delay为负值,延迟也按比例减少。延迟为正值的话,两个方向则保持不变。

任何浏览器都不会在悬停状态触发transitionend事件,因为过渡根本没有结束;但当反向过渡把菜单完全折叠起来后,在所有浏览器都会都会触发transitionend事件。该反向过渡的elapsedTime值取决于浏览器是在200毫秒内关闭菜单,还是用部分打开菜单所用的时间关闭菜单。

要覆盖这些值,在初始和最终状态中都包含过渡属性(例如,未悬停和悬停的样式)。这对逆向缩减机制虽然没有影响,但是却能进一步控制。

警告

祖辈元素和后代元素上都有过渡效果时要小心。过渡的属性发生变化后立即过渡祖辈或后代节点可能导致意料之外的结果。如果后代元素的过渡效果在祖辈元素的过渡效果之前结束,后代元素将继续过渡,所用的值(仍在过渡中)继承自父元素。这可能不是你想要的效果。

18.4 支持动画的属性和值

在实现过渡和动画之前,重要的是要了解并非所有的属性都支持动画。支持动画的CSS属性均可应用过渡(或动画)效果。那么,哪些属性支持动画呢?

判断属性是否支持动画的关键是确定其取值能否内插。插值指在两个数据点之间插入一个数据点。判断属性的值是否支持动画的关键准则是计算值能否内插。如果属性的计算值是关键字,不能内插;如果关键字能计算为某种数值,则能内插。简单而言,如果能找到属性的两个值的中间点,那么属性的值可能就支持动画。

例如,display属性的block和inline-block值并不是数字,因此没有中间点,从而不支持动画。transform属性的rotate(10deg)和rotate(20deg)值有中点,是rotate(15deg);因此支持动画。

border属性是border-style、border-width和border-color的简写(它们本身也是四个边属性的简写)。虽然border-style属性的值没有中点,但border-width属性的长度单位值是数值,所以支持动画。medium、thick和thin等关键字值都有数字对应(border-width属性把关键字计算为长度),因此这些值是可内插的。

border-color属性的颜色值是数值(命名的颜色都可以用十六进制或其他数字颜色值表示),所以颜色也支持动画。如果从border: red solid 3px过渡到border: blue dashed 10px,边框宽度和边框颜色将按照设定的速度过渡,但border-style将在过渡开始时(延迟过后)直接由solid变成dashed。

同样地,以数值作为参数的CSS函数一般都是支持动画的。这个规则的一个例外是visibility:虽然visible和hidden两个值之间没有中间点,但在可见和不可见之间却可以内插值。如果想插值,visibility属性的初始值或目标值必须有一个visible。在过渡结束时,该值将由visible变成hidden。如果是从hidden过渡到visible,在过渡开始时变化。

通常,auto应该被视作不支持动画的值,应该避免用于动画和过渡。根据规范,auto不支持动画,但有些浏览器将auto(如height: auto)对应的数字值解释为0px。对于height, width, top, bottom, left, right和margin等属性来说,auto不支持动画。

通常情况下,换个属性或值可能就行了。例如,不要把height: 0改成height: auto,可以从max-height: 0改成max-height: 100vh,这通常会产生预期效果。在min-height 和min-width属性中,auto值支持动画,因为min-height:auto的计算结果为零。

18.4.1 属性值是如何内插的

数字是作为浮点数内插。整数以正数内插,以整数递增或递减。

在CSS中,长度值和百分数转换为实数。如果过渡或以动画形式呈现calc(),或在长度值和百分数之间变化,数值将被转换为calc()函数,并作为实数内插。

颜色,无论它们是HSLA、RGB,还是像aliceblue这样的命名颜色,都会被转换为它们的RGBA等效值进行过渡,并在RGBA颜色空间中进行内插。如果你想在不同的颜色空间内插值,比如HSL,你就必须避免使用命名颜色。

以动画的形式改变字重时,如果使用的是关键字,如bold,它们将被转换为数字值,并被动画化。

如果支持动画的属性值有多个部分,各部分单独内插。例如,text-shadow最多有四个组分:color、x、y和blur。color被插值为颜色,而x、y和blur部分按照长度内插。

方框投影有两个额外的可选关键字:inset和spread。Spread部分的值是长度,因此就按照长度值内插。inset关键字无法转换为数值,因此无法在insert和drop阴影之间逐渐转换。

类似地,只有在过渡相同类型的渐变(linear, radial或conic)时,渐变才可以过渡,而且色标的数量相等。然后每个色标的颜色以颜色值内插,而每个色标的位置以长度和百分数内插。

18.4.1.1 内插重复值

如果属性的值为一个列表,各个值将按照相应的类型内插,前提是前后状态中列表里的值或可重复的值数目相等,而且每对值都可以内插。比如说

.img {
    background-image:
        url(1.gif), url(2.gif), url(3.gif), url(4.gif),
        url(5.gif), url(6.gif), url(7.gif), url(8.gif),
        url(9.gif), url(10.gif), url(11.gif), url(12.gif);
    transition: background-size 1s ease-in 0s;
    background-size: 10px 10px, 20px 20px, 30px 30px, 40px 40px;
}
.img:hover {
    background-size: 25px 25px, 50px 50px, 75px 75px, 100px 100px;
}

在过渡四个背景尺寸时,两个列表中的所有尺寸都以像素为单位列出,过渡前状态的第三个background-size可以逐渐过渡到过渡列表的第三个background-size。在前面的例子中,鼠标悬停在图像上时,背景图片1、5和9的高度和宽度将从10px过渡到25px。同样地,图像3、7和11将从30px过渡到75px,以此类推。

因此,background-size的值被重复了三次,就像CSS被写成了

.img {
    …
    background-size: 10px 10px, 20px 20px, 30px 30px, 40px 40px,
                     10px 10px, 20px 20px, 30px 30px, 40px 40px,
                     10px 10px, 20px 20px, 30px 30px, 40px 40px;
    …
}
.img:hover {
    background-size: 25px 25px, 50px 50px, 75px 75px, 100px 100px,
                     25px 25px, 50px 50px, 75px 75px, 100px 100px,
                     25px 25px, 50px 50px, 75px 75px, 100px 100px;
}

如果以逗号分隔的值数目与背景图的数量不一致,值的列表会被重复,直到有足够的值,即使在动画状态下的列表与初始状态不一致:

.img:hover {
    background-size: 33px 33px, 66px 66px, 99px 99px;
}

如果我们从初始状态声明的四个background-size值,过渡到悬停状态的三个background-size值,都是像素,背景图仍然有12个,那么在这两个状态之间过渡时,悬停状态和初始状态中的值都要复制(分别复制三次和四次),直到有12个值为止,就像下面声明的一样:

.img {
    …
    background-size: 10px 10px, 20px 20px, 30px 30px,
                     40px 40px, 10px 10px, 20px 20px,
                     30px 30px, 40px 40px, 10px 10px,
                     20px 20px, 30px 30px, 40px 40px;
    …
}
.img:hover {
    background-size: 33px 33px, 66px 66px, 99px 99px,
                     33px 33px, 66px 66px, 99px 99px,
                     33px 33px, 66px 66px, 99px 99px,
                     33px 33px, 66px 66px, 99px 99px;
}

如果一对数值不能内插--例如,如果background-size从默认状态下的contain变为悬停状态的cover--那么,根据规范,整个列表不能插值。然而,有些浏览器为了过渡的目的会忽略了这一对特定的值,仍然对可内插的值进行动画处理。

有些属性值,如果浏览器可以推断出隐含的值,这些属性也支持动画。例如,对于阴影,浏览器会推断出一个隐含的阴影 box-shadow: transparent 0 0 0 或 box-shadow: inset transparent 0 0 0,替换没有明确包含在过渡前或过渡后状态的值。这些例子都在本书的章节文件中。

只有可内插的值才会触发transitionend事件。

如果你不小心包含了一个不能被过渡的属性,不要害怕。整个声明不会失败:浏览器将把不支持动画的属性剔除,过渡余下的属性。

注意,一个不支持动画的属性或不存在的CSS属性并没有被忽略。浏览器只是跳过无法识别的或不支持动画的属性,保持它们在属性列表中的顺序,以免逗号分隔的其他过渡属性应用到错误的属性上。

注意

只有当下不受CSS动画影响的属性才能过渡。如果元素有动画效果,只要属性当前不受动画控制,仍然可以过渡。第19章介绍了CSS动画。

小贴士

由于过渡通常是渐进式增强,因此不需要为过时的浏览器添加polyfill。虽然您可以为IE9和更早版本使用JavaScript polyfill,并为Android4.3和更早版本的过渡添加前缀,但几乎没有必要这样做。

18.5 打印过渡

当打印网页或Web应用时,使用的是针对印刷媒体的样式表。如果style元素的media属性只匹配screen,那么CSS将完全不会影响打印的页面。

通常情况下,我们没有设定media属性;就跟设置了media="all "一样,这是默认的。根据不同的浏览器,当打印一个过渡元素时,要么忽略内插值,要么打印其当前状态的属性值。

你无法在纸上看到元素的过渡,但是在一些浏览器中,比如Chrome,如果一个元素从一个状态过渡到另一个状态,纸上打印出来的是调用print函数时所处的状态(前提是该属性是可打印的)。例如,如果背景颜色发生了变化,过渡前和过渡后的背景颜色都不会被打印出来,因为背景颜色一般不被打印。然而,如果文本颜色从一个值变到另一个值,彩色打印机上或PDF打印机将打印当前的颜色。

在其他浏览器中,比如Firefox,是打印过渡前的值还是过渡后的值,取决于过渡是如何启动的。例如,如果过渡是通过鼠标悬停启动的,打印的是非悬停值,因为在与打印对话框中操作时鼠标不可能悬停在该元素上。如果过渡是通过增加类来启动的,打印的是过渡开始后的值,即使过渡还没有完成。打印程序就像忽略过渡属性一样。

倘若有单独的打印样式表或针对印刷品的@media规则,浏览器会单独计算样式。在打印样式中,样式不会改变,所以也就没有过渡。在打印程序看来,属性值是瞬间改变的,没有耗费一定时间的过渡效果。

18.6 小结

过渡是一种有用的、相当强大的添加用户界面增强效果的方法。缺乏全面的支持不应妨碍你使用它们,因为如果浏览器不支持CSS过渡,这些变化仍将被应用。你的用户可能会错过一个有趣的(或可能令人讨厌的)效果,但不会错过任何内容。

过渡的决定性特征是,当一个元素从一个状态过渡到另一个状态时,它们就会被应用,无论那是由于用户操作还是DOM的某种脚本变化而发生的。如果你想在不考虑用户操作或DOM变化的情况下产生动画,那么下一章将告诉你方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值