Zmienne CSS – dlaczego jest to ważne?

Zmienne CSS, czyli inaczej niestandardowe właściwości CSS, są dostępne w Chrome 49. Mogą one pomóc w ograniczaniu powtórzeń w CSS, a także w przypadku poważnych efektów działania w czasie działania, takich jak przełączanie motywów czy rozszerzanie/polyfilling przyszłych funkcji CSS.

Zatłoczenie CSS

Przy projektowaniu aplikacji często umieszcza się zestaw kolorów marki, których można użyć ponownie, aby zachować spójność w wyglądzie aplikacji. Niestety ciągłe powtarzanie tych wartości kolorów w CSS jest nie tylko pracochłonne, ale też podatne na błędy. Jeśli w którymś momencie trzeba będzie zmienić jeden z kolorów, możesz rzucać ostrożność i znajdować i zastąpić wszystkie elementy, ale przy odpowiednio dużym projekcie może to łatwo stać się niebezpiecznym.

W ostatnim czasie wielu programistów korzystało z rozwiązań do wstępnego przetwarzania kodu CSS, np. SASS lub LESS, które rozwiązują ten problem przez zastosowanie zmiennych preprocesorów. Narzędzia te znacznie zwiększyły produktywność programistów, ale ich poważną wadą jest to, że są statyczne i nie można ich zmieniać w czasie działania. Dodanie możliwości zmieniania zmiennych w czasie działania nie tylko otwiera dostęp do dynamicznych motywów aplikacji, ale ma też poważne konsekwencje dla elastycznego projektowania stron i potencjalnie uzupełniania przyszłych funkcji CSS. W Chrome 49 funkcje te są teraz dostępne w postaci niestandardowych właściwości CSS.

Właściwości niestandardowe w pigułce

Właściwości niestandardowe dodają do naszego zestawu narzędzi CSS dwie nowe funkcje:

  • Możliwość przypisania przez autora dowolnych wartości do właściwości o nazwie wybranej przez autora.
  • Funkcja var(), która umożliwia autorowi używanie tych wartości w innych właściwościach.

Oto krótki przykład, który obrazuje,

:root {
    --main-color: #06c;
}

#foo h1 {
    color: var(--main-color);
}

--main-color to zdefiniowana przez autora właściwość niestandardowa o wartości #06c. Pamiętaj, że wszystkie właściwości niestandardowe zaczynają się od dwóch łączników.

Funkcja var() pobiera i zastępuje się wartością właściwości niestandardowej, co daje color: #06c;, o ile jest zdefiniowana w jakimś miejscu w arkuszu stylów, powinna być dostępna dla funkcji var.

Składnia może na początku wyglądać dziwnie. Wielu deweloperów pyta, dlaczego używać $foo tylko do nazw zmiennych. Zostało wybrane tak, aby było jak najbardziej elastyczne i umożliwiło wprowadzenie w przyszłości makr $foo. Więcej informacji na ten temat znajdziesz w tym poście autorstwa jednego z autorów specyfikacji – Tab Atkinsa.

Składnia właściwości niestandardowej

Składnia właściwości niestandardowej jest prosta.

--header-color: #06c;

Pamiętaj, że w właściwościach niestandardowych rozróżniana jest wielkość liter, więc --header-color i --Header-Color to różne właściwości niestandardowe. Choć z pozoru właściwości te mogą wydawać się proste, w rzeczywistości dozwolona składnia właściwości niestandardowych jest dość mało rygorystyczna. Na przykład taka właściwość niestandardowa:

--foo: if(x > 5) this.width = 10;

Nie przydaje się to jako zmienna, ponieważ jest nieprawidłowa w przypadku żadnej normalnej właściwości, ale może się okazać odczytywana i wykonywana za pomocą JavaScriptu podczas działania. Oznacza to, że właściwości niestandardowe mogą otworzyć wszystkie rodzaje ciekawych technik, które nie są obecnie dostępne w przypadku współczesnych preprocesorów CSS. Jeśli myślisz: „ziewam, mam stuprocentowo dobry wybór, więc komu to obchodzi...”, przyjrzyj się temu jeszcze raz. Nie są to zmienne, z którymi pracujesz.

Wodospad

Właściwości niestandardowe są zgodne ze standardowymi regułami kaskadowymi, dzięki czemu możesz definiować tę samą usługę na różnych poziomach szczegółowości

:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id="alert">
    While I got red set directly on me!
    <p>I’m red too, because of inheritance!</p>
</div>

Oznacza to, że możesz używać w zapytaniach o multimedia właściwości niestandardowych, aby ułatwić sobie elastyczne projektowanie. Jednym z przypadków użycia może być zwiększenie marginesów wokół głównych elementów sekcji wraz ze wzrostem rozmiaru ekranu:

:root {
    --gutter: 4px;
}

section {
    margin: var(--gutter);
}

@media (min-width: 600px) {
    :root {
    --gutter: 16px;
    }
}

Trzeba pamiętać, że powyższy fragment kodu nie jest możliwy przy użyciu współczesnych preprocesorów CSS, które nie potrafią definiować zmiennych w zapytaniach multimedialnych. Właśnie dzięki tej umiejętności masz duży potencjał.

Możesz też mieć właściwości niestandardowe, które czerpią wartości z innych właściwości niestandardowych. Ta opcja jest bardzo przydatna do tworzenia motywów:

:root {
    --primary-color: red;
    --logo-text: var(--primary-color);
}

Funkcja var()

Aby pobrać i użyć wartości właściwości niestandardowej, musisz użyć funkcji var(). Składnia funkcji var() wygląda tak:

var(<custom-property-name> [, <declaration-value> ]? )

Gdzie <custom-property-name> to nazwa właściwości niestandardowej zdefiniowanej przez autora, np. --foo, a <declaration-value> to wartość zastępcza do użycia, gdy wspomniana właściwość niestandardowa jest nieprawidłowa. Wartości zastępcze mogą mieć postać listy rozdzielanej przecinkami, które zostaną połączone w jedną wartość. Na przykład var(--font-stack, "Roboto", "Helvetica"); definiuje wartość zastępczą "Roboto", "Helvetica". Zwróć uwagę, że krótkie wartości, takie jak używane przy marginesach i dopełnieniu, nie są rozdzielone przecinkami, więc odpowiednia wartość zastępcza dopełnienia będzie wyglądać tak.

p {
    padding: var(--pad, 10px 15px 20px);
}

Korzystając z tych wartości zastępczych, autor komponentu może utworzyć style obronne swojego elementu:

/* In the component’s style: */
.component .header {
    color: var(--header-color, blue);
}
.component .text {
    color: var(--text-color, black);
}

/* In the larger application’s style: */
.component {
    --text-color: #080;
    /* header-color isn’t set,
        and so remains blue,
        the fallback value */
}

Ta metoda jest szczególnie przydatna w przypadku tworzenia zestawień komponentów sieciowych, które korzystają z funkcji Shadow DOM, ponieważ właściwości niestandardowe mogą przemierzać granice cieni. Autor komponentu internetowego może utworzyć początkowy projekt, używając wartości zastępczych, i udostępnić „haki” w postaci właściwości niestandardowych.

<!-- In the web component's definition: -->
<x-foo>
    #shadow
    <style>
        p {
        background-color: var(--text-background, blue);
        }
    </style>
    <p>
        This text has a yellow background because the document styled me! Otherwise it
        would be blue.
    </p>
</x-foo>
/* In the larger application's style: */
x-foo {
    --text-background: yellow;
}

Podczas korzystania z usługi var() trzeba uważać na pewne kwestie. Zmienne nie mogą być nazwami właściwości. Przykład:

.foo {
    --side: margin-top;
    var(--side): 20px;
}

Nie jest to jednak równoważne z ustawionym margin-top: 20px;. Druga deklaracja jest nieprawidłowa i jest zwracana jako błąd.

Nie możesz też (naturalnie) tworzyć wartości, gdy jej część jest dostarczana przez zmienną:

.foo {
    --gap: 20;
    margin-top: var(--gap)px;
}

Również w tym przypadku nie jest to równoważne z ustawionym margin-top: 20px;. Do budowania wartości potrzebujesz czegoś innego: funkcji calc().

Tworzenie wartości za pomocą funkcji calc()

Jeśli nie korzystasz jeszcze z funkcji calc(), możesz skorzystać z niewielkiego narzędzia służącego do wykonywania obliczeń w celu określenia wartości CSS. Jest obsługiwana przez wszystkie nowoczesne przeglądarki i można ją łączyć z właściwościami niestandardowymi, aby tworzyć nowe wartości. Na przykład:

.foo {
    --gap: 20;
    margin-top: calc(var(--gap) * 1px); /* niiiiice */
}

Praca z właściwościami niestandardowymi w języku JavaScript

Aby uzyskać wartość właściwości niestandardowej w czasie działania, użyj metody getPropertyValue() obliczonego obiektu CSSStyleDefinitionation.

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>I’m a red paragraph!</p>
/* JS */
var styles = getComputedStyle(document.documentElement);
var value = String(styles.getPropertyValue('--primary-color')).trim();
// value = 'red'

I podobnie, aby ustawić wartość właściwości niestandardowej w czasie działania, użyj metody setProperty() obiektu CSSStyleDeclaration.

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>Now I’m a green paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'green');

Możesz też ustawić wartość właściwości niestandardowej w taki sposób, aby odwoływała się do innej właściwości niestandardowej w czasie działania, używając funkcji var() w wywołaniu funkcji setProperty().

/* CSS */
:root {
    --primary-color: red;
    --secondary-color: blue;
}
<!-- HTML -->
<p>Sweet! I’m a blue paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'var(--secondary-color)');

Właściwości niestandardowe mogą odnosić się do innych właściwości niestandardowych w arkuszach stylów, więc możesz sobie wyobrazić, jak mogłoby to prowadzić do różnych ciekawych efektów działania.

Obsługiwane przeglądarki

Obecnie Chrome 49, Firefox 42, Safari 9.1 oraz iOS Safari 9.3 obsługują właściwości niestandardowe.

Pokaz

Zapoznaj się z przykładem, aby poznać wszystkie interesujące techniki dostępne obecnie dzięki właściwościom niestandardowym.

Więcej informacji

Jeśli chcesz dowiedzieć się więcej o właściwościach niestandardowych, Philip Walton z zespołu Google Analytics napisał w skrócie, dlaczego ceni sobie właściwości niestandardowe. Możesz śledzić ich postępy na stronie chromestatus.com w innych przeglądarkach.