transition从效果上看是一种平滑过渡的动画,本质上是在线性时间内将属性从开始值过渡到结束值。例如得到焦点,点击鼠标等动做致使CSS属性值的变化是瞬间完成的,感受有点生硬。用transition能够指定在某时间段内将属性值平滑过渡,加强用户体验。javascript
transition有4个子属性:transition-property,transition-duration,transition-timing-function,transition-delay
php
transition-property指定须要过渡的CSS属性。并非全部属性都能过渡的,只有能数字量化的CSS属性才能过渡。css
哪些属于能数字量化的CSS属性呢?例如:前端
颜色系,如color,background-color,border-color,outline-color
等java
数字系,实在太多了,如width,height,top,right,bottom,left,zoom,opacity,line-height,background-position,word-spacing,font-weight,vertical-align,outline-outset,z-index
等。css3
01系,如visibility(0表示隐藏,1表示显示)浏览器
还有更多如渐变,阴影等分类请参照W3C的Animation of property types,不一一列举了。前端工程师
W3C上还有可过渡属性一览表Properties from CSS。一般只要能设数字(包括%百分比)的属性都能过渡。闭包
除了单个指定属性外,transition-property还能设为all
,表示全部属性都将得到过渡效果。函数
transition-duration过渡须要的时间,单位可指定s秒,也可指定ms毫秒。默认值是0,表示马上变化。
若是设置了多个过渡属性,但每一个属性的过渡时间都同样,你不必为transition-duration设多个值,只有设一个便可,该值会应用到全部过渡属性上。
transition-timing-function过渡函数,有linear
,ease
,ease-in
,ease-out
,ease-in-out
,cubic-bezier(n,n,n,n)
,steps
。
其实它们都是贝赛尔曲线。以下
linear
是匀速过渡,
ease
是先快再慢的节奏,
ease-in
是加速冲刺的节奏,
ease-out
是减速到中止的节奏,
ease-in-out
是先加速后减速的节奏。
如今动画的精度愈来愈高,若是预约义好的这些函数知足不了你的需求,能够经过cubic-bezier(n,n,n,n)
自定义平滑曲线。
从上面的图形中观察到,贝塞尔曲线有4个点,左下为起始点P0坐标固定为(0,0),右上为终点P3坐标固定为(1,1),中间有两点P1和P2的坐标就是cubic-bezier(n,n,n,n)
的参数。
经过4条连起来的直线,生成平滑的曲线。一图胜千言:
linear
,
ease
,
ease-in
,
ease-out
,
ease-in-out
间的差别。
steps能够把过渡阶段分割成等价的几步。什么意思呢?一图胜千言:
start
,
end
,不设的话默认是
end
。
steps(4, start)
等价于
step-start(4)
,
steps(4, end)
等价于
step-end(4)
。例如
steps(4, end)
并不是像贝塞尔曲线那样平滑过渡,
transition-delay延迟开始过渡的时间,默认值是0,表示不延迟,当即开始过渡动做。单位是s秒或ms毫秒。
w3cschool上没说的是,该属性还能设负时间,意思是让过渡动做从该时间点开始启动,以前的过渡动做不显示。
你能够单独指定这4个子属性,也能够像background等属性同样,合并在transition属性里指定。
但合并时要注意,由于有transition-duration和transition-delay都是时间,浏览器会根据前后顺序,将第一个时间认做为transition-duration,第二个时间认做为transition-delay。
是分开或者合并指定并没有标准答案。分开指定可能代码易读性高一点。
但当页面须要适应各浏览器时,每一个都要加上-ms-,-moz-等前缀,代码会变的不少,合并在一块儿代码稍微少点。
另外也能够同时指定多个过渡效果,例如transition: background 1s linear 2s, border-radius 2s ease-in 3s;
。
常见的就是伪类触发:hover,:focus,:active,:checked等。还有例如@media媒体查询,根据设备大小,横屏竖屏切换时触发。
还有如click,keydown等JS事件触发。页面加载也能触发就不一一列举了。总之过渡的本质是在时间段内平滑过渡属性值,与怎么触发没有关系。
transition既然涉及时间,天然就有事件。参照MDN有transitionend事件,顾名思义就是过渡结束时触发该事件。但该事件比较坑。例如过渡padding时,代码以下:
#tempDiv { padding: 1px; transition-property: padding; transition-duration: 1s; } #tempDiv:hover { padding: 5px; } function showMessage() { console.log('finished'); //过渡结束时触发打印log } var element = document.getElementById("tempDiv"); element.addEventListener("transitionend", showMessage, false);
你能够代码贴到浏览器里试试,结果出现4条log。
由于过渡属性指定的是padding,因此在padding-top,padding-right,padding-bottom,padding-left过渡结束时均触发了transitionend事件。所以log被打印了4次。
若是上述CSS中将transition-property: padding;
改成all,一样会触发4次。
除非你改为transition-property: padding-top;
这样才能只触发一次,但现实中只过渡一边的场景很是少,一般都是4边同时过渡,
所以例如padding,margin,border之类的属性,用transitionend事件会有屡次捕捉的状况发生。
transition过渡时有时会出现一些比较暧昧的情形,好比设成em的属性,如你所知em是根据font-size来计算的。
相似还有rem,vh,vw等都是根据另外一个属性的值来计算获得它的值。
举个例子padding:2em;
,若是font-size被改变了,此时padding的“书面值”不变,仍旧是2em,但“实际值”将会发生变化并触发transition过渡。这被称做“隐式过渡”。
多数浏览器会实现隐式过渡,但传闻IE很特别,具体有多特别我也没试过。没试过就轻信传闻好像很不严谨,但根据IE过往的口碑,我宁肯信其有…前端工程师都懂的。
开关过渡,顾名思义就是触发源的事件结束后会恢复到原始状态。永久过渡就是过渡后不恢复到原始状态。
上面的例子都是开关过渡,当鼠标hover事件结束后,图片恢复原始尺寸。但永久过渡的话,鼠标hover事件结束后,图片仍旧保持放大后的尺寸。
//开关过渡 .transition { transition: all 1s ease-in-out; } .transition:hover { transform: scale(1.5); } //永久过渡 .forever { transition: all 1s ease-in-out 999999s; } .forever:hover { transform: scale(1.5); transition: all 1s ease-in-out; }
由于回到原始尺寸的transition-duration被设成了一个很大的时间,999999s差很少有12天,理论上你页面开12天就能看到关闭过渡的效果,但现实等于永久过渡。该技巧无需任何JS脚本。
一般咱们属性过渡时,都是定值到定值的过渡,例如width:100px
过渡到200px。但要过渡到width:auto
就不行了。
就算你指定transition: width 1s linear;
会发现根本不会有1秒的平滑的过渡效果,而是瞬间完成过渡。
.div1 {
background-color: red;
width: 100px;
height: 50px;
}
#box1:hover {
width: auto;
transition: width 1s linear;
}
<div id="box1" class="div1"></div>
若是想要过渡效果,必须将auto转换为固定值。那么问题来了,如何转换呢?
须要靠JS,经过getComputedStyle获取auto后的固定值后,经过style设置该值,而后再触发CSS的过渡效果。
window.onload = function(){ var box = document.getElementById("box2"), originWidth = box.clientWidth, width2AutoLater = null, width2OriginLater = null; var width2Auto = function(element, time) { if (typeof window.getComputedStyle == "undefined") return; var width = window.getComputedStyle(element).width; element.style.width = "auto"; var targetWidth = window.getComputedStyle(element).width; element.style.width = width; setTimeout(function() { element.style.transition = "width "+ time +"ms linear"; element.style.width = targetWidth; }, 10); }; var width2Origin = function(element, time) { setTimeout(function() { element.style.transition = "width 0s linear"; element.style.width = originWidth + "px"; }, 10); }; function callLater(func, paramA, paramB){ return function(){ func.call(this, paramA, paramB); }; } width2AutoLater = callLater(width2Auto, box, 1000); width2OriginLater = callLater(width2Origin, box, 1000); box.addEventListener("mouseenter", width2AutoLater); box.addEventListener("mouseleave", width2OriginLater); } <div id="box2" class="div1"></div>
代码耐心看看应该能看明白。无CSS,全靠JS实现过渡效果。
思路:给div注册了mouseenter和mouseleave事件来模拟hover效果。
mouseenter绑定width2Auto函数,函数里临时将div的width设为auto后,用getComputedStyle获得宽度值,将该宽度值和transition设进该div的style里。
mouseleave绑定width2Origin函数,函数里将div的width改回初始值。
由于注册事件的函数addEventListener的第二个参数是回调函数名,不能给回调函数传参数。
所以,使用闭包的特性,定义了callLater中间函数,函数里经过call调用上述两个函数。