Чем препроцессор CSS отличается от постпроцессора?

JuniorFrontend инструменты #tooling #css #preprocessors

Вопрос

В чём разница между препроцессором (Sass/Less) и постпроцессором (PostCSS) CSS, и куда в этой картине вписывается Tailwind?

Короткий ответ

Препроцессор (Sass, Less) добавляет свой собственный синтаксис — переменные, вложенность, миксины, — которого не существует в обычном CSS, и компилирует его в чистый CSS. Постпроцессор (PostCSS) на входе получает уже валидный CSS и трансформирует его через плагины — например, автоматически добавляет вендорные префиксы.

Подробный ответ

Препроцессоры (Sass/SCSS, Less, Stylus):

  • Работают со своим расширенным синтаксисом (.scss, .less), который CSS-парсер браузера не понимает.
  • Дают возможности, которых долго не было в самом CSS: переменные ($primary), вложенность селекторов, миксины (переиспользуемые блоки стилей с параметрами), математику, @extend, циклы/условия (в Sass).
  • Результат работы — компиляция в обычный .css, который уже отдаётся браузеру.
  • Многое из этого сегодня частично покрывается нативным CSS (CSS-переменные --var, вложенность через CSS Nesting), поэтому актуальность чистых препроцессоров снижается, но миксины и логика (@each, @if) остаются их преимуществом.

Постпроцессоры (PostCSS):

  • На вход получают уже синтаксически валидный CSS, а не расширенный диалект.
  • PostCSS сам по себе — это просто движок с плагинной архитектурой (парсит CSS в AST и даёт плагинам его трансформировать). Вся логика — в плагинах:
    • autoprefixer — добавляет вендорные префиксы (-webkit-, -moz-) на основе таблицы поддержки браузеров (browserslist).
    • postcss-preset-env — позволяет писать будущий CSS уже сегодня, транспилируя в поддерживаемый браузерами вариант.
    • cssnano — минификация.
  • Важное отличие: постпроцессор ничего не "выдумывает" синтаксически — он не создаёт новый язык, а работает над тем, что уже CSS (или почти CSS).

Tailwind CSS — это utility-first фреймворк (готовые классы вроде flex, p-4, text-red-500 вместо написания своих правил), а технически он реализован как PostCSS-плагин: на этапе сборки он сканирует ваши файлы разметки, находит использованные классы и генерирует под них итоговый CSS. То есть Tailwind — это не препроцессор и не альтернатива PostCSS, а один из плагинов/потребителей PostCSS-конвейера.

На практике препроцессор и постпроцессор часто используют вместе: пишут .scss, Sass компилирует его в CSS, а дальше PostCSS (autoprefixer, Tailwind) дообрабатывает результат.

Пример

// styles.scss — препроцессор: переменные, вложенность, миксин
$primary: #3b82f6;

@mixin button-base {
  padding: 0.5rem 1rem;
  border-radius: 0.375rem;
}

.card {
  border: 1px solid #eee;

  .title {
    color: $primary;
    font-weight: 600;
  }

  .btn {
    @include button-base;
    background: $primary;
  }
}
// postcss.config.js — постпроцессор: плагины над уже готовым CSS
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {}, // добавит -webkit-, -moz- и т.д.
    cssnano: process.env.NODE_ENV === 'production' ? {} : false,
  },
}

Дополнительные вопросы

  • Что из возможностей Sass уже можно делать нативным CSS без препроцессора?
  • Как работает browserslist и откуда autoprefixer узнаёт, какие префиксы нужны?
  • Почему Tailwind в проде даёт маленький файл CSS, хотя классов в фреймворке тысячи?