Олег Марков
Препроцессоры CSS - полный разбор возможностей Sass Less и Stylus
Введение
Препроцессоры CSS (css-preprocessors) появились как ответ на ограниченность «чистого» CSS. Сам по себе CSS достаточно прост, но по мере роста проектов становится трудно поддерживать большие таблицы стилей, повторяющиеся цвета, размеры, сложные селекторы и однотипные фрагменты кода.
Препроцессоры добавляют надстройку над CSS: вы пишете код на более «умном» языке (Sass, Less, Stylus), а затем этот код компилируется в обычный CSS, который понимает браузер. Давайте разберемся, как это работает на практике, какие задачи это решает и какие возможности вы получаете.
В статье мы будем опираться в основном на Sass (SCSS-синтаксис), иногда сравнивая его с Less и Stylus, чтобы у вас сложилась общая картина по css-preprocessors.
Что такое CSS-препроцессор и как он работает
Основная идея препроцессора
Препроцессор — это инструмент, который:
- Принимает файл с расширением вроде
.scss,.sass,.lessили.styl. - Обрабатывает расширенный синтаксис — переменные, функции, миксины, вложенность и т.п.
- Генерирует итоговый
.cssфайл, который подключается к странице.
Смотрите, схема довольно проста:
- Вы пишете:
// variables.scss
$primary-color: #3498db; // Основной цвет
$font-size-base: 16px; // Базовый размер шрифта
.button {
color: #fff; // Цвет текста
background-color: $primary-color; // Используем переменную
font-size: $font-size-base; // Используем переменную
}
- Препроцессор компилирует это в обычный CSS:
.button {
color: #fff;
background-color: #3498db;
font-size: 16px;
}
Браузеру не важен препроцессор — он получает только чистый CSS. Все «умные» конструкции живут на этапе сборки.
Популярные препроцессоры
Sass / SCSS
Sass — самый популярный из препроцессоров.
- Sass (старый синтаксис) — без фигурных скобок, с отступами, как в Python.
- SCSS — более современный и распространённый синтаксис, очень похожий на CSS, но с расширениями.
С точки зрения возможностей Sass и SCSS одинаковы, отличие только в синтаксисе. В статье будем использовать SCSS.
Less
Less исторически был популярен в экосистеме Node.js и в Bootstrap 3. Напоминает CSS, но есть отличия в синтаксисе переменных и некоторых конструкциях. Основное расширение — .less.
Stylus
Stylus используется реже, но тоже довольно мощный препроцессор. Часто встречается в проектах, связанных с Node.js. Умеет писать код практически без скобок и точек с запятой, но это уже вопрос вкуса.
Установка и базовая настройка препроцессора
Здесь я покажу базовую схему на примере Sass, потому что он сейчас самый распространенный.
Установка Sass через npm
Если у вас установлен Node.js, проще всего поставить Sass так:
# Устанавливаем Sass глобально
npm install -g sass
Теперь вы можете вызывать команду sass из терминала.
Компиляция одного файла
Давайте разберемся на примере простого проекта:
project/
scss/
style.scss # Исходный файл препроцессора
css/
style.css # Скомпилированный CSS
index.html
Компиляция:
# Компилируем style.scss в style.css
sass scss/style.scss css/style.css
- Справа — путь к выходному CSS.
- Слева — путь к файлу препроцессора.
Режим наблюдения (watch)
Чтобы не запускать команду после каждого изменения, используйте --watch:
# Автоматически отслеживаем изменения в style.scss
sass --watch scss/style.scss css/style.css
Теперь при каждом сохранении style.scss CSS будет пересобираться автоматически.
Работа с каталогом
Можно следить за целой директорией:
# Следим за всеми файлами в scss и складываем CSS в css
sass --watch scss:css
scss— директория с исходниками.css— директория, куда кладется результат.
Теперь давайте перейдем к возможностям, ради которых вы вообще устанавливаете препроцессоры.
Переменные
Переменные — одно из ключевых преимуществ препроцессоров. Они помогают централизованно управлять цветами, размерами, отступами и другими повторяющимися значениями.
Переменные в Sass (SCSS)
В Sass переменные начинаются со знака $.
// Определяем переменные
$primary-color: #3498db; // Основной цвет
$secondary-color: #2ecc71; // Второстепенный цвет
$font-size-base: 16px; // Базовый размер шрифта
$border-radius-base: 4px; // Базовый радиус скругления
.button-primary {
background-color: $primary-color; // Используем переменную
color: #fff; // Белый текст
font-size: $font-size-base; // Базовый шрифт
border-radius: $border-radius-base; // Скругленные углы
}
.button-secondary {
background-color: $secondary-color;
color: #fff;
font-size: $font-size-base;
border-radius: $border-radius-base;
}
Если вы захотите изменить основной цвет, вам достаточно поменять его один раз в определении переменной.
Переменные в Less и Stylus — сравнение
Чтобы вы видели общую картину, вот аналогичный пример в Less:
// Переменные в Less начинаются с @
@primary-color: #3498db; // Основной цвет
@font-size-base: 16px; // Базовый размер шрифта
.button-primary {
background-color: @primary-color;
font-size: @font-size-base;
}
И в Stylus:
// Переменные в Stylus без специального префикса
primary-color = #3498db // Основной цвет
font-size-base = 16px // Базовый размер шрифта
.button-primary
background-color primary-color
font-size font-size-base
Синтаксис разный, идея одна и та же — задаете значение один раз и используете много раз.
Организация переменных по файлам
Обычно переменные выносят в отдельный файл, например variables.scss:
// variables.scss
$primary-color: #3498db;
$secondary-color: #2ecc71;
$danger-color: #e74c3c;
$font-size-base: 16px;
$font-size-small: 14px;
$font-size-large: 20px;
Потом подключают его в основном файле через @use или @import (о них поговорим ниже).
Так вы получаете единый центр управления стилями.
Вложенность селекторов
CSS-препроцессоры позволяют писать вложенные селекторы, чтобы код выглядел ближе к структуре HTML. Это значительно упрощает работу с компонентами.
Базовая вложенность в Sass
Посмотрите пример:
// Описываем блок .card и стили для его частей
.card {
padding: 16px; // Внутренние отступы
background-color: #fff; // Фон карточки
border-radius: 8px; // Скругление углов
.card-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 8px; // Отступ снизу от заголовка
}
.card-content {
font-size: 14px;
color: #555; // Серый текст
}
.card-footer {
margin-top: 12px;
text-align: right; // Выравнивание содержимого по правому краю
}
}
Скомпилированный CSS будет таким:
.card {
padding: 16px;
background-color: #fff;
border-radius: 8px;
}
.card .card-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 8px;
}
.card .card-content {
font-size: 14px;
color: #555;
}
.card .card-footer {
margin-top: 12px;
text-align: right;
}
Как видите, препроцессор просто подставляет родительский селектор перед вложенным.
Использование амперсанда (&)
Символ & в Sass (и других препроцессорах) обозначает текущий селектор. Смотрите, я покажу вам, как это работает.
Псевдоклассы и псевдоэлементы
.button {
padding: 8px 16px;
background-color: #3498db;
color: #fff;
&:hover {
background-color: #2980b9; // Цвет при наведении
}
&:active {
background-color: #1f6a8f; // Цвет при нажатии
}
}
Результат:
.button {
padding: 8px 16px;
background-color: #3498db;
color: #fff;
}
.button:hover {
background-color: #2980b9;
}
.button:active {
background-color: #1f6a8f;
}
Модификаторы (например, BEM)
В методологии БЭМ часто используют модификаторы вида .button--primary. С & это записывается удобно:
.button {
padding: 8px 16px;
&--primary {
background-color: #3498db; // Основная кнопка
color: #fff;
}
&--secondary {
background-color: #95a5a6; // Вторичная кнопка
color: #2c3e50;
}
}
Результат:
.button {
padding: 8px 16px;
}
.button--primary {
background-color: #3498db;
color: #fff;
}
.button--secondary {
background-color: #95a5a6;
color: #2c3e50;
}
Вложенные медиа-запросы
В препроцессорах можно вкладывать медиа-запросы внутрь селекторов:
.container {
max-width: 1200px;
margin: 0 auto;
@media (max-width: 768px) {
max-width: 100%; // На маленьких экранах контейнер на всю ширину
padding: 0 16px; // Добавляем отступы
}
}
Это помогает держать адаптивные стили рядом с основными.
Осторожность с глубокой вложенностью
Вложенность — удобный инструмент, но легко перейти грань и получить очень длинные селекторы. Старайтесь не уходить глубже 3 уровней:
// Плохо — слишком глубокая вложенность
.page {
.header {
.menu {
.item {
.link {
// Сложный селектор, который сложно переиспользовать
}
}
}
}
}
Лучше держаться ближе к компонентному подходу, а не к отражению всей структуры HTML в селекторах.
Миксины
Миксины — это переиспользуемые блоки стилей, которые можно «подключать» в разные селекторы. Они похожи на функции, но не обязательно возвращают значение, а вставляют кусок CSS.
Простой миксин в Sass
Давайте разберемся на примере:
// Определяем миксин для центрирования по Flexbox
@mixin flex-center {
display: flex; // Включаем flex-контейнер
justify-content: center; // Центрируем по горизонтали
align-items: center; // Центрируем по вертикали
}
// Используем миксин в разных классах
.modal {
@include flex-center; // Подключаем миксин
}
.button-group {
@include flex-center; // Повторно используем тот же миксин
}
После компиляции в каждое место, где вы написали @include flex-center, будет подставлен код из миксина.
Миксины с параметрами
Миксины особенно полезны, когда принимают параметры.
// Миксин для кнопки
@mixin button($bg-color, $text-color: #fff, $radius: 4px) {
padding: 8px 16px;
background-color: $bg-color; // Используем параметр фона
color: $text-color; // Используем параметр текста
border-radius: $radius; // Скругление
border: none;
cursor: pointer;
}
// Применяем миксин с разными параметрами
.button-primary {
@include button(#3498db); // Только цвет фона, остальные по умолчанию
}
.button-secondary {
@include button(#95a5a6, #2c3e50, 0); // Все параметры явно
}
Так вы описываете «шаблон» кнопки один раз и переиспользуете его для разных вариантов.
Миксины vs функции
- Миксины вставляют целый блок стилей.
- Функции возвращают одно значение (например, цвет, число, строку) и используются внутри свойств.
Дальше мы посмотрим и на функции.
Функции и работа с цветами
Препроцессоры умеют выполнять простые вычисления и предоставляют встроенные функции. Это удобно, когда вы хотите, например, осветлить или затемнить цвет, рассчитать ширину столбца и т.д.
Встроенные цветовые функции Sass
Давайте посмотрим на типичные примеры:
$primary: #3498db; // Исходный цвет
.button {
background-color: $primary; // Основной фон
border-color: darken($primary, 10%); // Темнее на 10 процентов
}
.button:hover {
background-color: lighten($primary, 5%); // Светлее на 5 процентов
}
Комментарии:
darken— делает цвет темнее на указанный процент.lighten— делает цвет светлее.- Есть и другие функции:
mix,saturate,desaturate,adjust-hueи т.д.
Так вы можете построить целую цветовую палитру на основе пары базовых цветов, не создавая десятки фиксированных значений вручную.
Пользовательские функции в Sass
Вы можете определить собственную функцию с помощью @function:
// Функция для перевода пикселей в rem
@function px-to-rem($px, $base: 16px) {
@return ($px / $base) * 1rem; // Возвращаем результат в rem
}
// Используем функцию внутри свойств
.text-large {
font-size: px-to-rem(24px); // Получаем rem на основе 16px
}
.text-small {
font-size: px-to-rem(14px, 14px); // База 14px, размер тоже 14px, будет 1rem
}
Здесь вы видите уже почти полноценное программирование внутри CSS-слоя.
Арифметика в стилях
Препроцессоры позволяют выполнять арифметические операции прямо в коде:
$gutter: 24px; // Отступ между колонками
$columns: 3; // Количество колонок
.column {
width: (100% / $columns) - $gutter; // Вычисляем ширину с учетом отступа
margin-right: $gutter; // Отступ справа
}
Обратите внимание: такие вычисления работают на этапе компиляции, а не в браузере.
Плейсхолдеры и @extend
Помимо миксинов, в Sass есть ещё одна конструкция для переиспользования — плейсхолдеры (placeholder selectors) и директива @extend.
Что такое плейсхолдер
Плейсхолдер — это селектор, который начинается с % и сам по себе в итоговый CSS не попадает. Он нужен только для того, чтобы другие селекторы могли унаследовать его стили.
// Определяем плейсхолдер
%button-base {
padding: 8px 16px;
border-radius: 4px;
border: none;
cursor: pointer;
}
// Наследуемся от плейсхолдера
.button-primary {
@extend %button-base;
background-color: #3498db;
color: #fff;
}
.button-secondary {
@extend %button-base;
background-color: #95a5a6;
color: #2c3e50;
}
Сгенерированный CSS будет выглядеть примерно так:
.button-primary,
.button-secondary {
padding: 8px 16px;
border-radius: 4px;
border: none;
cursor: pointer;
}
.button-primary {
background-color: #3498db;
color: #fff;
}
.button-secondary {
background-color: #95a5a6;
color: #2c3e50;
}
Комментарии:
@extendобъединяет селекторы, разделяя их запятыми.- Это уменьшает размер CSS-файла, но иногда может создавать слишком сложные селекторы, если переусердствовать.
Часто разработчики предпочитают миксины, потому что они более предсказуемо «копируют» код, а не объединяют селекторы.
Импорт и модули
Когда проект растет, хранить все стили в одном файле становится невыгодно. Препроцессоры позволяют разбивать код по модулям и подключать их.
Частичные файлы (partials) в Sass
В Sass есть понятие частичных файлов — их имя начинается с символа _. Например:
_variables.scss_mixins.scss_buttons.scss
Такие файлы обычно не компилируются в отдельный CSS напрямую, а подключаются в главный файл.
Пример структуры:
scss/
_variables.scss // Переменные
_mixins.scss // Миксины
_buttons.scss // Стили кнопок
style.scss // Главный файл, который все собирает
Подключение через @use и @forward
Современный Sass рекомендует использовать @use вместо старого @import.
// style.scss
@use "variables"; // Подключаем файл _variables.scss
@use "mixins"; // Подключаем файл _mixins.scss
@use "buttons"; // Подключаем файл _buttons.scss
Комментарии:
- Не нужно указывать нижнее подчеркивание и расширение — Sass сам их подставит.
@useимпортирует файл как модуль, у него есть свое пространство имен.
Если вы хотите использовать переменные и миксины из модуля, по умолчанию нужно писать namespace.$variable:
// variables.scss
$primary-color: #3498db;
// style.scss
@use "variables";
body {
background-color: variables.$primary-color; // Доступ через пространство имен
}
Чтобы упростить запись, можно задать псевдоним:
@use "variables" as v; // Используем короткий префикс v
body {
background-color: v.$primary-color;
}
А если вам нужно подключить модуль без префикса, можно использовать as *:
@use "variables" as *; // Импортируем все в глобальное пространство имен
body {
background-color: $primary-color; // Используем переменную напрямую
}
@import в Sass и Less
В старых версиях Sass использовали @import:
@import "variables";
@import "mixins";
@import "buttons";
Сейчас @import считается устаревшим в Sass, но в Less он по-прежнему основной способ подключения.
В Less это выглядит похоже:
@import "variables.less";
@import "mixins.less";
@import "buttons.less";
Stylus также поддерживает @import и @require.
Управляющие конструкции: условия и циклы
CSS сам по себе не умеет «думать». Препроцессоры добавляют простую логику: условия, циклы и т.п. Это особенно полезно для генерации повторяющихся стилей — например, сеток, классов по размерам, цветовых модификаторов.
Условия (@if, @else) в Sass
Давайте посмотрим, как это может выглядеть.
$theme: "dark"; // Текущая тема
body {
@if $theme == "dark" {
background-color: #222; // Темный фон
color: #eee; // Светлый текст
} @else if $theme == "light" {
background-color: #fff; // Светлый фон
color: #111; // Темный текст
} @else {
background-color: #f0f0f0; // Фон по умолчанию
color: #333;
}
}
Эта логика выполняется при компиляции. В итоговый CSS попадет только одна ветка, соответствующая значению $theme.
Циклы (@for, @each, @while)
@for — перебор числовых диапазонов
// Сгенерируем классы .m-1 ... .m-5 для отступов
@for $i from 1 through 5 {
.m-#{$i} { // #{} — интерполяция значения в селектор
margin: $i * 4px; // Отступ кратен 4px
}
}
Результат:
.m-1 { margin: 4px; }
.m-2 { margin: 8px; }
.m-3 { margin: 12px; }
.m-4 { margin: 16px; }
.m-5 { margin: 20px; }
@each — перебор списков или карт
// Задаем карту цветов с именами
$colors: (
primary: #3498db,
success: #2ecc71,
danger: #e74c3c
);
// Генерируем классы .text-primary, .text-success, .text-danger
@each $name, $color in $colors {
.text-#{$name} {
color: $color; // Присваиваем соответствующий цвет
}
}
Результат:
.text-primary { color: #3498db; }
.text-success { color: #2ecc71; }
.text-danger { color: #e74c3c; }
Как видите, этот подход позволяет удобно масштабировать систему утилитарных классов.
Сравнение Sass, Less и Stylus по ключевым возможностям
Здесь я кратко подведу сравнение по основным функциям, чтобы у вас сложилось целостное представление о css-preprocessors.
Синтаксис переменных
- Sass/SCSS —
$variable - Less —
@variable - Stylus —
variable(без префикса)
Вложенность и амперсанд
Все три препроцессора поддерживают вложенность и использование & для работы с текущим селектором.
Миксины и функции
- Sass —
@mixin,@include,@function. - Less — миксины определяются как обычные классы или функции, которые можно вызывать.
- Stylus — позволяет определять функции и миксины почти как в языках программирования, синтаксис более свободный.
Импорт и модульность
- Sass — современный путь через
@useи@forward, старый —@import. - Less —
@importс разными опциями. - Stylus —
@importи@require.
Поддержка и экосистема
- Sass (особенно в формате SCSS) — де-факто стандарт в большинстве современных фронтенд-проектов.
- Less — все еще встречается, особенно в старых проектах и некоторых UI-библиотеках.
- Stylus — популярность ниже, но он гибкий и мощный.
Если вы выбираете, с чего начать, имеет смысл опираться на Sass/SCSS: больше документации, примеров и поддержка в инструментах.
Интеграция препроцессоров в рабочий процесс
Использование с npm-скриптами
Вы можете настроить сборку через package.json. Давайте посмотрим, как это выглядит.
{
"scripts": {
"sass:build": "sass scss/style.scss css/style.css", // Одноразовая сборка
"sass:watch": "sass --watch scss:css" // Режим наблюдения
}
}
Комментарии:
sass:build— запускаете при сборке проекта.sass:watch— запускаете во время разработки.
Интеграция с Webpack (общая идея)
В проектах на React, Vue и других SPA-фреймворках обычно используют Webpack или другой бандлер. Там все устроено через лоадеры.
Типичная цепочка:
sass-loader— компилирует SCSS в CSS.css-loader— обрабатывает@importиurl().style-loaderилиmini-css-extract-plugin— добавляет стили на страницу или в отдельный файл.
Пример конфигурации (упрощенно):
// Пример конфигурации rules в Webpack
module.exports = {
module: {
rules: [
{
test: /\.scss$/, // Ищем файлы .scss
use: [
'style-loader', // Встраиваем стили в DOM
'css-loader', // Обрабатываем CSS-импорты
'sass-loader' // Компилируем SCSS в CSS
]
}
]
}
};
Комментарии в коде помогают вам увидеть порядок работы лоадеров.
Интеграция с Gulp (общая идея)
Если вы используете Gulp, схема такая:
- Берете SCSS-файлы.
- Пропускаете через плагин
gulp-sass. - Кладете результат в папку
css.
Упрощенный пример:
// Подключаем Gulp и плагин для Sass
const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
// Описываем задачу компиляции
function styles() {
return gulp.src('scss/style.scss') // Берем главный файл
.pipe(sass().on('error', sass.logError)) // Компилируем и логируем ошибки
.pipe(gulp.dest('css')); // Кладем результат в css
}
// Экспортируем задачу
exports.styles = styles;
Такой подход удобен в классических версточных проектах без тяжелых бандлеров.
Когда препроцессоры действительно нужны
Чтобы не было ощущения, что препроцессор — это просто модная технология, давайте зафиксируем реальные задачи, которые он решает:
Централизованное управление токенами дизайна
Цвета, размеры, типографика, отступы — все вынесено в переменные и карты.Переиспользование шаблонов
Миксины, плейсхолдеры и функции помогают не дублировать одно и то же.Удобная организация структуры стилей
Модули (частичные файлы) и импорт позволяют разбивать код по смыслу — base, layout, components и т.д.Генерация однотипных классов
Циклы и карты позволяют создавать целые группы утилитарных классов — по отступам, цветам, размерам.Улучшенная поддерживаемость
Код выглядит более декларативно и структурированно. Вложенность помогает понимать, к какой части интерфейса относится каждый блок стилей.
При этом важно помнить: препроцессор — не замена хорошей архитектуры стилей. Методологии (BEM, ITCSS, SMACSS), дизайн-системы и продуманная структура файлов по-прежнему важны.
Заключение
Препроцессоры CSS — это мощный слой над обычным CSS, который добавляет базовые возможности программирования: переменные, функции, миксины, условия, циклы и модульность. В результате вы пишете более структурированный, переиспользуемый и удобный для сопровождения код.
Sass/SCSS, Less и Stylus по сути решают одну и ту же задачу, различаясь синтаксисом и отдельными деталями. Наиболее распространенный вариант сегодня — Sass с SCSS-синтаксисом, часто в связке с бандлерами вроде Webpack или сборщиками типа Gulp.
Если вы работаете с небольшим проектом, уже на десятках стилей вы почувствуете пользу от переменных и миксинов. В более крупных интерфейсах без препроцессора поддерживать единообразие и управляемость стилей становится заметно сложнее.
Главная мысль: препроцессор не отменяет необходимости продумывать архитектуру CSS, но дает вам удобные инструменты, чтобы эту архитектуру реализовать аккуратно и эффективно.
Частозадаваемые технические вопросы по теме и ответы
Как лучше организовать структуру файлов с препроцессором в среднем проекте
Используйте простую схему:
base/— сброс стилей, базовая типографика.abstracts/илиutils/— переменные, функции, миксины.components/— отдельные компоненты интерфейса.layout/— сетки, общие контейнеры.pages/— специфичные стили для страниц.
Главный файл, например style.scss, только подключает остальные через @use или @import.
Как подключать общие переменные в нескольких отдельных SCSS-файлах
Создайте _variables.scss и подключайте его в каждом файле, где нужны переменные. С @use можно писать:
@use "../abstracts/variables" as v;
.button {
color: v.$primary-color; // Берем переменную из модуля
}
Так вы избегаете дублирования и держите токены дизайна централизованно.
Как лучше всего мигрировать проект с Less на Sass
Делайте поэтапно:
- Выделите в Less-файлах переменные, миксины и общие части.
- Создайте аналогичные
_variables.scssи_mixins.scss, переписав синтаксис. - Постепенно переносите компоненты: переписывайте конкретные
.lessфайлы на.scss. - Параллельно настройте сборку так, чтобы одновременно поддерживались оба типа файлов, затем отключите Less, когда перенос завершится.
Как отлаживать ошибки компиляции препроцессора
Используйте:
- Запуск в режиме watch — ошибки появляются сразу в консоли.
- Опцию генерации source maps (в Sass флаг
--source-mapили соответствующая настройка в бандлере). - Постепенное комментирование блоков — закомментируйте часть кода и сужайте область поиска, пока ошибка не исчезнет.
Как использовать препроцессор только для части проекта не переписывая все стили
Оставляете существующий style.css как есть, добавляете новый style.scss для новых компонентов. В HTML подключаете оба файла:
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/style-new.css">
Новые стили пишете в style.scss и компилируете в style-new.css. Постепенно можно переносить старые части в SCSS, пока не избавитесь от старого файла.
Постройте личный план изучения Vue до уровня Middle — бесплатно!
Vue — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Vue
Лучшие курсы по теме

Vue 3 и Pinia
Антон Ларичев
TypeScript с нуля
Антон Ларичев