Могу ли я добавить имя класса в переменную CSS?

Можно ли добавить имя класса в переменную CSS или есть какой-то другой способ настроить его так, чтобы мне не приходилось манипулировать каждой отдельной переменной напрямую через javascript? Я хотел бы сохранить все свои стили в CSS и просто включить соответствующие классы с помощью JS. Например, если что-то подобное было возможно в CSS:

:root.white{ --bgcol:#FFF; --col:#000; }
:root.black{ --bgcol:#000; --col:#FFF; }

Затем я мог бы просто переключить .black или .white из javascript, чтобы вызвать изменение всех переменных. Каков наилучший подход для этого типа установки?

Ответ 1

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

Для тех, кто не знает, что означает :root и интересуется, где именно применяются имена классов, это html элемент (родительский элемент body). Так что здесь ничего особенного не происходит - вы просто переключаете имена классов в элементе html. Просто бывает, что глобальные пользовательские свойства традиционно определены для корневого элемента документа, поскольку он находится на верхнем уровне цепочки наследования.

Если у вас есть какие-либо не зависящие от темы пользовательские свойства, а также свойства стиля (т.е. Не настраиваемые свойства), которые применяются к корневому элементу, оставьте их в своем собственном неквалифицированном :root правило, отделенное от ваших тематических настраиваемых свойств, чтобы они не быть затронутым переключением темы. Вот пример:

const root = document.documentElement;

// Default theme - should assign declaratively in markup, not JS
// For a classless default theme, move its custom properties to unqualified :root
// Again, keep it separate from the other :root rule that contains non-theme props
// Remember, the cascade is your friend, not the enemy
root.classList.add('white');

document.querySelector('button').addEventListener('click', function() {
  root.classList.toggle('white');
  root.classList.toggle('black');
});
:root {
  --spacing: 1rem;
  color: var(--col);
  background-color: var(--bgcol);
}

:root.white {
  --bgcol: #FFF;
  --col: #000;
}

:root.black {
  --bgcol: #000;
  --col: #FFF;
}

p {
  margin: var(--spacing);
  border: thin dashed;
  padding: var(--spacing);
}
<button>Switch themes</button>
<p>Hello world!

Ответ 2

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

Например:

:root {
  --bg: red;
}
:root.blue {
  --bg: blue;
}
// ...
div {
  background: var(--bg);
}

Позже вы должны просто изменить html класс и переменные будут меняться.

Вы можете увидеть пример в этой скрипке.