CSS переменные и темизация

Основы CSS переменных

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

Пример объявления и использования:

:root {
  --primary-color: #42b983;
  --font-size-base: 16px;
}

.button {
  background-color: var(--primary-color);
  font-size: var(--font-size-base);
}

Переменные можно задавать на уровне глобальных стилей (:root) или локально в компоненте Vue, что позволяет создавать изолированные темы для отдельных модулей.


Интеграция CSS переменных в Vue

В Vue.js переменные можно использовать как в Single File Components (SFC), так и в глобальных стилях. При использовании SFC структура выглядит следующим образом:

<template>
  <div class="card">
    Тема приложения
  </div>
</template>

<script>
export default {
  name: 'ThemeCard'
}
</script>

<style scoped>
.card {
  background-color: var(--card-bg, #ffffff);
  color: var(--card-text, #333333);
  padding: 1rem;
  border-radius: 8px;
}
</style>

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


Динамическая темизация с помощью Vue

Одно из сильных преимуществ Vue — возможность динамически менять CSS переменные через реактивные данные. Для этого переменные задаются на корневом элементе через style или с помощью :style биндинга.

Пример динамического изменения темы:

<template>
  <div :style="themeStyles" class="app-container">
    Привет, Vue!
  </div>
</template>

<script>
export default {
  data() {
    return {
      theme: {
        '--primary-color': '#42b983',
        '--background-color': '#f5f5f5',
        '--text-color': '#333333'
      }
    };
  },
  computed: {
    themeStyles() {
      return this.theme;
    }
  },
  methods: {
    switchTheme() {
      this.theme['--primary-color'] = '#ff6347';
      this.theme['--background-color'] = '#1e1e1e';
      this.theme['--text-color'] = '#ffffff';
    }
  }
}
</script>

<style>
.app-container {
  background-color: var(--background-color);
  color: var(--text-color);
  padding: 2rem;
  transition: all 0.3s ease;
}
</style>

В этом примере тема меняется в реальном времени при вызове метода switchTheme(), не требуя перезагрузки страницы или пересборки стилей.


Темизация через Vuex или Pinia

Для крупных приложений удобно хранить текущую тему в глобальном состоянии с помощью Vuex или Pinia, что позволяет использовать одну тему на всех компонентах.

Пример с Pinia:

// store/theme.js
import { defineStore } from 'pinia';

export const useThemeStore = defineStore('theme', {
  state: () => ({
    currentTheme: {
      '--primary-color': '#42b983',
      '--background-color': '#ffffff',
      '--text-color': '#333333'
    }
  }),
  actions: {
    setDarkTheme() {
      this.currentTheme = {
        '--primary-color': '#ff6347',
        '--background-color': '#1e1e1e',
        '--text-color': '#ffffff'
      };
    }
  }
});
<template>
  <div :style="theme.currentTheme">
    Темизированный компонент
  </div>
</template>

<script>
import { useThemeStore } from '../store/theme';

export default {
  setup() {
    const theme = useThemeStore();
    return { theme };
  }
}
</script>

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


Миксин для темизации компонентов

Для повторного использования логики темизации можно создать Vue миксин, который автоматически подключает тему к компоненту:

export const themeMixin = {
  computed: {
    themeStyles() {
      return this.$store.state.theme.currentTheme; // или Pinia store
    }
  }
}

Применение в компоненте:

<template>
  <div :style="themeStyles">
    Контент с миксином
  </div>
</template>

<script>
import { themeMixin } from '../mixins/themeMixin';

export default {
  mixins: [themeMixin]
}
</script>

Такой подход снижает дублирование кода и упрощает поддержку большого приложения.


Адаптация темы под пользовательские настройки

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

const savedTheme = JSON.parse(localStorage.getItem('userTheme')) || defaultTheme;
Object.entries(savedTheme).forEach(([key, value]) => {
  document.documentElement.style.setProperty(key, value);
});

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


Взаимодействие CSS переменных с препроцессорами

CSS переменные совместимы с Sass или Less. В отличие от Sass-переменных, CSS переменные остаются доступными в runtime, что делает их идеальными для динамической темизации:

$primary-color: #42b983;

.button {
  background-color: var(--primary-color, $primary-color);
}

Такой подход объединяет мощь препроцессора для разработки и гибкость runtime переменных для динамики интерфейса.


Анимации и переходы с переменными

CSS переменные могут использоваться внутри анимаций и переходов:

:root {
  --transition-duration: 0.3s;
}

.button {
  background-color: var(--primary-color);
  transition: background-color var(--transition-duration) ease;
}

.button:hover {
  --primary-color: #ff6347;
}

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


Итоговые рекомендации

  • Использовать CSS переменные для всех ключевых цветов, размеров и шрифтов, чтобы упростить поддержку тем.
  • Динамическая темизация через Vue :style или глобальный store обеспечивает гибкость и единообразие интерфейса.
  • Хранение пользовательской темы в localStorage или базе данных позволяет сохранять настройки между сессиями.
  • Миксины и глобальные стили помогают стандартизировать подход к темизации для большого приложения.

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