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指定平滑过渡的时间。
上面,按下按钮后,div的width属性值将从原来的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在动画播放完毕后只能停留在结束状态。