@starting-style CSS at-rule

Baseline 2024
Newly available

Since August 2024, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

The @starting-style CSS at-rule is used to define starting values for properties set on an element that you want to transition from when the element receives its first style update, i.e., when an element is first displayed on a previously loaded page.

Syntax

The @starting-style at rule can be used in two ways:

  1. As a standalone block, in which case it contains one or more rulesets defining starting style declarations and selecting the elements they apply to:

    css
    @starting-style {
      /* rulesets */
    }
    
  2. Nested within an existing ruleset, in which case it contains one or more declarations defining starting property values for the elements already selected by that ruleset:

    css
    selector {
      /* existing ruleset */
      /* ... */
    
      @starting-style {
        /* declarations */
      }
    }
    

Description

To avoid unexpected behavior, CSS transitions are by default not triggered on an element's initial style update, or when its display type changes from none to another value. To enable first-style transitions, @starting-style rules are needed. They provide starting styles for elements that do not have a previous state, defining the property values to transition from.

@starting-style is especially useful when creating entry and exit transitions for elements displayed in the top layer (such as popovers and modal <dialog>s), elements that are changing to and from display: none, and elements when first added to or removed from the DOM.

Note: @starting-style is only relevant to CSS transitions. When using CSS animations to implement such effects, @starting-style is not needed. See Using CSS animations for an example.

There are two ways to use @starting-style: as a standalone rule or nested within a ruleset.

Let's consider a scenario where we want to animate a popover when shown (that is, when added to the top layer). The "original rule" specifying the styles for the open popover could look something like this (see the popover example below):

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

To specify the starting values of the popover's properties that will be animated using the first method, you include a standalone @starting-style block in your CSS:

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

Note: The @starting-style at-rule and the "original rule" have the same specificity. To ensure that starting styles get applied, include the @starting-style at-rule after the "original rule". If you specify the @starting-style at-rule before the "original rule", the original styles will override the starting styles.

To specify the starting style for the popover using the nested method, you can nest the @starting-style block inside the "original rule":

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

  @starting-style {
    opacity: 0;
    transform: scaleX(0);
  }
}

When exactly are starting styles used?

It is important to understand that an element will transition from its @starting-style styles when it is first rendered in the DOM, or when it transitions from display: none to a visible value. When it transitions back from its initial visible state, it will no longer use the @starting-style styles as it is now visible in the DOM. Instead, it will transition back to whatever styles exist for that element's default state.

In effect, there are three style states to manage in these situations — starting-style state, transitioned state, and default state. It is possible for the "to" and "from" transitions to be different in such cases. You can see a proof of this in our Demonstration of when starting styles are used example, below.

Formal syntax

@starting-style = 
@starting-style { <rule-list> }

Examples

Basic @starting-style usage

Transition an element's background-color from transparent to green when it is initially rendered:

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

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

Transition the opacity of an element when it changes its display value to or from none:

css
#target {
  transition-property: opacity, display;
  transition-duration: 0.5s;
  display: block;
  opacity: 1;
  @starting-style {
    opacity: 0;
  }
}

#target.hidden {
  display: none;
  opacity: 0;
}

Demonstration of when starting styles are used

In this example, a button is pressed to create a <div> element, give it a class of showing, and add it to the DOM.

showing is given a @starting-style of background-color: red and a style of background-color: blue to transition to. The default div ruleset contains background-color: yellow, and is also where the transition is set.

When the <div> is first added to the DOM, you'll see the background transition from red to blue. After a timeout, we remove the showing class from the <div> via JavaScript. At that point it transitions from blue back to yellow, not red. This proves that the starting styles are only used when the element is first rendered in the DOM. Once it has appeared, the element transitions back to the default style set on it.

After another timeout, we then remove the <div> from the DOM altogether, resetting the initial state of the example so it can be run again.

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);
});

Result

The code renders as follows:

Animating a popover

In this example, a popover is animated using CSS transitions. Basic entry and exit animations are provided using the transition property.

HTML

The HTML contains a <div> element declared as a popover using the popover attribute and a <button> element designated as the popover's display control using its popovertarget attribute.

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