Reguła CSSReguły @

@property

Rejestruje zmienną CSS z typem, wartością początkową i zasadą dziedziczenia. Taką zmienną można płynnie animować, np. kąt gradientu.

Na tej stronie

Przykład

#
CSS
@property --angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.card {
  border: 3px solid transparent;
  border-radius: 14px;
  background:
    linear-gradient(#18181b, #18181b) padding-box,
    conic-gradient(from var(--angle), #7c3aed, #0ea5e9, #10b981, #7c3aed) border-box;
  animation: spin 4s linear infinite;
}

@keyframes spin {
  to { --angle: 360deg; }
}
Podgląd

Definicja i zastosowanie

#

Zwykła zmienna CSS (--nazwa) jest dla przeglądarki tylko ciągiem znaków. Przeglądarka nie wie, czy --kat: 45deg to kąt, więc nie potrafi wyliczyć wartości pośrednich i przy animacji zmienia ją skokowo. Reguła @property rejestruje zmienną z konkretnym typem, a wtedy przeglądarka traktuje ją jak prawdziwą właściwość.

Rejestracja ma trzy deskryptory. syntax określa typ, np. "<angle>", "<color>", "<length>", "<number>", "<integer>" lub "<percentage>", a "*" oznacza dowolną wartość. inherits mówi, czy potomkowie dziedziczą wartość. initial-value to wartość domyślna, wymagana dla każdego typu poza "*". Musi być niezależna od kontekstu, więc nie może to być np. 2em. Deskryptory syntax i inherits są obowiązkowe.

Największa korzyść to animacje. W większości przeglądarek zamiana jednego gradientu na drugi następuje skokowo, ale można animować zarejestrowaną zmienną, której gradient używa: kąt w conic-gradient(), pozycję koloru albo sam kolor. Liczba typu <integer> połączona z licznikiem CSS może nawet płynnie odliczać od 0 do 100.

Zmienną można też zarejestrować z JavaScriptu przez CSS.registerProperty(). Typ działa przy okazji jak zabezpieczenie: wartość niezgodna z typem, np. liczba w zmiennej typu <color>, zostaje odrzucona i zmienna przyjmuje wartość początkową albo odziedziczoną.

Składnia

#
Składnia
@property --nazwa {
  syntax: "<typ>";
  inherits: true | false;
  initial-value: <wartość>;
}

Deskryptory i typy

#
  • syntax: "<percentage>"

    pasek wypełnia się płynnie

    Zmienna --p ustawia miejsce, w którym kończy się zielony kolor gradientu. Dzięki rejestracji z typem procentowym pasek wypełnia się płynnie.
  • bez @property

    pasek skacze

    Ta sama animacja bez rejestracji. Przeglądarka nie zna typu zmiennej, więc zamiast wartości pośrednich przełącza ją w połowie czasu z 0% na 100%.
  • syntax: "<angle>"

    obracający się gradient

    Zmienna z kątem steruje punktem startowym gradientu stożkowego (from var(--angle)). Animacja kąta od 0 do 360 stopni daje obracający się pierścień.
  • syntax: "<integer>"

    licznik od 0 do 100

    Liczba całkowita przekazana do licznika CSS (counter-reset) i wyświetlona przez content. Animacja liczy płynnie od 0 do 100.
  • syntax: "<color>"

    kolor w gradiencie

    Samego gradientu zwykle nie przejdziesz płynnie, ale kolor zapisany w zarejestrowanej zmiennej już tak. Lewy koniec przechodzi z fioletu w bursztyn.
  • inherits: false

    dziecko nie dziedziczy

    Rodzic ustawia --accent na zielony i ma zieloną ramkę, ale dziecko tej wartości nie dziedziczy. Dostaje wartość początkową, czyli szary. Zwykła zmienna bez rejestracji byłaby u dziecka zielona.
  • initial-value

    wartość, gdy nic nie ustawiono

    Zmiennej --radius nikt nie ustawił, a mimo to ma wartość 24px z initial-value. Bez rejestracji var(--radius) nie miałoby czego wstawić i zaokrąglenie by zniknęło.

Deskryptory i typy w praktyce

#

syntax: "<percentage>"

Zmienna --p ustawia miejsce, w którym kończy się zielony kolor gradientu. Dzięki rejestracji z typem procentowym pasek wypełnia się płynnie.
@property --p {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

.bar {
  animation: fill 2s infinite alternate;
}
@keyframes fill { to { --p: 100%; } }

bez @property

Ta sama animacja bez rejestracji. Przeglądarka nie zna typu zmiennej, więc zamiast wartości pośrednich przełącza ją w połowie czasu z 0% na 100%.
.bar {
  animation: fill 2s infinite alternate;
}
@keyframes fill { to { --p: 100%; } }

syntax: "<angle>"

Zmienna z kątem steruje punktem startowym gradientu stożkowego (from var(--angle)). Animacja kąta od 0 do 360 stopni daje obracający się pierścień.
@property --angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.ring {
  animation: turn 2.5s linear infinite;
}
@keyframes turn { to { --angle: 360deg; } }

syntax: "<integer>"

Liczba całkowita przekazana do licznika CSS (counter-reset) i wyświetlona przez content. Animacja liczy płynnie od 0 do 100.
@property --n {
  syntax: "<integer>";
  inherits: false;
  initial-value: 0;
}

.count {
  counter-reset: n var(--n);
  animation: count 3s infinite alternate;
}
@keyframes count { to { --n: 100; } }

syntax: "<color>"

Samego gradientu zwykle nie przejdziesz płynnie, ale kolor zapisany w zarejestrowanej zmiennej już tak. Lewy koniec przechodzi z fioletu w bursztyn.
@property --c {
  syntax: "<color>";
  inherits: false;
  initial-value: #7c3aed;
}

.swatch {
  animation: tint 2s infinite alternate;
}
@keyframes tint { to { --c: #f59e0b; } }

inherits: false

Rodzic ustawia --accent na zielony i ma zieloną ramkę, ale dziecko tej wartości nie dziedziczy. Dostaje wartość początkową, czyli szary. Zwykła zmienna bez rejestracji byłaby u dziecka zielona.
@property --accent {
  syntax: "<color>";
  inherits: false;
  initial-value: #52525b;
}

.parent {
  --accent: #10b981;
  border: 3px solid var(--accent);
}
.child { background: var(--accent); }

initial-value

Zmiennej --radius nikt nie ustawił, a mimo to ma wartość 24px z initial-value. Bez rejestracji var(--radius) nie miałoby czego wstawić i zaokrąglenie by zniknęło.
@property --radius {
  syntax: "<length>";
  inherits: false;
  initial-value: 24px;
}

.tile { border-radius: var(--radius); }

Więcej przykładów

#
Przycisk wypełniany po najechaniu
CSS
@property --fill {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

.btn {
  background: linear-gradient(90deg, #7c3aed var(--fill), #27272a var(--fill));
  transition: --fill 0.4s ease-out;
}

.btn:hover {
  --fill: 100%;
}
Podgląd

Najedź kursorem na przycisk. Zarejestrowaną zmienną można przejść także przez zwykłe transition, a nie tylko animację @keyframes.

Rejestracja z JavaScriptu
JavaScript
CSS.registerProperty({
  name: '--angle',
  syntax: '<angle>',
  inherits: false,
  initialValue: '0deg'
})

Działa tak samo jak reguła @property. Przydaje się, gdy zmienne rejestruje biblioteka albo gdy typ zależy od danych w skrypcie.

Obsługa przeglądarek

#

Nowość w przeglądarkach · od 2024 roku

Działa w aktualnych wersjach wszystkich głównych przeglądarek. Starsze wersje mogą tego nie obsługiwać.

  • Chrome
  • Edge
  • Firefox
  • Safari

Dobre praktyki

#
  • Rejestruj tylko zmienne, które animujesz albo którym chcesz nadać typ. Zwykłe zmienne z kolorami motywu i odstępami rejestracji nie potrzebują.
  • Zmienne do animacji rejestruj z inherits: false. Przeglądarka nie musi wtedy przeliczać ich wartości we wszystkich potomkach.
  • Zadbaj o sensowny wygląd bez animacji. Starsza przeglądarka bez obsługi @property zmieni zmienną skokowo, ale gradient nadal się wyświetli.

Powiązane hasła

#

Widzisz błąd albo brakuje przykładu? Napisz do nas.