Есть ли способ добавить темный режим в мое приложение с помощью SCSS?

Мне поставили задачу добавить переключатель в веб-приложение angular, которое позволит пользователям переключаться с темы светлого режима по умолчанию на тему темного режима. Я не могу найти способ успешно реализовать это.

Когда я получил задание, в каталоге стилей был файл _variables.scss. Он содержал переменные для цветов, шрифтов, размеров и интервалов. Цвета были в картах, а затем каждый оттенок был назначен переменной с использованием метода map-get(), например, $shade-0: map-get($shades, 'shade-0').

Сначала я думал, что могу создать файл themes.scss и импортировать его вместе с _variables.scss. Затем этот файл будет связан с двумя дополнительными файлами scss lightTheme.scss и darkTheme.scss. Каждый файл темы будет содержать список переменных цвета, похожих на исходные в variables.scss. Я могу заставить это работать для одной темы или другой, но я не могу переключаться между файлами темы.

darkTheme.scss

$shades: (
  'shade-6':                            #f5f5f5,
  'shade-5':                            #BDBDBD,
  'shade-4':                            #9E9E9E,
  'shade-3':                            #757575,
  'shade-2':                            #616161,
  'shade-1':                            #303437,
  'shade-0':                            #404447,
);

$shade-0:                              map-get($shades, 'shade-0');
$shade-1:                              map-get($shades, 'shade-1');
$shade-2:                              map-get($shades, 'shade-2');
$shade-3:                              map-get($shades, 'shade-3');
$shade-4:                              map-get($shades, 'shade-4');
$shade-5:                              map-get($shades, 'shade-5');
$shade-6:                              map-get($shades, 'shade-6');

$colors: (
  'forest':                            #239F28CC,
  'aqua':                              #8ab4f8,
  'ruby':                              #C93939CC,
  'zing':                              #20CAC3CC,
  'carrot':                            #E9853ECC,
  'grape':                             #7542F2CC,
  'midnight':                          #433F5CCC,
  'slate':                             #657786CC,
);

$forest:                               map-get($colors, 'forest');
$aqua:                                 map-get($colors, 'aqua');
$ruby:                                 map-get($colors, 'ruby');
$zing:                                 map-get($colors, 'zing');
$carrot:                               map-get($colors, 'carrot');
$grape:                                map-get($colors, 'grape');
$midnight:                             map-get($colors, 'midnight');
$slate:                                map-get($colors, 'slate');

$bg-color:                            map-get($shades, 'shade-1');
$border-color:                        map-get($shades, 'shade-2');
$border-dark-color:                   map-get($shades, 'shade-3');
$text-color:                          map-get($shades, 'shade-6');
$muted:                               map-get($colors, 'slate');
$subtle:                              map-get($shades, 'shade-4');

lightTheme.scss

$colors: (
      'forest':                            #239F28,
      'aqua':                              #186EEF,
      'ruby':                              #C93939,
      'zing':                              #20CAC3,
      'carrot':                            #E9853E,
      'grape':                             #7542F2,
      'midnight':                          #433F5C,
      'slate':                             #657786,
);
$shades: (
  'shade-0':                            #ffffff,
  'shade-1':                            #f5f5f5,
  'shade-2':                            #d8d8d8,
  'shade-3':                            #bbbbbb,
  'shade-4':                            #979797,
  'shade-5':                            #535353,
  'shade-6':                            #0c0c0c,
);
$shade-0:                              map-get($shades, 'shade-0');
$shade-1:                              map-get($shades, 'shade-1');
$shade-2:                              map-get($shades, 'shade-2');
$shade-3:                              map-get($shades, 'shade-3');
$shade-4:                              map-get($shades, 'shade-4');
$shade-5:                              map-get($shades, 'shade-5');
$shade-6:                              map-get($shades, 'shade-6');
$forest:                               map-get($colors, 'forest');
$aqua:                                 map-get($colors, 'aqua');
$ruby:                                 map-get($colors, 'ruby');
$zing:                                 map-get($colors, 'zing');
$carrot:                               map-get($colors, 'carrot');
$grape:                                map-get($colors, 'grape');
$midnight:                             map-get($colors, 'midnight');
$slate:                                map-get($colors, 'slate');
$bg-color:                             map-get($shades, 'shade-1');
$border-color:                         map-get($shades, 'shade-2');
$border-dark-color:                    map-get($shades, 'shade-3');
$text-color:                           map-get($shades, 'shade-6');
$muted:                                map-get($colors, 'slate');
$subtle:                               map-get($shades, 'shade-4');

темы.scss

@import 'global/lightTheme';
@import 'global/darkTheme';

Я попытался изменить переменные с переменных scss на переменные css и использовать их с var(), но столкнулся с трудностями, поскольку некоторые компоненты используют darken(), lighten() и mix() и поэтому не компилируются. Есть ли способ заставить это работать?

вы можете импортировать стили с условиями, перейдите по этой ссылке: stackoverflow.com/questions/36367532/…

Alex 13.07.2019 12:26

Не забудьте учитывать предустановку пользователя, проверьте prefers-color-scheme.

David Thomas 13.07.2019 16:19
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
CSS: FlexBox
CSS: FlexBox
Ранее разработчики использовали макеты с помощью Position и Float. После появления flexbox сценарий полностью изменился.
6
2
10 491
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Я подготовил CodePen для демонстрации переключения темы с помощью переменных CSS.

Я определяю переменные цвета в зависимости от класса контейнера приложения (.light или .dark). Простое переключение этих классов изменит тему сайта.

Имейте в виду, что Переменные CSS не полностью поддерживаются во всех браузерах. (94% по всему миру).

Подробнее о переменных CSS.

Это действительно здорово @Barthy, это достаточно близко к тому, что мне нужно. Это решит большинство моих проблем, за исключением того, что в моем приложении есть определенные компоненты, в которых один из цветов становится темнее, например background-color: darken($bg-color, 8%); . Точно так же используются lighten() и mix(). Я знаю, что переменные CSS и SCSS плохо сочетаются друг с другом. У вас есть предложения?

Ben Newton 13.07.2019 23:16

Да, определите более темные цвета так же, как и все остальные цвета, и используйте их позже! Я обновлю перо с примером.

Barthy 14.07.2019 15:33

@BenNewton, вы видели обновление, которое я сделал в ручка?

Barthy 15.07.2019 01:08

Да, я сделал. Большое спасибо за вашу помощь, это сработало!

Ben Newton 15.07.2019 16:07

Я нашел этот статья на Medium, думаю, вы можете его проверить.

Идея заключается в том, что вы запрашиваете тег body в своем html, а затем устанавливаете для него класс

Этот вопрос был задан год назад, но все еще полезен для тех, кто читает это, вот более простое решение.

Основные моменты

  • Javascript используется только для переключения класса вашего корневого элемента.
  • Вам не нужно определять отдельные классы тем для каждого элемента.

Все, что вам нужно сделать в вашем файле scss, это:

.content {
  padding: 32px;
  @include theme() {
    color: theme-get('text-color');
    background-color: theme-get('bg-color');
  }
}

Реализация

Вы можете создать отдельный файл, скажем, themes.scss, в котором вы можете определить свойства для обеих ваших тем:

$themes: (
  darkTheme: (
    'text-color': white,
    'bg-color': #424242
  ),
  lightTheme: (
    'text-color': black,
    'bg-color': #f5f5f5
  )
);

Используйте mixin:

// From Sass 2.0 on, it is no longer allowed to declare globals on the fly.
$theme-map: null;

@mixin theme() {
  @each $theme, $map in $themes {
    // $theme: darkTheme, lightTheme
    // $map: ('text-color': ..., 'bg-color': ...)

    // make the $map globally accessible, so that theme-get() can access it
    $theme-map: $map !global;

    // make a class for each theme using interpolation -> #{}
    // use & for making the theme class ancestor of the class
    // from which you use @include theme() {...}
    .#{$theme} & {
      @content;    // the content inside @include theme() {...}
    }
  }
  // no use of the variable $theme-map now
  $theme-map: null !global;
}

Теперь вы можете получить доступ к свойству темы, используя map-get($theme-map, ...). Но мы можем избежать передачи $theme-map в качестве аргумента каждый раз, определив функцию, которая сделает это за нас.

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

Результирующий файл css будет:

.content {
  padding: 32px;
}

.darkTheme .content {
  color: white;
  background-color: #424242;
}

.lightTheme .content {
  color: black;
  background-color: #f5f5f5;
}

Пример

Вот скрипт для демонстрации: https://jsfiddle.net/aksh101099/zubnapr9/1/

Это прекрасное решение! Работает как шарм, спасибо за это!

kmnowak 16.10.2020 20:56

Разве это не создает двойной CSS? (так что если у вас 10 тем, то в 10 раз больше css). Хотя сами решения работают нормально, в некоторых случаях придерживаться переменных css, то есть :root { --sth: xxx} и var(--sth) si, можно.

Alex 26.12.2021 13:02

Чтобы согласиться с ответом Акшдипа Сингха, если вы используете модули css (или scss), вам нужно будет определить ключевое слово темы в своем селекторе как глобальное, чтобы к нему не применялось имя модуля:

@mixin theme() {
    @each $theme, $map in $themes {
      // $theme: darkTheme, lightTheme
      // $map: ('text-color': ..., 'bg-color': ...)
  
      // make the $map globally accessible, so that theme-get() can access it
      $theme-map: $map !global;
  
      // make a class for each theme using interpolation -> #{}
      // use & for making the theme class ancestor of the class
      // from which you use @include theme() {...}
      :global(.#{$theme}) & {
        @content;    // the content inside @include theme() {...}
      }
    }
    // no use of the variable $theme-map now
    $theme-map: null !global;
}

Другие вопросы по теме