DevGang
Авторизоваться

Применение визуальных тем с помощью SCSS

Если у вас есть большое устаревшее веб-приложение, реализация темы темного режима — довольно сложная идея. Особенно, когда ваш CSS разбросан повсюду и вам нужно беспокоиться о ряде сторонних компонентов.

Идея реализации темного режима в нашем продукте электронного маркетинга стала естественным продолжением разговоров, которые команда вела об использовании темного режима в электронных письмах HTML и почтовых клиентах.

Раньше команда не уделяла особого внимания организации CSS. Частично это произошло из-за отсутствия какой-либо всеобъемлющей системы проектирования. В результате я назначил себя нашим де-факто экспертом по UX, и на меня легла задача найти лучший способ реализации тем CSS.

Чистый стиль

Нет смысла даже пытаться реализовать цветовые схемы в веб-продукте, если CSS нечистый. Современные фреймворки справедливо разделяют HTML, JavaScript и CSS на отдельные файлы, но наше приложение 15-летней давности (которое было основано на еще более старом решении ASP) не следовало этим общим процессам.

Этот многоэтапный процесс, вероятно, был самым трудоемким элементом реализации визуальных тем, но он того стоил, даже как несвязанная задача.

Мы просмотрели все существующие файлы CSS и разделили стили отдельных компонентов на отдельные файлы. Здесь нет правильного подхода, главное – последовательность. Я разделил наш CSS на внешние и внутренние компоненты; поэтому я создал подпапки для каждого поставщика компонентов (например, BootStrap, Telerik и т. д.) и подпапки для областей приложения (например, настройки приложения, безопасность пользователя и т. д.), прежде чем переносить наш CSS в файлы внутри этих папок. Все оставшееся, что не могло легко вписаться в категорию, было перенесено в универсальный CSS.

После завершения этого процесса мы установили и настроили WebCompiler для автоматической компиляции наших стилей из SCSS.

Наконец, мы рассмотрели использование встроенных блоков CSS и стилей CSS в нашем контенте CSHTML (этого было много) и перенесли все, специфичное для темы, в новые файлы SCSS.

Позже будет проведена дополнительная работа по очистке, но этот вариант хорошо подходит для будущей разработки и позволил нам разделить сгенерированный CSS между общими элементами приложения, которые требуются постоянно, и стилями, специфичными для экрана, которые просто необходимо было загружать рядом с определенными экранами.

Из-за большого количества перемещаемого CSS разумно тестировать изменения и сравнивать экраны с неизмененными версиями. Это позволяет нам обнаружить любые проблемы с приоритетом, вызванные перемещением объектов.

Создайте переменные SCSS и просмотрите цветовую схему

Несмотря на то, что команда позаботилась о том, чтобы существующая цветовая схема была единообразной во всем продукте, неизбежно возникали области, в которых вариации были случайно введены в наш CSS.

Сейчас было идеальное время, чтобы просмотреть все цветовые коды и шрифты в наших файлах SCSS и проверить наличие несоответствий. Это дало нам возможность не только оптимизировать внешний вид продукта, но и максимально сократить количество переменных CSS.

Даже несмотря на это, после первого прохода мы все равно создали более 100 переменных CSS. Влияние этой очистки на внешний вид продукта было сразу очевидно.

Генерация тем

Следующим шагом было создание нашей первой темы из переменных SCSS. Я объявил каждую тему в отдельном файле, в этом нет строгой необходимости, но это значительно упрощает обслуживание.

Каждый файл состоит из списка переменных и объекта темы, который использует эти переменные, что выглядит примерно так, как показано в примере ниже.

// branding colours
$branding-primary: #105CC6;
$action-edit-button: #00a2e8;

// fonts
$font-primary:"Helvetica Neue", Helvetica, Arial, sans-serif;
$font-legend: Arial, Helvetica, sans-serif;
$font-header: Calibri, Arial, sans-serif;
$font-code: Lucida Console;

$standard-theme: ( 
    // branding
    branding-primary: $branding-primary,
    branding-primary-dark: darken($branding-primary, 15%),
    branding-primary-edit: $action-edit-button,
    branding-primary-edit-dark: darken($action-edit-button, 20%),

    // base fonts
    font-primary: $font-primary,
    font-legend: $font-legend,
    font-title-area: $font-header,
    font-code: $font-code
);

Чтобы сгенерировать окончательный CSS, нам нужно взять наши темы и использовать примесь SCSS, чтобы определить дополнительные правила CSS, которые запускают их использование.

Мы достигли этого, указав имя класса CSS в элементе DOM <html>, которое будет определять имя текущей темы. Стандартная тема включается классом theme-standard, а темная тема включается классом theme-dark и т. д.

// import themes from external files
@import 'standard.scss';
@import 'dark.scss';

// add themes to an array
$themes: (
    standard: $standard-theme,
    dark: $dark-theme,
);

@mixin theme() {
    $array: $themes;

    @each $theme, $map in $array {
        html.theme-#{$theme} & {
            $array-map: () !global;

            @each $key, $submap in $map {
                $value: map-get(map-get($array, $theme), '#{$key}');
                $array-map: map-merge($array-map, ($key: $value)) !global;
            }

            @content;
            $array-map: null !global;
        }
    }
}

@function themeValue($key) {
    @return map-get($array-map, $key);
}

Затем мы можем изменить наш SCSS, включив в него ссылку на функцию themeValue. Это приведет к созданию нескольких строк CSS, по одной для каждой возможной темы.

body {
    @include theme() {
        font-family: themeValue(font-primary);
    }
    font-variant: none;
}

Выбор темы

Наконец, осталось только настроить нашу тему. Это должно происходить как можно выше при загрузке страницы, чтобы предотвратить появление нестилизованного контента.

Конечно, мы могли бы просто применить класс стиля к DOM-объекту <html> и покончить с этим; однако большинство приложений предоставляют опцию "System Theme", и ее реализация самостоятельно не потребует особых усилий.

В этом примере мы уже поддерживаем theme-standard и theme-dark, теперь мы представим theme-system в качестве третьего варианта и автоматически применим светлую или темную тему.

// are we using the system theme
const isSystemTheme = theme == "theme-system";
if (isSystemTheme)
{
    // detect colour scheme
    if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
        theme = "theme-dark";
    }
    else
    {
        theme = "theme-standard";
    }
}

setVisualTheme(theme, isSystemTheme);

Затем мы очистим существующую тему и применим новую. Обратите внимание: если мы используем системную тему по умолчанию, это позволит нам изменить тему без обновления страницы.

function setVisualTheme(themeName, isSystemTheme) {
    // remove any existing theme
    const $html = $("html");
    $html.attr("class", function(i, c){
        return c.replace(/(^|\s)theme-\S+/g, '');
    });

    $("html").prop("usingSystemTheme", isSystemTheme);

    // set new theme
    $("html").addClass(themeName);
}

Мы можем перехватить изменения в системной теме, используя приведенный ниже JavaScript. Если тема операционной системы будет изменена, это будет автоматически передано в окно браузера, и мы сможем гарантировать, что это обновление отразится на странице:

window.matchMedia("(prefers-color-scheme: dark)")
    .addEventListener("change", event => {
        if ($("html").prop("usingSystemTheme")) {
            let targetTheme = "theme-standard";

            if (event.matches) {
                targetTheme = "theme-dark";
            }

             setVisualTheme(targetTheme, true);
         }
    });

В качестве последнего шага мы также можем обновить цвет заголовка браузера, чтобы он соответствовал цвету темы. Это обеспечивает более целостное ощущение в мобильной среде.

Мы можем сделать это, добавив дополнительное метазначение в наш документ:

<meta name="theme-color" content="#4285f4" />

Мы не можем извлечь цвет темы непосредственно из CSS, но мы можем применить соответствующий класс к скрытому объекту DOM, а затем прочитать этот цвет с помощью JavaScript и применить его к объекту theme-color. Этот подход также решил проблему со сторонним компонентом, который требовал установки цветовой схемы с помощью JavaScript.

Заключение

Реализация визуальных тем в продукте, который никогда не был написан с учетом этого, была непростой задачей; однако большая часть работы заключалась в очистке существующей реализации CSS.

На этом пути было несколько моментов, когда польза от того, что мы делали, была очевидна, и это было еще до того, как мы реализовали нашу первую цветовую схему.

Если это путешествие что-то и доказывает, так это то, насколько важно разделять наши компоненты пользовательского интерфейса и связанный с ними CSS. Это то, что современные фреймворки делают очень хорошо, но чего может не хватать в устаревших приложениях.

Источник:

#CSS
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу