Animace při vstupu elementu do stránky byla dlouho problém. CSS přechody fungovaly jen při změně stavu, ne při prvním vykreslení. Pravidlo @starting-style tento problém řeší.
Problém s animacemi při vstupu
Představte si, že chcete animovat dialog při jeho otevření. S klasickým transition to nefunguje:
dialog {
opacity: 1;
transition: opacity 0.3s;
}
dialog:not([open]) {
opacity: 0;
}
Dialog při otevření neanimuje — prohlížeč ho rovnou vykreslí s opacity: 1. Přechod funguje jen při změně z jednoho stavu do druhého, ne při prvním zobrazení.
Řešení pomocí @starting-style
Pravidlo @starting-style definuje počáteční styl, ze kterého element přechází při prvním vykreslení:
dialog[open] {
opacity: 1;
transition: opacity 0.3s;
@starting-style {
opacity: 0;
}
}
Teď prohlížeč ví, že má začít s opacity: 0 a plynule přejít na opacity: 1.
Syntaxe
Existují dva způsoby zápisu — vnořený a samostatný:
Vnořený zápis
.element {
opacity: 1;
transform: scale(1);
transition: all 0.3s;
@starting-style {
opacity: 0;
transform: scale(0.9);
}
}
Samostatný zápis
.element {
opacity: 1;
transform: scale(1);
transition: all 0.3s;
}
@starting-style {
.element {
opacity: 0;
transform: scale(0.9);
}
}
Vnořený zápis je přehlednější a udržuje související styly pohromadě.
Ukázka
Animovaný tooltip
Tooltip, který se plynule objeví při najetí myší:
Notifikace / Toast
Notifikace, která přijede ze strany:
Animovaná karta
Karta, která se při zobrazení „rozbalí“:
Animovaná karta
Obsah karty s efektem rozbalení a mírného natočení.
Animovaný seznam
Položky seznamu s postupným zobrazením:
- První položka
- Druhá položka
- Třetí položka
- Čtvrtá položka
Zpětná animace (exit)
Pravidlo @starting-style definuje jen vstupní stav. Pro animaci při skrytí musíte definovat výstupní stav pomocí selektoru:
.element {
opacity: 1;
transform: translateY(0);
transition: all 0.3s, display 0.3s allow-discrete;
}
/* Vstupní animace */
.element.is-visible {
display: block;
@starting-style {
opacity: 0;
transform: translateY(-20px);
}
}
/* Výstupní animace */
.element:not(.is-visible) {
opacity: 0;
transform: translateY(20px);
}
Prohlížeč animuje přechod do stavu :not(.is-visible). Vlastnost display se přepne na konci animace, takže element zůstane viditelný po celou dobu přechodu.
Animace vlastnosti display
Vlastnost display není běžně animovatelná. S @starting-style a klíčovým slovem allow-discrete to ale jde:
.tooltip {
display: none;
opacity: 0;
transition:
opacity 0.3s,
display 0.3s allow-discrete;
}
.tooltip.is-visible {
display: block;
opacity: 1;
@starting-style {
opacity: 0;
}
}
Klíčové slovo allow-discrete říká prohlížeči, že má animovat i diskrétní vlastnosti jako display. Prohlížeč přepne display na začátku přechodu (při zobrazení) nebo na konci (při skrytí).
Použití s Popover API
Kombinace @starting-style s Popover API umožňuje animované vyskakovací prvky bez JavaScriptu:
[popover] {
opacity: 1;
transform: scale(1);
transition:
opacity 0.2s,
transform 0.2s,
display 0.2s allow-discrete,
overlay 0.2s allow-discrete;
@starting-style {
opacity: 0;
transform: scale(0.95);
}
}
[popover]:not(:popover-open) {
opacity: 0;
transform: scale(0.95);
}
Vlastnost overlay zajišťuje, že element zůstane v top layer po dobu animace při zavírání.
Animovaný popover
Zavře se kliknutím mimo nebo na Escape.
Animovaný dialog
Jak se to řešilo dříve
Před @starting-style existovalo několik workaroundů:
1. @keyframes animace
Nejběžnější řešení — definovat animaci s explicitním počátkem:
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.element {
animation: fadeIn 0.3s ease-out;
}
Nevýhody:
- Animace běží vždy, i když element už byl viditelný
- Pro exit animaci potřebujete další keyframes a JavaScript
- Složitější správa stavů
2. JavaScript s requestAnimationFrame
Přidání třídy až po vykreslení:
element.style.display = 'block';
requestAnimationFrame(() => {
requestAnimationFrame(() => {
element.classList.add('is-visible');
});
});
Dvojité requestAnimationFrame zajistí, že prohlížeč stihne vykreslit počáteční stav před přidáním třídy.
3. setTimeout hack
element.style.display = 'block';
setTimeout(() => {
element.classList.add('is-visible');
}, 10);
Nevýhody:
- Nespolehlivé — závisí na rychlosti prohlížeče
- Může způsobit probliknutí
- Není deklarativní
Proč je @starting-style lepší
- Čistě v CSS — žádný JavaScript
- Deklarativní — jasně říká „toto je počáteční stav“
- Spolehlivé — prohlížeč garantuje správné pořadí
- Funguje s display — díky
allow-discrete
Rozdíl oproti @keyframes
Pravidlo @starting-style není náhrada za @keyframes. Každý přístup má své využití:
| @starting-style | @keyframes | |
|---|---|---|
| Použití | Vstupní přechody | Komplexní animace |
| Kroky | Jeden (počátek → konec) | Libovolný počet |
| Opakování | Ne | Ano |
| Výstupní animace | Přes :not() selektor | Přes animation-direction |
Pro jednoduché přechody při zobrazení je @starting-style čistší řešení. Pro složitější animace s více kroky použijte @keyframes.
Podpora v prohlížečích
Pravidlo @starting-style podporují:
- Chrome od verze 117
- Edge od verze 117
- Safari od verze 17.5
- Firefox od verze 129
Pro starší prohlížeče element jednoduše nebude animovaný — zobrazí se okamžitě. Přijatelná degradace.
Tipy
- Používejte vnořený zápis — je přehlednější a souvisí s CSS Nesting
- Nezapomeňte na allow-discrete při animaci
display - Přidejte overlay pro elementy v top layer (dialogy, popovers)
- Definujte i výstupní stav pomocí
:not([open])nebo podobného selektoru
Odkazy
Související články
Možnosti stylování <iframe>
Co lze a nelze u <iframe> ovlivnit pomocí CSS a jak na změnu textu nebo barev.
