Настройка CSS-препроцессоров для проекта сайта
Выбор препроцессора и его правильная настройка с первого дня — фундамент поддерживаемой CSS-архитектуры. Неправильная конфигурация приводит к дублированию импортов, медленной сборке, конфликтам между инструментами. Эта работа выполняется один раз и определяет удобство разработки на весь срок жизни проекта.
Выбор инструмента
| Критерий | SCSS | LESS | PostCSS | Tailwind |
|---|---|---|---|---|
| Синтаксис | CSS+ | CSS+ | CSS (нативный) | Утилиты |
| Миксины | Мощные | Есть | Через плагины | Нет |
| Функции | Расширенные | Базовые | Через плагины | Нет |
| Производительность сборки | Хорошая | Хорошая | Отличная | Отличная |
| Экосистема | Большая | Средняя | Огромная | Растущая |
| Новые проекты | Да | Legacy/AntD | Всегда | React/Vue |
Рекомендация: SCSS для классических проектов, Tailwind для React/Vue, PostCSS как обязательный слой поверх любого.
Настройка в Vite
# SCSS
npm install -D sass
# LESS
npm install -D less
# PostCSS и плагины
npm install -D postcss autoprefixer postcss-preset-env cssnano postcss-import
// vite.config.ts — полная конфигурация
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@styles': path.resolve(__dirname, 'src/styles'),
},
},
css: {
preprocessorOptions: {
scss: {
// Автоматически инджектировать переменные и миксины
additionalData: `
@use "@styles/abstracts/variables" as v;
@use "@styles/abstracts/mixins" as m;
@use "sass:math";
@use "sass:color";
@use "sass:map";
`,
// Использовать современный Dart Sass API
api: 'modern-compiler',
// Подавить устаревшие предупреждения
silenceDeprecations: ['legacy-js-api'],
},
},
// CSS Modules
modules: {
localsConvention: 'camelCase',
generateScopedName:
process.env.NODE_ENV === 'production'
? '[hash:base64:8]'
: '[name]__[local]__[hash:base64:4]',
},
// PostCSS применяется ко всему CSS после компиляции препроцессора
postcss: './postcss.config.js',
// Source maps в разработке
devSourcemap: true,
},
});
// postcss.config.js
const isProd = process.env.NODE_ENV === 'production';
module.exports = {
plugins: [
require('postcss-import'),
require('postcss-nested'),
require('postcss-custom-media'),
require('autoprefixer'),
require('postcss-preset-env')({
stage: 2,
features: {
'nesting-rules': true,
'custom-properties': false,
},
}),
...(isProd
? [require('cssnano')({ preset: ['default', { discardComments: { removeAll: true } }] })]
: []),
],
};
Настройка в Webpack
// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.(sa|sc)ss$/,
use: [
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: isProd
? '[hash:base64:8]'
: '[name]__[local]--[hash:base64:4]',
auto: /\.module\.(sa|sc)ss$/, // Только *.module.scss
},
importLoaders: 2,
sourceMap: !isProd,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
config: './postcss.config.js',
},
},
},
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
sassOptions: { outputStyle: 'compressed' },
additionalData: `@use "@/styles/abstracts" as *;`,
},
},
],
},
],
},
plugins: [
...(isProd ? [new MiniCssExtractPlugin({
filename: 'assets/[name].[contenthash:8].css',
chunkFilename: 'assets/[id].[contenthash:8].css',
})] : []),
],
};
Структура файлов препроцессора
src/styles/
abstracts/
_variables.scss
_functions.scss
_mixins.scss
_placeholders.scss
_index.scss ← @forward всего
base/
_reset.scss ← modern-normalize или custom
_typography.scss
_root.scss ← :root { --переменные }
components/ ← стили для каждого компонента
layout/ ← header, footer, grid, sidebar
themes/
_light.scss
_dark.scss
vendors/ ← переопределения сторонних библиотек
_swiper.scss
_leaflet.scss
main.scss ← точка входа
Lintering: Stylelint
npm install -D stylelint stylelint-config-standard-scss stylelint-order
// .stylelintrc.js
module.exports = {
extends: [
'stylelint-config-standard-scss',
],
plugins: ['stylelint-order'],
rules: {
// Порядок свойств
'order/properties-order': [
'content',
'position', 'top', 'right', 'bottom', 'left', 'z-index',
'display', 'flex', 'flex-direction', 'flex-wrap', 'gap',
'align-items', 'justify-content',
'grid', 'grid-template', 'grid-area',
'width', 'min-width', 'max-width',
'height', 'min-height', 'max-height',
'margin', 'padding',
'background', 'color', 'font', 'font-size', 'font-weight',
'border', 'border-radius',
'box-shadow', 'opacity', 'transform', 'transition', 'animation',
],
// SCSS-специфичные
'scss/at-rule-no-unknown': true,
'scss/no-duplicate-mixins': true,
'scss/no-global-function-names': true,
// Запрет вложенности глубже 3 уровней
'max-nesting-depth': 3,
// Запрет !important кроме исключений
'declaration-no-important': [true, { severity: 'warning' }],
},
};
// package.json scripts
{
"scripts": {
"lint:css": "stylelint \"src/**/*.{css,scss}\"",
"lint:css:fix": "stylelint \"src/**/*.{css,scss}\" --fix"
}
}
Browserslist
Autoprefixer и postcss-preset-env читают список целевых браузеров:
// .browserslistrc
[production]
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 11
[development]
last 1 chrome version
last 1 firefox version
last 1 safari version
Или в package.json:
{
"browserslist": {
"production": ["> 0.5%", "last 2 versions", "not dead"],
"development": ["last 1 chrome version", "last 1 firefox version"]
}
}
Сроки
Полная начальная настройка CSS-инфраструктуры (препроцессор + PostCSS + CSS Modules + Stylelint + Browserslist): 4–8 часов. Настройка для существующего проекта с миграцией: 1–2 дня. Эта работа окупается за первый же месяц разработки за счёт единообразия кода и исключения типовых ошибок.







