@starting-style
语法
@starting-style
at 规则可以通过两种方式使用
- 作为独立块,在这种情况下,它包含一个或多个规则集,定义起始样式声明并选择它们应用的元素css
@starting-style { rulesets }
- 嵌套在现有的规则集中,在这种情况下,它包含一个或多个声明,定义已由该规则集选择的元素的起始属性值css
selector { /* existing ruleset */ /* ... */ @starting-style { declarations } }
描述
为了避免意外行为,CSS 过渡 在默认情况下不会在元素的初始样式更新时触发,或者当其display
类型从 none
更改为其他值时。若要启用第一个样式过渡,需要 @starting-style
规则。它们为没有先前状态的元素提供起始样式,定义要从中过渡的属性值。
@starting-style
在创建显示在顶层(例如 弹出窗口 和模态 <dialog>
)、从 display: none
更改为和从 display: none
更改为的元素以及首次添加到或从 DOM 中移除的元素的进入和退出过渡时特别有用。
使用 @starting-style
有两种方法:作为独立规则或嵌套在规则集中。
让我们考虑一个场景,我们希望在显示(即添加到顶层)时为 弹出窗口 设置动画。指定打开的弹出窗口样式的“原始规则”可能如下所示(请参见下面的弹出窗口示例)
[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
}
若要使用第一种方法指定弹出窗口将要使用动画的属性的起始值,请在 CSS 中包含一个独立的 @starting-style
块
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}
注意:@starting-style
at 规则和“原始规则”具有相同的特异性
。若要确保应用起始样式,请将 @starting-style
at 规则放在“原始规则”之后。如果在“原始规则”之前指定 @starting-style
at 规则,则原始样式将覆盖起始样式。
若要使用嵌套方法指定弹出窗口的起始样式,可以在“原始规则”内嵌套 @starting-style
块
[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
@starting-style {
opacity: 0;
transform: scaleX(0);
}
}
何时准确使用起始样式?
必须了解,当元素首次在 DOM 中呈现或从display: none
过渡到可见值时,它将从其 @starting-style
样式过渡。当它从其初始可见状态过渡回来时,它将不再使用 @starting-style
样式,因为它现在在 DOM 中可见。相反,它将过渡回该元素默认状态的任何现有样式。
实际上,在这些情况下需要管理三种样式状态——起始样式状态、过渡状态和默认状态。在这种情况下,“到”和“从”过渡可能不同。您可以在下面的起始样式使用时机的演示示例中看到这一点。
正式语法
示例
基本的 @starting-style 用法
在元素初始渲染时,将其background-color
从透明过渡到绿色。
#target {
transition: background-color 1.5s;
background-color: green;
}
@starting-style {
#target {
background-color: transparent;
}
}
当元素的display
值切换到或从none
时,过渡元素的opacity
。
#target {
transition-property: opacity, display;
transition-duration: 0.5s;
display: block;
opacity: 1;
@starting-style {
opacity: 0;
}
}
#target.hidden {
display: none;
opacity: 0;
}
开始样式使用示例
在这个示例中,按下按钮创建一个<div>
元素,赋予其showing
类,并将其添加到DOM中。
showing
被赋予@starting-style
为background-color: red
,并设置过渡目标样式为background-color: blue
。默认的div
规则集包含background-color: yellow
,并且也是设置transition
的地方。
当<div>
首次添加到DOM时,您将看到背景从红色过渡到蓝色。经过一段时间后,我们通过JavaScript从<div>
中移除showing
类。此时,它将从蓝色过渡回黄色,而不是红色。这证明开始样式仅在元素首次渲染到DOM中时使用。一旦它出现,元素就会过渡回设置在其上的默认样式。
在另一个超时后,我们将<div>
完全从DOM中移除,重置示例的初始状态以便可以再次运行。
HTML
<button>Display <code><div></code></button>
CSS
div {
background-color: yellow;
transition: background-color 3s;
}
div.showing {
background-color: skyblue;
}
@starting-style {
div.showing {
background-color: red;
}
}
JavaScript
const btn = document.querySelector("button");
btn.addEventListener("click", () => {
btn.disabled = true;
const divElem = document.createElement("div");
divElem.classList.add("showing");
document.body.append(divElem);
setTimeout(() => {
divElem.classList.remove("showing");
setTimeout(() => {
divElem.remove();
btn.disabled = false;
}, 3000);
}, 3000);
});
结果
代码呈现如下
动画弹出窗口
在这个示例中,一个popover 使用CSS transitions进行动画处理。使用transition
属性提供基本的进入和退出动画。
HTML
HTML包含一个<div>
元素,使用popover属性声明为弹出窗口,以及一个<button>
元素,使用其popovertarget属性指定为弹出窗口的显示控件。
<button popovertarget="mypopover">Show the popover</button>
<div popover="auto" id="mypopover">I'm a Popover! I should animate.</div>
CSS
在这个示例中,我们希望为两个属性设置动画,opacity
和transform
(特别是水平缩放变换),使弹出窗口淡入淡出以及水平伸缩。
html {
font-family: Arial, Helvetica, sans-serif;
}
[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
}
[popover] {
font-size: 1.2rem;
padding: 10px;
/* Final state of the exit animation */
opacity: 0;
transform: scaleX(0);
transition:
opacity 0.7s,
transform 0.7s,
overlay 0.7s allow-discrete,
display 0.7s allow-discrete;
/* Equivalent to
transition: all 0.7s allow-discrete; */
}
/* Include after the [popover]:popover-open rule */
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}
/* Transition for the popover's backdrop */
[popover]::backdrop {
background-color: rgb(0 0 0 / 0%);
transition:
display 0.7s allow-discrete,
overlay 0.7s allow-discrete,
background-color 0.7s;
/* Equivalent to
transition: all 0.7s allow-discrete; */
}
[popover]:popover-open::backdrop {
background-color: rgb(0 0 0 / 25%);
}
/* Nesting (&) is not supported for pseudo-elements
so specify a standalone starting-style block. */
@starting-style {
[popover]:popover-open::backdrop {
background-color: rgb(0 0 0 / 0%);
}
}
为此,我们已为弹出窗口元素的默认隐藏状态(通过[popover]
选择)上的这些属性设置了初始状态,并在弹出窗口的打开状态(通过:popover-open
伪类选择)上设置了结束状态。
然后,我们设置了一个transition
属性来在两个状态之间进行动画。动画的初始状态包含在@starting-style
规则中,以启用进入动画。
因为动画元素在显示时被提升到顶层,并在隐藏时从顶层移除(使用display: none
),所以需要一些额外的步骤来确保动画在两个方向上都能正常工作。
- 将
display
添加到过渡元素列表中,以确保动画元素在进入和退出动画的整个过程中都可见(设置为display: block
或其他可见的display
值)。没有它,退出动画将不可见;实际上,弹出窗口只会消失。请注意,简写形式中也设置了transition-behavior: allow-discrete
值以激活动画。 - 将
overlay
添加到过渡元素列表中,以确保将元素从顶层移除的操作延迟到动画结束。对于像这样的简单动画,这并没有太大的区别,但在更复杂的情况下,不这样做会导致元素过快地从覆盖层中移除,这意味着动画不流畅或无效。同样,在这种情况下,需要transition-behavior: allow-discrete
才能发生动画。
注意:我们还在弹出窗口打开时出现在其后面的::backdrop
上包含了一个过渡,以提供不错的变暗动画。[popover]:popover-open::backdrop
用于在弹出窗口打开时选择背景。
结果
代码呈现如下
注意:因为弹出窗口每次显示时都会从display: none
更改为display: block
,所以弹出窗口每次进入过渡发生时都会从其@starting-style
样式过渡到其[popover]:popover-open
样式。当弹出窗口关闭时,它会从其[popover]:popover-open
状态过渡到默认的[popover]
状态。
在DOM添加和移除时过渡元素
此示例包含一个按钮,当按下该按钮时,它会将新元素追加到<section>
容器中。每个元素依次包含一个嵌套按钮,当按下该按钮时,会移除该元素。此示例演示了如何在将元素添加到或从DOM中移除时使用过渡来为元素设置动画。
HTML
<button>Create new column</button>
<section></section>
JavaScript
JavaScript启用元素的添加和移除
const btn = document.querySelector("button");
const sectionElem = document.querySelector("section");
btn.addEventListener("click", createColumn);
function randomColor() {
function randomNum() {
return Math.floor(Math.random() * 255);
}
return `rgb(${randomNum()} ${randomNum()} ${randomNum()})`;
}
function createColumn() {
const divElem = document.createElement("div");
divElem.style.backgroundColor = randomColor();
const closeBtn = document.createElement("button");
closeBtn.textContent = "✖";
closeBtn.setAttribute("aria-label", "close");
divElem.append(closeBtn);
sectionElem.append(divElem);
closeBtn.addEventListener("click", () => {
divElem.classList.add("fade-out");
setTimeout(() => {
divElem.remove();
}, 1000);
});
}
当单击“创建新列”按钮时,会调用createColumn()
函数。这将创建一个具有随机生成的背景颜色的<div>
元素和一个<button>
元素以关闭<div>
。然后,它将<button>
追加到<div>
,并将<div>
追加到<section>
容器。
然后,我们通过addEventListener
为关闭按钮添加事件侦听器。单击关闭按钮会执行两件事
- 将
fade-out
类添加到<div>
。添加类会触发在该类上设置的退出动画。 - 延迟1000毫秒后移除
<div>
。setTimeout()
将<div>
从DOM中移除(通过Element.remove()
)的操作延迟到动画结束后。
CSS
我们包含一个transition
,它会为每列的opacity
和scale
设置动画,因为它们被添加和移除。
div {
flex: 1;
border: 1px solid gray;
position: relative;
background: linear-gradient(
to right,
rgb(255 255 255 / 0%),
rgb(255 255 255 / 50%)
);
opacity: 1;
scale: 1 1;
transition:
opacity 0.7s,
scale 0.7s,
display 0.7s allow-discrete,
all 0.7s allow-discrete;
/* Equivalent to
transition: all 0.7s allow-discrete; */
}
/* Include after the `div` rule */
@starting-style {
div {
opacity: 0;
scale: 1 0;
}
}
.fade-out {
opacity: 0;
display: none;
scale: 1 0;
}
div > button {
font-size: 1.6rem;
background: none;
border: 0;
text-shadow: 2px 1px 1px white;
border-radius: 15px;
position: absolute;
top: 1px;
right: 1px;
cursor: pointer;
}
为了为每个<div>
的opacity
和scale
设置动画,因为它被添加到DOM中,然后在它从DOM中移除时反转动画,我们
- 在
div { ... }
规则上指定我们要过渡的属性的结束状态。 - 在
@starting-style
块内指定要从其过渡属性的起始状态。 - 在
.fade-out
规则内指定退出动画——这是JavaScript在按下其关闭按钮时分配给<div>
元素的类。除了设置opacity
和scale
的结束状态外,我们还在<div>
上设置了display: none
——我们希望它们在从UI中移除时立即不可用。 - 在
div { ... }
规则内指定transition
列表以对opacity
、scale
和display
进行动画处理。请注意,对于display
,简写形式中也设置了transition-behavior: allow-discrete
值,以便它可以进行动画处理。
结果
最终结果如下所示
规范
规范 |
---|
CSS Transitions Level 2 # defining-before-change-style |
浏览器兼容性
BCD 表格仅在浏览器中加载