Maison > Article > interface Web > 深入理解CSS过渡transition - 小火柴的蓝色理想
通过过渡transition,可以让web前端开发人员不需要javascript就可以实现简单的动画交互效果。过渡属性看似简单,但实际上它有很多需要注意的细节和容易混淆的地方。本文将介绍和梳理关于CSS过渡的知识
过渡transition是一个复合属性,包括transition-property、transition-duration、transition-timing-function、transition-delay这四个子属性。通过这四个子属性的配合来完成一个完整的过渡效果
transition-<span style="color: #000000;">property: 过渡属性(默认值为all) transition</span>-<span style="color: #000000;">duration: 过渡持续时间(默认值为0s) transiton</span>-timing-<span style="color: #000000;">function: 过渡函数(默认值为ease函数) transition</span>-delay: 过渡延迟时间(默认值为0s)
[注意]IE9-不支持该属性,safari3.1-6、ISO3.2-6.1、android2.1-4.3需要添加-webkit-前缀;而其余高版本浏览器支持标准写法
<span style="color: #800000;">.test</span>{<span style="color: #ff0000;"> height</span>:<span style="color: #0000ff;"> 100px</span>;<span style="color: #ff0000;"> width</span>:<span style="color: #0000ff;"> 100px</span>;<span style="color: #ff0000;"> background-color</span>:<span style="color: #0000ff;"> pink</span>;<span style="color: #ff0000;"> transition-duration</span>:<span style="color: #0000ff;"> 3s</span>; <span style="color: #008000;">/*</span><span style="color: #008000;"> 以下三值为默认值,稍后会详细介绍 </span><span style="color: #008000;">*/</span><span style="color: #ff0000;"> transition-property</span>:<span style="color: #0000ff;"> all</span>;<span style="color: #ff0000;"> transition-timing-function</span>:<span style="color: #0000ff;"> ease</span>;<span style="color: #ff0000;"> transition-delay</span>:<span style="color: #0000ff;"> 0s</span>; }<span style="color: #800000;"> .test:hover</span>{<span style="color: #ff0000;"> width</span>:<span style="color: #0000ff;"> 500px</span>; }
<span style="color: #0000ff;"><span style="color: #800000;">div </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="test"</span><span style="color: #0000ff;">></span><span style="color: #800000;">div</span><span style="color: #0000ff;">></span></span>
//鼠标移动到元素上,会出现宽度变化效果
复合属性
过渡transition的这四个子属性只有
transition: <transition-property> || <transition-duration> || <transition-timing-function> || <transition-delay></transition-delay></transition-timing-function></transition-duration></transition-property>
[注意]transition的这四个子属性之间不能用逗号隔开,只能用空格隔开。因为逗号隔开的代表不同的属性(transition属性支持多值,多值部分稍后介绍);而空格隔开的代表不同属性的四个关于过渡的子属性
<span style="color: #800000;">.test</span>{<span style="color: #ff0000;"> height</span>:<span style="color: #0000ff;"> 100px</span>;<span style="color: #ff0000;"> width</span>:<span style="color: #0000ff;"> 100px</span>;<span style="color: #ff0000;"> background-color</span>:<span style="color: #0000ff;"> pink</span>;<span style="color: #ff0000;"> <!-- 代表持续时间为2s,延迟时间为默认值0s --> transition;2s; </span>}<span style="color: #800000;"> .test:hover</span>{<span style="color: #ff0000;"> width</span>:<span style="color: #0000ff;"> 500px</span>; }
<span style="color: #0000ff;"><span style="color: #800000;">div </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="test"</span><span style="color: #0000ff;">></span><span style="color: #800000;">div</span><span style="color: #0000ff;">></span></span>
<span style="color: #800000;">.test</span>{<span style="color: #ff0000;"> height</span>:<span style="color: #0000ff;"> 100px</span>;<span style="color: #ff0000;"> width</span>:<span style="color: #0000ff;"> 100px</span>;<span style="color: #ff0000;"> background-color</span>:<span style="color: #0000ff;"> pink</span>;<span style="color: #ff0000;"> <!-- 代表持续时间为1s,延迟时间为2s --> transition</span>:<span style="color: #0000ff;"> 1s 2s</span>; }<span style="color: #800000;"> .test:hover</span>{<span style="color: #ff0000;"> width</span>:<span style="color: #0000ff;"> 500px</span>; }
<span style="color: #0000ff;"><span style="color: #800000;">div </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="test"</span><span style="color: #0000ff;">></span><span style="color: #800000;">div</span><span style="color: #0000ff;">></span></span>
transition-property
值: none | all |
初始值: all
应用于: 所有元素
继承性: 无
<span style="color: #000000;">none: 没有指定任何样式 all: 默认值,表示指定元素所有支持transition</span>-<span style="color: #000000;">property属性的样式 </span><transition-property>: 可过渡的样式,可用逗号分开写多个样式</transition-property>
可过渡的样式
不是所有的CSS样式值都可以过渡,只有具有中间值的属性才具备过渡效果
Vstart = 开始值; Vend = 结束值; Vres = 中间值; p =<span style="color: #000000;"> 过渡函数的输出值 Vres </span>= (<span style="color: #800080;">1</span> - p) * Vstart + p *<span style="color: #000000;"> Vend 当Vres具有有效值时,则该CSS样式可过渡</span>
颜色: color background-color border-color outline-<span style="color: #000000;">color 位置: backround</span>-<span style="color: #000000;">position left right top bottom 长度: [</span><span style="color: #800080;">1</span>]max-height min-height max-width min-<span style="color: #000000;">width height width [</span><span style="color: #800080;">2</span>]border-width margin padding outline-width outline-<span style="color: #000000;">offset [</span><span style="color: #800080;">3</span>]font-size line-height text-indent vertical-<span style="color: #000000;">align [</span><span style="color: #800080;">4</span>]border-spacing letter-spacing word-<span style="color: #000000;">spacing 数字: opacity visibility z</span>-index font-<span style="color: #000000;">weight zoom 组合: text</span>-shadow transform box-<span style="color: #000000;">shadow clip 其他: gradient</span>
该属性的单位是秒s或毫秒ms
transition-duration
值:
初始值: 0s
应用于: 所有元素
继承性: 无
[注意]该属性若不能为负值
[注意]若该属性为0s则为默认值,若为0则为无效值。所以必须带单位
[注意]该值为单值时,即所有过渡属性都对应同样时间;该值为多值时,过渡属性按照顺序对应持续时间
<span style="color: #008000;">//</span><span style="color: #008000;">DEMO中的过渡属性值</span> transition-property: width,background;
该属性定义元素属性延迟多少时间后开始过渡效果,该属性的单位是秒s或毫秒ms
transition-delay
值:
初始值: 0s
应用于: 所有元素
继承性: 无
[注意]该属性若为负值,无延迟效果,但过渡元素的起始值将从0变成设定值(设定值=延迟时间+持续时间)。若该设定值小于等于0,则无过渡效果;若该设定值大于0,则过渡元素从该设定值开始完成剩余的过渡效果
[注意]若该属性为0s则为默认值,若为0则为无效值。所以必须带单位
[注意]该值为单值时,即所有过渡属性都对应同样时间;该值为多值时,过渡属性按照顺序对应持续时间
<span style="color: #008000;">//</span><span style="color: #008000;">DEMO中的过渡属性值</span> transition-property: width,background;
过渡时间函数用于定义元素过渡属性随时间变化的过渡速度变化效果
transition-timing-function
值:
初始值: ease
应用于: 所有元素
继承性: 无
取值
过渡时间函数共三种取值,分别是关键字、steps函数和besizer函数
steps函数
steps步进函数将过渡时间划分成大小相等的时间时隔来运行
steps步进函数为
steps(<integer>[,start | end]?)</integer>
<interger><span style="color: #000000;">:用来指定间隔个数(该值只能是正整数) 第二个参数: 该参数可选,默认是end,表示开始值保持一次;若参数为start,表示开始不保持</span></interger>
贝塞尔曲线
贝塞尔曲线通过p0-p3四个控制点来控制,其中p0表示(0,0),p3表示(1,1)。而
transition-timing-function: cubic-bezier(x1,y1,x2,y2);
[注意]x1,y1,x2,y2都是0到1的值(包括0和1)
关键字
关键字其实是bezier函数或steps函数的特殊值
ease: 开始和结束慢,中间快。相当于cubic-bezier(<span style="color: #800080;">0.25</span>,<span style="color: #800080;">0.1</span>,<span style="color: #800080;">0.25</span>,<span style="color: #800080;">1</span><span style="color: #000000;">) linear: 匀速。相当于cubic</span>-bezier(<span style="color: #800080;">0</span>,<span style="color: #800080;">0</span>,<span style="color: #800080;">1</span>,<span style="color: #800080;">1</span><span style="color: #000000;">) ease</span>-<span style="color: #0000ff;">in</span>: 开始慢。相当于cubic-bezier(<span style="color: #800080;">0.42</span>,<span style="color: #800080;">0</span>,<span style="color: #800080;">1</span>,<span style="color: #800080;">1</span><span style="color: #000000;">) ease</span>-<span style="color: #0000ff;">out</span>: 结束慢。相当于cubic-bezier(<span style="color: #800080;">0</span>,<span style="color: #800080;">0</span>,<span style="color: #800080;">0.58</span>,<span style="color: #800080;">1</span><span style="color: #000000;">) ease</span>-<span style="color: #0000ff;">in</span>-<span style="color: #0000ff;">out</span>: 和ease类似,但比ease幅度大。相当于cubic-bezier(<span style="color: #800080;">0.42</span>,<span style="color: #800080;">0</span>,<span style="color: #800080;">0.58</span>,<span style="color: #800080;">1</span><span style="color: #000000;">) step</span>-start: 直接位于结束处。相当于steps(<span style="color: #800080;">1</span><span style="color: #000000;">,start) step</span>-end: 位于开始处经过时间间隔后结束。相当于steps(<span style="color: #800080;">1</span>,end)
transition的多个属性值用逗号分隔开表示可以同时为多个值设置过渡属性。
transtion: <single-transition>[,<single-transition>]*</single-transition></single-transition>
<single-transition>: <transition-property> || <transition-duration> || <transition-timing-function> || <transition-delay></transition-delay></transition-timing-function></transition-duration></transition-property></single-transition>
<span style="color: #008000;">//</span><span style="color: #008000;">property为all,timing-function为linear,delay为0s,duration为0s。表示无过渡行为</span> transition: 0s;
【1】若不同的transition-property的值,对应的transition-delay | transition-timing-function | transition-duration的属性值都相同时,其他的属性设置一个即可
<span style="color: #800000;">#test1</span>{<span style="color: #ff0000;"> transition-property</span>:<span style="color: #0000ff;"> width,background</span>;<span style="color: #ff0000;"> transition-delay</span>:<span style="color: #0000ff;"> 200ms</span>;<span style="color: #ff0000;"> transition-timing-function</span>:<span style="color: #0000ff;"> linear</span>;<span style="color: #ff0000;"> transition-duration</span>:<span style="color: #0000ff;"> 2s</span>; } <span style="color: #008000;">/*</span><span style="color: #008000;">类似于</span><span style="color: #008000;">*/</span><span style="color: #800000;"> #test2</span>{<span style="color: #ff0000;"> transition</span>:<span style="color: #0000ff;"> width 2s linear 200ms,background 2s linear 200ms</span>; }
【2】当transition-property的值的个数多于对应的transition-delay | transition-timing-function | transition-duration的属性值(属性值的个数大于1个)时,将按顺序开始取值
<span style="color: #800000;">#test1</span>{<span style="color: #ff0000;"> transition-property</span>:<span style="color: #0000ff;"> width,background,opacity</span>;<span style="color: #ff0000;"> transition-duration</span>:<span style="color: #0000ff;"> 2s,500ms</span>;<span style="color: #ff0000;"> transition-timing-function</span>:<span style="color: #0000ff;"> linear,ease</span>;<span style="color: #ff0000;"> transition-delay</span>:<span style="color: #0000ff;"> 200ms,0s</span>; } <span style="color: #008000;">/*</span><span style="color: #008000;">类似于</span><span style="color: #008000;">*/</span><span style="color: #800000;"> #test2</span>{<span style="color: #ff0000;"> transition</span>:<span style="color: #0000ff;"> width 2s linear 200ms,background 500ms ease 0s,opacity 2s linear 200ms</span>; }
【3】当transition-property的值少于对应的transition-delay | transition-timing-function | transition-duration的属性值时,多余的其他属性值将无效
<span style="color: #800000;">#test1</span>{<span style="color: #ff0000;"> transition-property</span>:<span style="color: #0000ff;"> width</span>;<span style="color: #ff0000;"> transition-duration</span>:<span style="color: #0000ff;"> 2s,500ms</span>;<span style="color: #ff0000;"> transition-timing-function</span>:<span style="color: #0000ff;"> linear,ease</span>;<span style="color: #ff0000;"> transition-delay</span>:<span style="color: #0000ff;"> 200ms,0s</span>; } <span style="color: #008000;">/*</span><span style="color: #008000;">类似于</span><span style="color: #008000;">*/</span><span style="color: #800000;"> #test2</span>{<span style="color: #ff0000;"> transition</span>:<span style="color: #0000ff;"> width 2s linear 200ms</span>; }
【4】当transition-property的值中出现一个无效值,它依然按顺序对应transition的其他属性值(其他属性出现无效值,处理情况也类似)
<span style="color: #800000;">#test1</span>{<span style="color: #ff0000;"> transition-property</span>:<span style="color: #0000ff;"> width,wuxiao,background</span>;<span style="color: #ff0000;"> transition-duration</span>:<span style="color: #0000ff;"> 2s,500ms</span>;<span style="color: #ff0000;"> transition-timing-function</span>:<span style="color: #0000ff;"> linear,ease</span>;<span style="color: #ff0000;"> transition-delay</span>:<span style="color: #0000ff;"> 200ms,0s</span>; } <span style="color: #008000;">/*</span><span style="color: #008000;">类似于</span><span style="color: #008000;">*/</span><span style="color: #800000;"> #test2</span>{<span style="color: #ff0000;"> transition</span>:<span style="color: #0000ff;"> width 2s linear 200ms,background 2s linear 200ms</span>; }
【5】当transition-property的值中,有些值重复出现多次,则以最后出现的值为准,前面所有出现的值都被认定为无效值,但依然按顺序对应transition的其他属性值
<span style="color: #800000;">#test1</span>{<span style="color: #ff0000;"> transition-property</span>:<span style="color: #0000ff;"> width,width,background</span>;<span style="color: #ff0000;"> transition-duration</span>:<span style="color: #0000ff;"> 2s,500ms</span>;<span style="color: #ff0000;"> transition-timing-function</span>:<span style="color: #0000ff;"> linear,ease</span>;<span style="color: #ff0000;"> transition-delay</span>:<span style="color: #0000ff;"> 200ms,0s</span>; } <span style="color: #008000;">/*</span><span style="color: #008000;">类似于</span><span style="color: #008000;">*/</span><span style="color: #800000;"> #test2</span>{<span style="color: #ff0000;"> transition</span>:<span style="color: #0000ff;"> width 500ms ease 0s,background 2s linear 200ms</span>; }
【1】过渡开始时间=样式改变的时刻+过渡延迟时间;而过渡结束时间=过渡开始时间+过渡持续
【2】过渡起始值=过渡前的过渡属性值;而过渡结束值=过渡完成后的过渡属性值
【3】过渡分为两个阶段:前进(forward)和反向(reverse)。若前进阶段进行一段时间后进入反向阶段。则反向阶段的初始值是前进阶段结束时的瞬时值
【4】以hover为例,若在元素非hover态时设置transition,相当于设置的反向状态。而前进和反向是一致的。而如果在元素hover态设置transition,则前进状态以hover态设置的为准,而反向状态以非hover态设置的为准
<span style="color: #000000;">.test{ width: 100px; transition: 3s; } .test:hover{ width: 500px; transition: 500ms; }</span>
【5】如果子元素和父元素过渡属性都一致。若触发子元素过渡时,父元素正在过渡,则将父元素过渡的中间态的值作为子元素过渡的初始值
<span style="color: #000000;">.box:hover{ font</span>-<span style="color: #000000;">size: 50px; } .test:hover{ font</span>-<span style="color: #000000;">size: 30px; }</span>
<div style="color: #0000ff;">class=<span style="color: #800000;">"</span><span style="color: #800000;">box</span><span style="color: #800000;">"</span>> <div style="color: #0000ff;">class=<span style="color: #800000;">"</span><span style="color: #800000;">test</span><span style="color: #800000;">"</span>>test</div> </div>
【6】若过渡起始值或过渡开始值为auto,则浏览器不会自己计算成具体数字值,而是不发生过渡效果。所以要过渡某些属性,首先需要将其重置成具体数字值
[注意]低版本webkit内核浏览器存在bug,会产生反向的过渡效果
<span style="color: #000000;">.test{ width: 100px; </span>-webkit-<span style="color: #000000;">transition: width 2s; transition:width 2s; } .test:hover{ width:auto; }</span>
【7】隐式过渡是指一个属性改变时引起另一个属性的改变。如border-width是1em,则font-size改变时,border-width也会相应的改变。firefox和IE浏览器支持隐式过渡。而webkit内核浏览器不支持隐式过渡。
<span style="color: #000000;">.test{ border: 1px solid black; </span>-webkit-transition: font-<span style="color: #000000;">size 2s; transition:font</span>-<span style="color: #000000;">size 2s; font: 20px</span>/100px <span style="color: #800000;">"</span><span style="color: #800000;">宋体</span><span style="color: #800000;">"</span><span style="color: #000000;">; } .test:hover{ font</span>-<span style="color: #000000;">size: 40px; border</span>-right-<span style="color: #000000;">width: 1em; }</span>
一般地,过渡transition的触发有三种方式,分别是伪类触发、媒体查询触发和javascript触发。其中常用伪类触发包括:hover、:focus、:active等
【1】hover
鼠标悬停触发
【2】active
用户单击元素并按住鼠标时触发
【3】focus
获得焦点时触发
【4】@media触发
符合媒体查询条件时触发
<span style="color: #008000;">/*</span><span style="color: #008000;"> 把浏览器的宽度拖动到小于1000px时触发 </span><span style="color: #008000;">*/</span><span style="color: #000000;"> @media (max</span>-<span style="color: #000000;">width: 1000px){ .test{ width: 500px; } }</span>
【5】点击事件
用户点击元素时触发
test.onclick =<span style="color: #000000;"> function(){ test.style.width </span>= <span style="color: #800000;">'</span><span style="color: #800000;">300px</span><span style="color: #800000;">'</span><span style="color: #000000;">; setTimeout(function(){ test.style.width </span>= <span style="color: #800000;">'</span><span style="color: #800000;">100px</span><span style="color: #800000;">'</span><span style="color: #000000;">; },</span><span style="color: #800080;">3000</span><span style="color: #000000;">); }</span>
关于过渡transition的事件只有一个,是transitionend事件,它发生在过渡事件完成后
[注意]safari3.1-6、ISO3.2-6.1、android2.1-4.3需要使用webkitTransitionEnd事件
【1】过渡分为两个阶段:前进阶段和反向阶段。transitionend事件在前进阶段结束时会触发,在反向阶段结束时也会触发。
<span style="color: #0000ff;">var</span> index = 0<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">兼容低版本safari、IOS、android</span> test.addEventListener("webkitTransitionEnd"<span style="color: #000000;">, myFunction); </span><span style="color: #008000;">//</span><span style="color: #008000;"> 标准语法</span> test.addEventListener("transitionend"<span style="color: #000000;">, myFunction); </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> myFunction() { index</span>++<span style="color: #000000;">; </span><span style="color: #0000ff;">this</span>.innerHTML =<span style="color: #000000;"> index;</span><span style="color: #000000;"> }</span>
【2】过渡事件触发的次数与transition-property过渡属性的个数有关。过渡属性有几个就会触发几次
transition: width 1s,background-<span style="color: #000000;">color 1s; </span>-webkit-transition: width 1s,background-color 1s;
【3】如果过渡属性是复合属性,如border-width相当于是border-top-width、border-bottom-width、border-left-width和border-right-width这四个属性的集合。则过渡事件触发4次
[注意]在低版本webkit内核浏览器里只触发1次
transition:border-<span style="color: #000000;">width 1s; </span>-webkit-transition: border-width 1s;
【4】如果过渡属性是默认值all,则过渡事件的次数是计算后的非复合的过渡属性的个数。如果发生过渡的属性是border-width和width,则经过计算后过渡事件应该触发5次
[注意]在低版本webkit内核浏览器中处理情况也一致
<span style="color: #000000;">.test{ width: 50px; border: 1px solid black; transition:all 1s; </span>-webkit-<span style="color: #000000;">transition: all 1s; } .test:hover{ border</span>-<span style="color: #000000;">width: 10px; width: 100px; }</span>
【5】如果过渡延迟时间为负值,且绝对值大于等于过渡持续时间时,低版本webkit内核浏览器不会产生过渡效果,但会触发过渡事件;而其他浏览器即不会产生过渡效果,也不会触发过渡事件
transition:width 1s -<span style="color: #000000;">1s; </span>-webkit-transition: width 1s -1s;
【6】如果过渡属性是存在复合属性及该复合属性包含的非复合属性,则浏览器计算复合属性的子属性时,不会重复计算已包含的属性
[注意]低版本webkit内核浏览器会出现bug,不仅复合属性被当作一个属性来触发事件,而且会多触发一次
<span style="color: #000000;">.test{ border: 1px solid black; transition:border</span>-width 1s,border-left-<span style="color: #000000;">width 2s; </span>-webkit-transition: border-width 1s,border-left-<span style="color: #000000;">width 2s; } .test:hover{ border</span>-<span style="color: #000000;">width:10px; }</span>
[注意]当过渡事件执行完后,应及时使用removeEventListener取消绑定,以免对其他效果造成影响
<span style="color: #0000ff;">var</span> index = 0<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">兼容低版本safari、IOS、android</span> test.addEventListener("webkitTransitionEnd"<span style="color: #000000;">, myFunction); </span><span style="color: #008000;">//</span><span style="color: #008000;"> 标准语法</span> test.addEventListener("transitionend"<span style="color: #000000;">, myFunction); </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> myFunction() { index</span>++<span style="color: #000000;">; </span><span style="color: #0000ff;">this</span>.innerHTML =<span style="color: #000000;"> index; </span><span style="color: #0000ff;">if</span>(index == 1<span style="color: #000000;">){ test.removeEventListener(</span>"webkitTransitionEnd"<span style="color: #000000;">, myFunction); test.removeEventListener(</span>"transitionend"<span style="color: #000000;">, myFunction); } }</span>