Вёрстка сайту з PostCSS
PostCSS — інструмент трансформації CSS через JavaScript-плагіни. Сам по собі нічого не робить — все поведінку задають плагіни. Tailwind CSS працює на PostCSS. Autoprefixer — плагін PostCSS. CSS Modules обробляються PostCSS. PostCSS — не заміна SCSS, а шар трансформації, який можна використовувати в поєднанні з будь-яким препроцесором або без нього.
Встановлення та базова конфігурація
npm install -D postcss
// postcss.config.js
/** @type {import('postcss').Config} */
module.exports = {
plugins: [
require('postcss-import'), // @import → інлайн
require('postcss-nested'), // Вкладеність як у SCSS
require('postcss-custom-media'), // Custom Media Queries
require('autoprefixer'), // Вендорні префікси
require('postcss-preset-env')({ // Сучасний CSS → сумісний
stage: 2,
features: {
'nesting-rules': true,
'custom-properties': false, // Залишити нативні
'color-function': true,
},
}),
...(process.env.NODE_ENV === 'production'
? [require('cssnano')({ preset: 'default' })]
: []),
],
};
PostCSS-конфіг у Vite читається автоматично з кореня проекту або через css.postcss у vite.config.ts.
Ключові плагіни
postcss-import
Замінює @import на вміст файлів прямо при збірці — єдиний CSS-файл без HTTP-запитів:
/* src/styles/main.css */
@import "./reset.css";
@import "./tokens.css";
@import "./base.css";
@import "./components/button.css";
@import "./components/card.css";
@import "./layout/header.css";
@import "./pages/home.css";
postcss-nested — вкладеність без SCSS
/* До обробки */
.card {
background: var(--color-surface);
border-radius: var(--radius-lg);
&:hover {
box-shadow: var(--shadow-md);
}
& .card-title {
font-size: 1.25rem;
font-weight: 600;
}
@media (min-width: 768px) {
padding: 2rem;
}
}
/* Після обробки */
.card { background: var(--color-surface); border-radius: var(--radius-lg); }
.card:hover { box-shadow: var(--shadow-md); }
.card .card-title { font-size: 1.25rem; font-weight: 600; }
@media (min-width: 768px) { .card { padding: 2rem; } }
postcss-custom-media
/* Визначити кастомні медіа-запити один раз */
@custom-media --sm (min-width: 576px);
@custom-media --md (min-width: 768px);
@custom-media --lg (min-width: 1024px);
@custom-media --xl (min-width: 1280px);
@custom-media --dark (prefers-color-scheme: dark);
@custom-media --motion-ok (prefers-reduced-motion: no-preference);
/* Використання */
.hero {
padding: 3rem 1rem;
@media (--md) {
padding: 6rem 2rem;
}
@media (--lg) {
flex-direction: row;
padding: 8rem 3rem;
}
}
.card {
@media (--dark) {
background: #1e293b;
color: #f1f5f9;
}
}
.animated-element {
@media (--motion-ok) {
transition: transform 300ms ease;
}
}
postcss-preset-env — нативний сучасний CSS
/* Нативний CSS nesting (Level 4) → PostCSS розворачує для старих браузерів */
.nav {
display: flex;
gap: 1rem;
& a {
color: var(--color-text-secondary);
&:hover {
color: var(--color-text-primary);
}
&[aria-current="page"] {
color: var(--color-accent);
font-weight: 500;
}
}
}
/* :is() та :where() */
:is(h1, h2, h3, h4) {
font-weight: 600;
line-height: 1.3;
}
/* color-mix() */
.button-hover {
background: color-mix(in srgb, var(--color-accent) 85%, black);
}
/* oklch кольори */
.primary {
color: oklch(50% 0.2 264);
}
cssnano — мініфікація
// Тонка настройка cssnano
require('cssnano')({
preset: ['advanced', {
discardComments: { removeAll: true },
reduceIdents: false, // Не перейменовувати @keyframes
zindex: false, // Не оптимізувати z-index
colormin: true,
minifyFontValues: true,
}],
})
Власний PostCSS-плагін
Коли стандартних плагінів не вистачає:
// postcss-theme-tokens.js
const plugin = require('postcss').plugin('postcss-theme-tokens', (opts = {}) => {
return (root) => {
root.walkRules((rule) => {
if (rule.selector === ':root') {
rule.walkDecls(/^--/, (decl) => {
// Логувати всі токени для документації
if (opts.log) {
console.log(`Token: ${decl.prop} = ${decl.value}`);
}
});
}
});
};
});
module.exports = plugin;
Або через сучасний API:
// postcss-strip-debug.mjs
export default {
postcssPlugin: 'postcss-strip-debug',
Declaration(decl) {
// Убрати border: 1px solid red; з production
if (
process.env.NODE_ENV === 'production' &&
decl.prop === 'border' &&
decl.value.includes('red')
) {
decl.remove();
}
},
};
export const postcss = true;
PurgeCSS через PostCSS
npm install -D @fullhuman/postcss-purgecss
// postcss.config.js
module.exports = {
plugins: [
...(process.env.NODE_ENV === 'production'
? [
require('@fullhuman/postcss-purgecss')({
content: ['./src/**/*.{html,jsx,tsx,vue}'],
defaultExtractor: (content) =>
content.match(/[\w-/:]+(?<!:)/g) || [],
safelist: {
standard: [/^is-/, /^has-/, /^data-/],
greedy: [/modal/, /tooltip/],
},
}),
]
: []),
],
};
Інтеграція з SCSS
PostCSS та SCSS працюють послідовно — SCSS компілюється першим, PostCSS обробляє результат:
// vite.config.ts
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/abstracts" as *;`,
},
},
postcss: {
plugins: [autoprefixer(), cssnano()],
},
},
});
Терміни
Настройка ланцюга PostCSS-плагінів для проекту: 2–4 години. PostCSS, як правило, додається до існуючого інструментарію, а не використовується самостійно. Написання кастомного плагіну для специфічної задачі: 2–6 годин залежно від складності трансформації.







