Web编程技术营地
研究、演示、创新

CSS Transitions

撰写时间:2025-11-30

修订时间:2026-03-09

应用CSStransitions,可在我们指定的CSS属性值发生变化时,自动产生平滑的过渡效果。

注,本文各个例子仅显示核心代码,但均使用以下代码作为后台支撑:

color-scheme-iframe.js const MEDIA_STR = '(prefers-color-scheme: light)'; function initIframe(partialSrcdoc) { pc.appendInlineStyle(` ul.pageconsole-output { > li { padding-left: 0em; display: flex; align-items: center; > iframe { border-width: 0px; width: 100%; } } } `); let iframe = document.createElement('iframe'); assembleSrcdoc(iframe, partialSrcdoc); iframe.onload = (evt) => { let doc = iframe.contentDocument; applyColorScheme(doc); handleColorSchemeChanged(doc); autoHeight(iframe, doc); appendResetBtn(doc); doOnIframeLoaded(doc); }; pc.appendChild(iframe); } function appendResetBtn(doc) { let resetBtn = doc.querySelector('#reset'); if (!resetBtn) { resetBtn = doc.createElement('button'); resetBtn.textContent = 'Reset'; resetBtn.onclick = () => { doc.location.reload(); doOnReset(doc); }; doc.body.appendChild(resetBtn); } } function assembleSrcdoc(iframe, partialSrcdoc) { let srcdoc = ` <style> :root { color-scheme: 'light dark'; } body { color: light-dark(#000, #ACB7C4); background-color: light-dark(#FFF, #2B2B2B); } button { margin: 1em 0; padding: 0.7em; border-radius: 0.3em; border-width: 1px; } <<UI_STYLE_PART>> </style> <body> <<UI_BODY_PART>> </body> `; let uiStylePart = /<style>(.+)<\/style>/s.exec(partialSrcdoc)[1]; srcdoc = srcdoc.replace('<<UI_STYLE_PART>>', uiStylePart); let uiBodyPart = /<body>(.+)<\/body>/s.exec(partialSrcdoc)[1]; srcdoc = srcdoc.replace('<<UI_BODY_PART>>', uiBodyPart); iframe.srcdoc = srcdoc; } function autoHeight(iframe, doc) { iframe.style.height = '0px'; iframe.style.height = `${doc.documentElement.scrollHeight}px`; } function getCurrColorTheme() { let currColorTheme = localStorage.getItem('color-theme'); if (currColorTheme) { return currColorTheme; } else { let themeStr = /\(prefers-color-scheme: (.+)\)/.exec(MEDIA_STR)[1]; if (matchMedia(MEDIA_STR).matches) { return themeStr; } else { return themeStr === 'light' ? 'dark' : 'light'; } } } function handleColorSchemeChanged(doc) { matchMedia(MEDIA_STR).onchange = (evt) => { applyColorScheme(doc); }; window.addEventListener('color-scheme-changed', (evt) => { applyColorScheme(doc); }); } function applyColorScheme(doc) { let currColorScheme = getCurrColorTheme(); doc.documentElement.style.colorScheme = currColorScheme; } function doOnIframeLoaded(doc) { } function doOnReset(doc) { }

基本用法

let partialSrcdoc = ` <body>
</body> `; initIframe(partialSrcdoc); function doOnIframeLoaded(doc) { doc.querySelector('button').onclick = () => { let divElement = doc.querySelector('div'); divElement.style.width = '300px'; }; }

使用transition-property指定需要产生平滑过渡效果的CSS属性名,使用transition-duration指定平滑过渡的时间。

上面,按下按钮后,divwidth属性值将从原来的100px变成300px,由于我们为其width属性设定了平滑过渡效果,则整个过程将在指定的时间内平滑地完成,从而产生平滑的动画效果。

同时指定多个属性

transition-property的值可为多个属性名,中间用,号隔开。相对地,transition-duration的值也使用中间用,号隔开。

let partialSrcdoc = ` <body>
</body> `; initIframe(partialSrcdoc); function doOnIframeLoaded(doc) { doc.querySelector('#change-value').onclick = () => { let divElement = doc.querySelector('#demo'); divElement.style.width = '300px'; divElement.style.opacity = 0; }; }

transition-timing-function

transition-timing-function用以设置动画开始、动画结束的速度。

let partialSrcdoc = ` <body>
</body> `; initIframe(partialSrcdoc); function doOnIframeLoaded(doc) { doc.querySelector('#change-value').onclick = () => { let divElement = doc.querySelector('#demo'); divElement.style.width = '300px'; divElement.style.opacity = 0; }; }

具体参见CSS Animations: animation-timing-function

transition-delay

transition-delay指定隔多久后才开始动画。

let partialSrcdoc = ` <body>
</body> `; initIframe(partialSrcdoc); function doOnIframeLoaded(doc) { doc.querySelector('#change-value').onclick = () => { let divElement = doc.querySelector('#demo'); divElement.style.width = '300px'; divElement.style.opacity = 0; }; }

transition综合属性

语法:

transition: <single-transition># <single-transition> = [ none | <single-transition-property> ] || <time> || <timing-function> || <time>

因为有2个动画时间,若只提供1个动画时间,则为transition-duration的值;若提供2个动画时间,第2个为transition-delay的值。

let partialSrcdoc = ` <body>
</body> `; initIframe(partialSrcdoc); function doOnIframeLoaded(doc) { doc.querySelector('#change-value').onclick = () => { let divElement = doc.querySelector('#demo'); divElement.style.width = '300px'; divElement.style.opacity = 0; }; }

Transition 事件

let partialSrcdoc = ` <body>
</body> `; initIframe(partialSrcdoc); function doOnIframeLoaded(doc) { let divElement = doc.querySelector('#demo'); doc.querySelector('#change-value').onclick = () => { divElement.style.width = '300px'; }; divElement.ontransitionrun = (evt) => { pc.log('ontransitionrun'); pc.log(evt); pc.log(evt.elapsedTime); }; divElement.ontransitionstart = (evt) => { pc.log('ontransitionstart'); pc.log(evt.elapsedTime); }; divElement.ontransitionend = (evt) => { pc.log('ontransitionend'); pc.log(evt.elapsedTime); }; divElement.ontransitioncancel = (evt) => { pc.log('ontransitioncancel'); pc.log(evt.elapsedTime); }; } function doOnReset(doc) { pc.consoleUL.querySelectorAll(':scope > li:not(:first-child)').forEach(li => li.remove()); }

CSS Transition 与 CSS Animation 的异同

相同之处

它们的相同之处在于,在指定属性值发生变化时,都会触发动画。具体来说,两者都可指定以下的CSS属性值:

  • 要产生动画的属性
  • 计时函数 (timing functions)
  • 延迟播放动画时长

不同之处

第一,触发条件不同。

CSS Transition所指定的属性值发生变化时,才会触发动画。而要让CSS Transition所指定的属性值发生变化,较常用的场合是使用CSS:hover,或是通过JavaScript编写按钮响应代码来改变其值。

第二,CSS Animation可以自由设定动画中间的多个关键帧,而CSS Transition只有首尾两个关键帧。

第三,CSS Animation可以在动画播放完毕后即可停留在结束状态,也可回到初始状态,而CSS Transition在动画播放完毕后只能停留在结束状态。

参考资源

  1. W3C: CSS Transitions