Zmiana zakresowych zmiennych CSS za pomocą JavaScript

Jan 18 2023
Przydatne do motywowania
Trochę googlowałem na ten temat i nie znalazłem rozsądnego rozwiązania, więc pomyślałem, że może być wart krótkiego artykułu. Treść Jeśli pracujesz z wieloma motywami, często zdarza się, że nie umieszczasz zmiennych CSS bezpośrednio w :root .

Trochę googlowałem na ten temat i nie znalazłem rozsądnego rozwiązania, więc pomyślałem, że może być wart krótkiego artykułu.

Treść

  1. Problem
  2. Jak zmienić zmienne CSS wewnątrz :root
  3. Jak zmienić zakres zmiennych CSS
  4. Zmiana zmiennych CSS o określonym zakresie z poziomu Web Workera
  5. Tworzenie skrótu
  6. Projekt neo.mjs
  7. Nie na temat, ale niesamowite: co ChatGPT myśli o neo?

Jeśli pracujesz z wieloma motywami, często wydaje się, że nie umieszczasz zmiennych CSS bezpośrednio w plikach :root.

Zamiast tego możesz użyć struktury takiej jak
:root .theme-light {/*my variables*/}

Jeśli chcesz zmienić wartości tych zmiennych CSS w czasie wykonywania za pomocą JavaScript, może to być nieco trudne.

2. Jak zmienić zmienne CSS wewnątrz :root

:root {
    --my-color: red;
}
document.documentElement.setProperty('--my-color', 'blue');

3. Jak zmienić zakresowe zmienne CSS

:root .theme-light {
    --my-color: red;
}

:root .theme-dark {
    --my-color: darkred;
}

Możemy np. zastosować theme-light do rzutni, użyć kontenera potomnego z theme-dark i wewnątrz tego jednego przycisków ponownie z theme-light.

Miałem nadzieję na elegancki sposób zmiany zmiennych CSS również w tym przypadku użycia. Nie znalazłem tego. Więc:

/**
 * @param {Object} data
 * @param {String} data.key
 * @param {String} [data.priority] optionally pass 'important'
 * @param {String} data.theme
 * @param {String} data.value
 */
function setCssVariable(data) {
    let key = data.key,
        rule, sheet;

    if (!key.startsWith('--')) {
        key = '--' + key;
    }

    for (sheet of document.styleSheets) {
        if (sheet.href.includes(data.theme)) {
            for (rule of sheet.cssRules) {
                if (rule.constructor.name === 'CSSStyleRule') {
                    if (rule.style.getPropertyValue(key) !== '') {
                        rule.style.setProperty(key, data.value, data.priority);
                        return true;
                    }
                }
            }
        }
    }

    return false;
}

setCssVariable({
    key  : 'my-color',
    theme: 'theme-light',
    value: 'blue'
});

Przeglądamy wszystkie arkusze stylów dokumentu. Zakładając, że URL twojego pliku CSS zawiera nazwę twojego motywu, możesz ograniczyć przez niego liczbę kontroli.

Jeśli tak nie jest, możesz sprawdzić selectorTextwewnętrzną pętlę (droższą):

W przypadku użycia neo każdy plik motywu ma tylko jedną CSSStyleRule, więc wewnętrzna pętla nie jest tak droga, jak mogłoby się wydawać na pierwszy rzut oka.

Nieistniejące wartości właściwości zwracają pusty ciąg (interesujące :)), więc możemy go sprawdzić, aby określić, która CSSRule zawiera zmienną, którą chcemy zmienić.

Ponowny dostęp do właściwości rule.style daje nam:

i skończyliśmy.

Możesz użyć tej techniki w swojej aplikacji Angular, React lub innej popularnej technologii, z którą korzystasz. Kolejne sekcje wykraczają poza to.

4. Zmiana zmiennych CSS w zakresie z poziomu Web Workera

src/main/addon/Stylesheet.mjs (główny wątek)

class Stylesheet extends Base {
    static getConfig() {return {
        className: 'Neo.main.addon.Stylesheet',

        remote: {
            app: [
                'setCssVariable'
            ]
        }
    }}

    setCssVariable(data) {
        // ...
    }
}

Jeśli przyjrzysz się uważnie konsoli, zauważysz niebieskie pole → zakres jest ustawiony na Web Worker i możemy po prostu wywołać metodę jako obietnicę w tej samej poza tym pustej przestrzeni nazw.

5. Tworzenie skrótu

src/worker/App.mjs (poza głównym wątkiem)

class App extends Base {
    construct(config) {
        super.construct(config);

        // convenience shortcut
        Neo.setCssVariable = this.setCssVariable.bind(this);
    }

    setCssVariable(data) {
        let addon = Neo.main?.addon?.Stylesheet,
            theme = Neo.config.themes?.[0];

        if (!addon) {
            return Promise.reject('Neo.main.addon.Stylesheet not imported');
        } else {
            if (theme.startsWith('neo-')) {
                theme = theme.substring(4);
            }

            return addon.setCssVariable({theme, ...data});
        }
    }
}

z poziomu Web Workera.

6. Projekt neo.mjs

„Pracownik aplikacji w roli głównej” czy „poza głównym wątkiem” to już nie fikcja, a praca bardzo stabilna i niezwykle szybka:

neo trafiło już na wersję 4.8.2 z ponad 15 000 zatwierdzeń w ekosystemie. Być może przegapiłeś tysiące od mojego ostatniego wpisu na blogu.

Jeśli nie przyjrzałeś się korzyściom płynącym z wydajności, skalowalności i rozszerzeń, możesz nadrobić zaległości w temacie wielowątkowych frontendów nowej generacji.

Jako spoiler: Max Rahder jest właśnie w trakcie pierwszego profesjonalnego szkolenia neo dla 20 uczniów. Po zakończeniu powinniśmy mieć wystarczająco dużo treści, aby w końcu uruchomić brakującą sekcję edukacyjną.

Jeśli chcesz uzyskać wczesny dostęp, po prostu napisz do nas na Slacku:

7. Nie na temat, ale niesamowite: co ChatGPT myśli o neo?

Pozdrowienia i szczęśliwego kodowania,
Tobiasz