Zmienne CSS – dlaczego jest to ważne?

Zmienne CSS, czyli właściwości niestandardowe CSS, trafiają w Chrome 49. Mogą one służyć do zmniejszania powtórzeń w CSS-ie, a także do tworzenia zaawansowanych efektów w czasie wykonywania, takich jak przełączanie motywów czy potencjalne rozszerzanie lub wypełnianie przyszłych funkcji CSS.

Zaśmiecanie kodu CSS

Podczas projektowania aplikacji warto zarezerwować zestaw kolorów marki, które będą używane wielokrotnie, aby zachować spójność wyglądu aplikacji. Niestety powtarzanie tych wartości kolorów w CSS jest nie tylko uciążliwe, ale też może powodować błędy. Jeśli w którymś momencie trzeba będzie zmienić jeden z kolorów, będzie można śmiało ostrzec wiatrem i „znajdź i zamień”, ale w przypadku wystarczająco dużego projektu może to być niebezpieczne.

Ostatnio wielu deweloperów zaczęło używać preprocesorów CSS, takich jak SASS czy LESS, które rozwiązują ten problem dzięki zmiennym preprocesora. Chociaż te narzędzia znacznie zwiększyły produktywność programistów, używane w nich zmienne mają poważną wadę: są statyczne i nie można ich zmienić w czasie działania. Dodanie możliwości zmiany zmiennych w czasie wykonywania kodu nie tylko umożliwia tworzenie dynamicznych motywów aplikacji, ale też ma duże znaczenie dla projektowania responsywnego i możliwości wypełniania przyszłych funkcji CSS. Wraz z wydaniem Chrome 49 te funkcje są dostępne w postaci właściwości niestandardowych w CSS.

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

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

  • Możliwość przypisania przez autora dowolnych wartości do właściwości o wybranej przez niego nazwie.
  • Funkcja var(), która pozwala autorowi używać tych wartości w innych usługach.

Oto krótki przykład:

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

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

--main-color to zdefiniowana przez autora właściwość niestandardowa o wartości #06c. Uwaga: wszystkie właściwości niestandardowe zaczynają się od dwóch myślników.

Funkcja var() pobiera wartość właściwości niestandardowej i zastępuje ją wartością właściwości niestandardowej. W efekcie color: #06c; właściwość niestandardowa jest zdefiniowana w dowolnym miejscu w arkuszu stylów, więc powinna być dostępna dla funkcji var.

Składnia może na początku wyglądać trochę dziwnie. Wielu programistów zadaje pytanie: „Dlaczego nie używać nazwy $foo tylko do nazw zmiennych?”. Wybrano to podejście, aby było jak najbardziej elastyczne i potencjalnie umożliwiało używanie makr $foo w przyszłości. Aby poznać historię, przeczytaj ten post autorstwa Tab Atkins, jednej z autorów specyfikacji.

Składnia właściwości niestandardowych

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ć może się to wydawać proste w odniesieniu do wartości twarzy, dopuszczalna składnia właściwości niestandardowych jest w rzeczywistości dość mało restrykcyjna. Oto przykład prawidłowej właściwości niestandardowej:

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

Nie jest ona przydatna jako zmienna, ponieważ jest nieprawidłowa w przypadku zwykłych właściwości, ale może być odczytywana i używana w JavaScript w czasie wykonywania. Oznacza to, że właściwości niestandardowe mogą odblokować różne interesujące techniki, które nie są obecnie możliwe w ramach obecnych preprocesorów CSS. Jeśli więc myślisz „Yawn Mam SASS, więc kogo to obchodzi…”, spójrz jeszcze raz. Nie są to zmienne, z którymi często pracujesz.

Kaskada

Właściwości niestandardowe podlegają standardowym regułom kaskadowym, więc możesz zdefiniować tę samą właściwość 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 wykorzystywać właściwości niestandardowe w zapytaniach o media, aby ułatwić elastyczne projektowanie stron. Jednym z takich przypadków może być zwiększanie marginesu 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;
    }
}

Należy pamiętać, że powyższy fragment kodu nie jest możliwy do użycia w obecnych preprocesorach CSS, które nie mogą definiować zmiennych w zapytaniach o media. Wykorzystując tę umiejętność, masz duży potencjał.

Możesz też mieć właściwości niestandardowe, których wartości pochodzą z innych właściwości niestandardowych. Może to być bardzo przydatne podczas projektowania:

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

Funkcja var()

Aby pobrać wartość właściwości niestandardowej i z niej korzystać, 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, która jest używana, gdy odwołana właściwość niestandardowa jest nieprawidłowa. Wartości zastępcze mogą być listą rozdzieloną przecinkami, która zostanie połączona w jedną wartość. Na przykład var(--font-stack, "Roboto", "Helvetica"); definiuje wartość zastępczą "Roboto", "Helvetica". Pamiętaj, że wartości skrótów, takie jak te używane do marginesów i dopełnień, nie są rozdzielane przecinkami, więc odpowiednia wartość zastępcza dla 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 napisać style obronne dla 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 technika jest szczególnie przydatna w przypadku stylizacji komponentów internetowych, które korzystają z cienia DOM, ponieważ właściwości niestandardowe mogą przekraczać granice cienia. Autor komponentu internetowego może utworzyć początkowy projekt, używając wartości zastępczych, i ujawnić elementy motywu 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 funkcji var() należy pamiętać o kilku kwestiach. Zmiennych nie można używać w nazwach właściwości. Przykład:

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

Nie jest to jednak równoznaczne z ustawieniem margin-top: 20px;. Druga deklaracja jest nieprawidłowa i zostaje odrzucona jako błąd.

Nie można też utworzyć wartości, jeśli jej część jest dostarczana przez zmienną:

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

Ponownie: to nie jest to samo co ustawienie margin-top: 20px;. Aby uzyskać wartość, musisz użyć czegoś innego: funkcji calc().

Tworzenie wartości za pomocą funkcji calc()

Jeśli nie znasz jeszcze funkcji calc(), możesz skorzystać z niewielkiego narzędzia, które pozwoli Ci wykonać obliczenia w celu określenia wartości CSS. Jest on obsługiwany we wszystkich nowoczesnych przeglądarkach i może być łączony z właściwościami niestandardowymi w celu tworzenia nowych wartości. Na przykład:

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

Praca z właściwościami niestandardowymi w JavaScripcie

Aby uzyskać wartość właściwości niestandardowej w czasie wykonywania kodu, użyj metody getPropertyValue() obiektu obliczonych deklaracji stylu CSS.

/* 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'

Aby podobnie ustawić wartość właściwości niestandardowej w czasie działania aplikacji, 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');

Wartość właściwości niestandardowej możesz też ustawić tak, aby w czasie wykonywania kodu odwoływała się do innej właściwości niestandardowej. W tym celu w wywołaniu funkcji setProperty() użyj funkcji var().

/* 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ą się odwoływać do innych właściwości niestandardowych w Twoich arkuszach stylów, co może prowadzić do różnych ciekawych efektów w czasie wykonywania.

Obsługa przeglądarek

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

Prezentacja

Wypróbuj przykład, aby poznać wszystkie interesujące techniki, z których możesz teraz korzystać dzięki właściwościom niestandardowym.

Więcej informacji

Jeśli chcesz dowiedzieć się więcej o usługach niestandardowych, przeczytaj artykuł Philipa Waltona z zespołu Google Analytics, w którym wyjaśnia on, dlaczego jest tak podekscytowany usługami niestandardowymi. Możesz też śledzić postępy w wdrażaniu tych usług w innych przeglądarkach na stronie chromestatus.com.