Spec-Zone.ru › CSS

`@starting-style` CSS at-rule

Базовая поддержка Новая возможность

Эта возможность поддерживается в последних версиях устройств и браузеров. Она может не работать на старых устройствах и в старых версиях браузеров. Поддержка во всех браузерах появилась в августе 2024 года.

Правило @starting-style CSS at-rule используется для задания начальных значений свойств элемента, от которых должен выполняться переход при первом обновлении его стилей, то есть когда элемент впервые отображается на уже загруженной странице.

Синтаксис

Правило @starting-style можно использовать двумя способами:

  1. Как самостоятельный блок, содержащий один или несколько наборов правил, которые задают начальные стили и выбирают элементы, к которым они применяются:

    @starting-style {
      /* rulesets */
    }
    
  2. Вложить в существующий набор правил. В этом случае оно содержит одно или несколько объявлений, задающих начальные значения свойств для элементов, уже выбранных этим набором правил:

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

Описание

Чтобы избежать неожиданного поведения, CSS-переходы по умолчанию не запускаются при первоначальном обновлении стилей элемента или при изменении типа display с none на другое значение. Для включения переходов при первом обновлении стилей нужны правила @starting-style. Они задают начальные стили для элементов, у которых нет предыдущего состояния, и определяют значения свойств, с которых начинается переход.

@starting-style особенно полезно при создании переходов появления и исчезновения для элементов, отображаемых в верхнем слое (например, всплывающих окон и модальных <dialog>), элементов, которые переключаются в display: none и обратно, а также элементов, которые впервые добавляются в DOM или удаляются из него.

Примечание: @starting-style имеет значение только для CSS-переходов. При использовании CSS-анимаций для создания таких эффектов @starting-style не требуется. Пример см. в разделе Использование CSS-анимаций.

Использовать @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 и «исходное правило» имеют одинаковую специфичность. Чтобы начальные стили применялись, добавьте правило @starting-style после «исходного правила». Если указать правило @starting-style перед «исходным правилом», исходные стили переопределят начальные.

Чтобы задать начальный стиль всплывающего окна вложенным способом, можно поместить блок @starting-style внутрь «исходного правила»:

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

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

Когда именно используются начальные стили?

Важно понимать, что при первой отрисовке элемента в DOM или при переходе от @starting-style к видимому значению выполняется переход от его стилей display: none. При переходе обратно из первоначального видимого состояния стили @starting-style больше не используются, поскольку элемент уже виден в DOM. Вместо этого выполняется переход к стилям, заданным для состояния элемента по умолчанию.

В таких ситуациях фактически нужно управлять тремя состояниями стилей: начальным, состоянием после перехода и состоянием по умолчанию. В подобных случаях переходы «к» и «от» могут различаться. Это можно увидеть в приведённом ниже примере «Демонстрация использования начальных стилей».

Формальный синтаксис

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

Примеры

Базовое использование @starting-style

При первой отрисовке элемента выполните переход его background-color от прозрачного к зелёному:

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

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

Выполните переход opacity элемента при изменении его значения display на none или обратно:

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

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

Демонстрация использования начальных стилей

В этом примере нажмите кнопку, чтобы создать элемент <div>, задать ему class со значением showing и добавить его в DOM.

Для showing задаётся @starting-style со значением background-color: red и стиль background-color: blue, к которому выполняется переход. Набор правил div по умолчанию содержит background-color: yellow; здесь же задаётся transition.

Когда <div> впервые добавляется в DOM, цвет фона меняется с красного на синий. По истечении времени мы удаляем класс showing из <div> с помощью JavaScript. В этот момент цвет меняется с синего обратно на жёлтый, а не на красный. Это доказывает, что начальные стили используются только при первой отрисовке элемента в DOM. После появления элемента выполняется переход обратно к заданному для него стилю по умолчанию.

По истечении ещё одного промежутка времени мы полностью удаляем <div> из DOM, сбрасывая исходное состояние примера, чтобы его можно было запустить снова.

HTML

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

CSS

div {
  width: 200px;
  height: 100px;
  border: 1px solid black;
  margin-top: 10px;
}

div::after {
  content: "class: " attr(class);
  position: relative;
  top: 3px;
  left: 3px;
}
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);
});

Результат

Код отображается следующим образом:

Анимация всплывающего окна

В этом примере для анимации всплывающего окна используются CSS-переходы. Базовые анимации появления и исчезновения задаются с помощью свойства 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: "Helvetica", "Arial", 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: transparent;
  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: transparent;
  }
}

Для этого мы задали начальное состояние этих свойств для скрытого по умолчанию состояния элемента всплывающего окна (выбранного с помощью [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> — см. раздел Переходы для элементов dialog.

Переходы при добавлении элементов в 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 randomBackground() {
  function randomNum() {
    return Math.floor(Math.random() * 255);
  }
  const baseColor = `${randomNum()} ${randomNum()} ${randomNum()}`;

  return `linear-gradient(to right, rgb(${baseColor} / 0), rgb(${baseColor} / 0.5))`;
}

function createColumn() {
  const divElem = document.createElement("div");
  divElem.style.background = randomBackground();

  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() мы добавляем обработчик события для кнопки закрытия. При её нажатии выполняются два действия:

  • К <div> добавляется класс fade-out. Добавление класса запускает заданную для него анимацию исчезновения.
  • Через 1000 мс удаляется <div>. Метод setTimeout() откладывает удаление <div> из DOM (с помощью Element.remove()) до окончания анимации.

CSS

Мы задаём свойство transition, которое анимирует opacity и scale каждого столбца при его добавлении и удалении:

html * {
  box-sizing: border-box;
  font-family: sans-serif;
}

body {
  margin: 0;
  display: flex;
  flex-direction: column;
  height: 100vh;
  gap: 10px;
}

body > button {
  margin: 10px 10px 0 10px;
}

section {
  display: flex;
  flex: 1;
  gap: 10px;
  margin: 10px;
}
div {
  flex: 1;
  border: 1px solid gray;
  position: relative;
  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;
}

Чтобы анимировать opacity и scale каждого <div> при добавлении в DOM и обратить анимацию при удалении из DOM, мы:

  • Задаём конечное состояние свойств, для которых нужен переход, в правиле div { ... }.
  • Задаём начальное состояние, из которого будут переходить свойства, внутри блока @starting-style.
  • Задаём анимацию исчезновения в правиле .fade-out — JavaScript назначает этот класс элементам <div> при нажатии кнопок закрытия. Помимо задания конечных состояний opacity и scale, мы также задаём для <div> свойство display: none — после удаления из интерфейса элементы должны сразу становиться недоступными.
  • Указываем список свойств transition внутри правила div { ... }, чтобы анимировать opacity, scale и display. Обратите внимание, что для display значение transition-behavior: allow-discrete также задаётся в сокращённой записи, чтобы это свойство анимировалось.

Результат

Итоговый результат выглядит так:

Спецификации

Спецификация
Модуль CSS Transitions уровня 2
# defining-before-change-style

Совместимость с браузерами

Настольные Мобильные
Chrome Edge Firefox Opera Safari Chrome для Android Firefox для Android Opera для Android Safari на iOS Samsung Internet WebView для Android WebView на iOS
starting-style
117
117
129
103
17.5
117
129
78
17.5
24.0
117
17.5

См. также

  • Модуль CSS-переходы
  • overlay
  • transition-behavior
  • CSSStartingStyleRule
  • Четыре новые возможности CSS для плавной анимации появления и исчезновения на developer.chrome.com (2023)

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@starting-style

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API