@starting-style

可用性有限

此功能不是基线功能,因为它在一些最广泛使用的浏览器中无法工作。

**@starting-style** CSS at 规则 用于定义应用于元素的属性的起始值,当元素收到其第一个样式更新时,您希望从这些值过渡,即当元素首次显示在先前加载的页面上时。

语法

@starting-style at 规则可以通过两种方式使用

  1. 作为独立块,在这种情况下,它包含一个或多个规则集,定义起始样式声明并选择它们应用的元素
    css
    @starting-style {
      rulesets
    }
    
  2. 嵌套在现有的规则集中,在这种情况下,它包含一个或多个声明,定义已由该规则集选择的元素的起始属性值
    css
    selector { /* existing ruleset */
      /* ... */
    
      @starting-style {
        declarations
      }
    }
    

描述

为了避免意外行为,CSS 过渡 在默认情况下不会在元素的初始样式更新时触发,或者当其display 类型从 none 更改为其他值时。若要启用第一个样式过渡,需要 @starting-style 规则。它们为没有先前状态的元素提供起始样式,定义要从中过渡的属性值。

@starting-style 在创建显示在顶层(例如 弹出窗口 和模态 <dialog>)、从 display: none 更改为和从 display: none 更改为的元素以及首次添加到或从 DOM 中移除的元素的进入和退出过渡时特别有用。

注意:@starting-style 仅与 CSS 过渡相关。当使用CSS 动画 来实现此类效果时,不需要 @starting-style。请参阅使用 CSS 动画 以获取示例。

使用 @starting-style 有两种方法:作为独立规则或嵌套在规则集中。

让我们考虑一个场景,我们希望在显示(即添加到顶层)时为 弹出窗口 设置动画。指定打开的弹出窗口样式的“原始规则”可能如下所示(请参见下面的弹出窗口示例

css
[popover]:popover-open {
  opacity: 1;
  transform: scaleX(1);
}

若要使用第一种方法指定弹出窗口将要使用动画的属性的起始值,请在 CSS 中包含一个独立的 @starting-style

css
@starting-style {
  [popover]:popover-open {
    opacity: 0;
    transform: scaleX(0);
  }
}

注意:@starting-style at 规则和“原始规则”具有相同的特异性。若要确保应用起始样式,请将 @starting-style at 规则放在“原始规则”之后。如果在“原始规则”之前指定 @starting-style at 规则,则原始样式将覆盖起始样式。

若要使用嵌套方法指定弹出窗口的起始样式,可以在“原始规则”内嵌套 @starting-style

css
[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从透明过渡到绿色。

css
#target {
  transition: background-color 1.5s;
  background-color: green;
}

@starting-style {
  #target {
    background-color: transparent;
  }
}

当元素的display值切换到或从none时,过渡元素的opacity

css
#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-stylebackground-color: red,并设置过渡目标样式为background-color: blue。默认的div规则集包含background-color: yellow,并且也是设置transition的地方。

<div>首次添加到DOM时,您将看到背景从红色过渡到蓝色。经过一段时间后,我们通过JavaScript从<div>中移除showing类。此时,它将从蓝色过渡回黄色,而不是红色。这证明开始样式仅在元素首次渲染到DOM中时使用。一旦它出现,元素就会过渡回设置在其上的默认样式。

在另一个超时后,我们将<div>完全从DOM中移除,重置示例的初始状态以便可以再次运行。

HTML

html
<button>Display <code>&lt;div&gt;</code></button>

CSS

css
div {
  background-color: yellow;
  transition: background-color 3s;
}

div.showing {
  background-color: skyblue;
}

@starting-style {
  div.showing {
    background-color: red;
  }
}

JavaScript

js
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属性指定为弹出窗口的显示控件。

html
<button popovertarget="mypopover">Show the popover</button>
<div popover="auto" id="mypopover">I'm a Popover! I should animate.</div>

CSS

在这个示例中,我们希望为两个属性设置动画,opacitytransform(特别是水平缩放变换),使弹出窗口淡入淡出以及水平伸缩。

css
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]状态。

注意:您可以在<dialog>参考页面上找到一个示例,该示例演示了如何在显示和隐藏<dialog>元素及其背景时对其进行过渡——请参见过渡对话框元素

在DOM添加和移除时过渡元素

此示例包含一个按钮,当按下该按钮时,它会将新元素追加到<section>容器中。每个元素依次包含一个嵌套按钮,当按下该按钮时,会移除该元素。此示例演示了如何在将元素添加到或从DOM中移除时使用过渡来为元素设置动画。

HTML

html
<button>Create new column</button>
<section></section>

JavaScript

JavaScript启用元素的添加和移除

js
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,它会为每列的opacityscale设置动画,因为它们被添加和移除。

css
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>opacityscale设置动画,因为它被添加到DOM中,然后在它从DOM中移除时反转动画,我们

  • div { ... }规则上指定我们要过渡的属性的结束状态。
  • @starting-style块内指定要从其过渡属性的起始状态。
  • .fade-out规则内指定退出动画——这是JavaScript在按下其关闭按钮时分配给<div>元素的类。除了设置opacityscale的结束状态外,我们还在<div>上设置了display: none——我们希望它们在从UI中移除时立即不可用。
  • div { ... }规则内指定transition列表以对opacityscaledisplay进行动画处理。请注意,对于display,简写形式中也设置了transition-behavior: allow-discrete值,以便它可以进行动画处理。

结果

最终结果如下所示

规范

规范
CSS Transitions Level 2
# defining-before-change-style

浏览器兼容性

BCD 表格仅在浏览器中加载

另请参阅