З Sass в PostCSS

18

Від автора: я працював з Sass протягом багатьох років. Але зараз я хочу поміняти спосіб написання стилів за допомогою PostCSS і плагіна cssnext. Мені подобається ідея, що вже сьогодні можна писати CSS синтаксисом майбутнього і використовувати інструменти, що підходять під ті, до яких я звик. Мій особистий сайт ідеально підходить для тестування нових функцій.

Першим моїм кроком був огляд того, чим я користуюся в Sass. Я повинен був знати, чим користувався раніше, щоб підшукати цього заміну в нових інструментах. Нижче я навів список того, чим я користувався в цьому проекті:

Частковий імпорт

змінні

вкладеність

міксини

extend

класи плейсхолдеры

функції кольору darken і rgba

стиснення

Підготовка

Перед переходом на новий синтаксис мені потрібно було виконати багато непотрібної роботи. Файлова структура проекту була заточена під Sass. Для частин я використовував нижнє підкреслення в назвах, а також підключив розширення scss. У мене було дві папки під Sass файли. У папці modules зберігався Sass, не конвертирующийся в CSS. Це змінні, класи плейсхолдеры і міксини. У папці partials зберігалися всі файли Sass, конвертирующиеся в CSS.

Початкова файлова структура:

css/
scss/
modules/
_module.scss

partials/
_partial.scss

tylergaw.scss

Всі частини Sass імпортувалися в файл tylergaw.scss.

@import «modules/setup»;
@import «modules/reset»;
@import «modules/fonts»;

Я перебудував структуру і перейменував файли. Першим ділом я змінив розширення з scss на css. Я використовував скрипт Bash:

for in f *.scss; do git mv — «$f» «${f%.scss}.css»; done;

Підкреслення теж були взяті з Sass, їх я теж видалив. Я не додумався, як зробити це через Bash, тому довелося видаляти їх вручну. (замітка собі: покращити знання з Bash)

Останній етап був – перемістити всі CSS файли в папку modules і видалити папку partials. Я вирішив, що звертатися до всіх CSS файлів у вигляді модулів набагато краще, ніж ділити їх по папках modules/partials.

Установка білду

Я почав з PostCSS CLI. Додав тимчасовий скрипт в файл package.json:

«scripts»: {
«postcss»: «postcss -o public/css/tylergaw.css src/css/tylergaw.css»
}

Скомпілював CSS, не змінюючи стилі:

npm run postcss

І вийшло! Майже. Помилок в консолі не було, але в один прекрасний день я отримав голу сторінку.

З Sass в PostCSS

Результат першого білду PostCSS

Тепер з допомогою функціоналу я міг повернути стилі на місце.

Заглянувши в консоль в Chrome, я побачив кілька помилок 404. Так я знайшов першу відсутню функцію — @import. У файлі tylergaw.css були лише @import’и для всіх CSS модулів. Браузер код бачив і робив, що вміє. Він намагався завантажити кожен модуль через HTTP запит. Мій білд копіює тільки один CSS файл, а не всі модулі. Тому браузер і не зміг їх знайти.

Я міг змінити процес і змусити працювати @import’и, але це було б неефективно. Потрібна була заміна @import з Sass.

Перший плагін

Для заміни @import з Sass я використовував плагін postcss-import. Після установки модуля через npm я оновив скрипт:

«scripts»: {
«postcss»: «postcss -u postcss-import -o public/css/tylergaw.css src/css/tylergaw.css»
}

Запустив скрипт ще раз за допомогою npm run postcss. В одному CSS файлі зберігалися всі модулі, і на сайт частково повернулися стилі.

З Sass в PostCSS

Результати білду PostCSS з плагіном postcss-import

З’явиться імпорт в CSS?

Вбудовування через @import перевернуло всю гру в Sass. Після появи цієї функції ми змогли краще організовувати стилі. Не впевнений, що цей функціонал коли-небудь з’явиться в звичайному CSS. Схоже, для таких речей завжди будуть потрібні білди, що не так вже й погано.

Плагін postcss-import стане обов’язковим для всіх моїх майбутніх проектів на PostCSS. Думаю, у багатьох буде так само. Цитата плагін: «Цей плагін повинен бути першим у вашому списку. Тоді інші плагіни будуть працювати у AST, ніби у вас всього один файл. Все буде працювати так, як ви очікуєте.»

Плагін cssnext

cssnext – PostCSS плагін для компіляції майбутнього синтаксис CSS синтаксису, який працює вже сьогодні. Важливо відзначити, що це не інша мова, як Sass або Less. Для всіх пропонованих функцій ще тільки розробляється специфікація. Якісь функції вже зараз працюють в браузерах. Інші знаходяться тільки на початковому етапі специфікації.

З допомогою cssnext я заповнив залишилися проблеми, які з’явилися після відходу від Sass.

Вендорные префікси

Коли я писав свій сайт, я ще не знав про Autoprefixer. Для додавання префіксів я використовував власні Sass міксини. У cssnext вбудований Autoprefixer, тому модуль з миксинами можна було видалити.

Змінні

Потім я замінив Sass змінні на власні властивості CSS. У файлі _setup.scss був код:

$grey: #1e1e1d;
$yellow: #ffad15;
$offwhite: #f8f8f8;
$darkerwhite: darken($offwhite, 15);

Це не всі змінні Sass, але найголовніші. Інші знаходяться в окремих модулях.

Зверніть увагу на різницю між корисними властивостями і змінними. Користувальницькі властивості дійсні тільки для значень властивостей. Їх не можна використовувати в селекторах, назвах властивостей і медіа запитах.

Оновлений файл setup.css:

:root {
—white: #fff;
—grey: #1e1e1d;
—yellow: #ffad15;
—offwhite: #f8f8f8;

}

Приклад з новим використанням:

a {
color: var(—yellow);
}

CSS користувальницькі властивості відрізняються від Sass змінних тільки синтаксисом. Через поганий підтримки в браузерах властивості досі компілюються. У прикладі вище скомпільований значення буде color: #ffad15.

Функції кольору

У попередньому прикладі я залишив одну змінну $darkerwhite: darken($offwhite, 15);, її теж потрібно замінити. Є чорнова специфікація для функції color. В плагіні cssnext ця функція вже є, і вона дуже крута. Нижче показаний код setup.css з користувальницьким властивістю darkerwhite і значенням у вигляді функції color і shade:

:root {

—offwhite: #f8f8f8;
—darkerwhite: color(var(—offwhite) shade(20%));

}

У функції color безліч модифікаторів. За раз можна використовувати кілька модифікаторів:

background-color: color(#d32c3f shade(40%) alpha(40%));

Компілюється в:

background-color: rgba(127, 26, 38, 0.4);

Повторимо. На даний момент cssnext компілює color() в hex або rgba значення. Як тільки функція color буде підтримуватися в браузерах, компіляція стане не потрібна, а кольором можна буде маніпулювати на льоту.

Вкладеність

Вкладеність – наріжний камінь CSS препроцесорів. Вкладеність необхідна для комфортної стилізації. Tab Atkins розробляє специфікацію вкладеності для CSS, а плагін cssnext дозволяє використовувати цю функцію вже зараз.

Це були квіточки. У синтаксисі вкладеності використовується знак & перед вкладеними блоками. Наприклад, нижче представлений код Sass зі сторінки мого проекту:

.projects-list {

li {
& > div {…}
}
a {

&:hover,
&:focus {…}
&::after {…}
}
@media (min-width: 640px) {…}
}

Я додав вкладеність, код перетворився в:

.projects-list {

& li {
& > div {…}
}
& a {

&:hover,
&:focus {…}
&::after {…}
}
@media (min-width: 640px) {…}
}

Для базової вкладеності необхідно використовувати символ &. Псевдокласи і селектори в Sass і CSS одні і ті ж. У медіа запитах символ & не потрібен.

Також потрібно згадати @nest. Як сказано в документації, складна вкладеність вимагає @nest замість &. У цьому проекті він мені не знадобився, може, в наступних знадобиться.

Extend і класи плейсхолдеры

Для загальних стилів в Sass я використовував @extend і класи плейсхолдеры. Приклад використання для заголовків:

%futura {
font-family: ‘futura-pt’, helvetica, sans-serif;
}
%futura-heading {
@extend %futura;
font-weight: 700;
line-height: 1.1;
text-transform: uppercase;
}

і приклад використання:

.my-heading {
@extend %futura-heading;
}

Як використовувати користувальницькі властивості ми вже подивилися. Правила @apply є специфікація, що знаходиться в розробці. Це правило дозволяє зберігати набір властивостей і посилатися на них в селекторах. Я використовував @apply замість extend.

Повернемося в setup.css, я оновив властивості заголовка:

:root {

—franklin: {
font-family: ‘futura-pt’, helvetica, sans-serif;
};
—franklin-heading: {
@apply —franklin;
font-weight: 700;
line-height: 1.1;
text-transform: uppercase;
};
}

і приклад використання:

.my-heading {
@apply —franklin-heading;
}

Правило @apply не еквівалент extend. У поточній формі в плагіні cssnext правило @apply копіює властивості та значення для кожного правила. Наш проект маленький, тому нас це не важливо. У великих проектах зайві властивості будуть засмічувати код. Краще, напевно, використовувати загальні назви класів для отримання таких результатів.

На даному етапі мій сайт виглядав так само, як до змін. Винятком була сторінка проектів. Там я використав різні кольори для кожної плитки проекту. Нижче я поясню, як правильно стилізувати цю сторінку без Sass і зайвого коду.

З Sass в PostCSS

Кольорові плитки сторінки проектів

Міксини з аргументами

Щоб спростити написання стилів, я використовував Sass міксини. Міксин приймав один аргумент, колір плитки. Міксин project-block:

@mixin project-block ($c) {
background-color: $c;
a {
color: $c;
&:hover {
background-color: $c;
color: $offwhite);
}
}
}

і приклад використання:

.p-jribbble {
@include project-block(#ff0066);
}

На момент написання статті я не зміг знайти заміну даного функціоналу в CSS. Користувальницькі властивості @apply не є функціями, в них не можна передати аргумент. Можливо, в майбутньому для передачі аргументів можна буде використовувати користувальницькі селектори. В чорновій специфікації є складний приклад, який виглядає багатообіцяюче. На даний момент я до кінця не розумію принцип роботи.

Але це не означає, що моя удача закінчилася. Мій CSS довше Sass, але не набагато. Також я використовував ще одну CSS функцію, яка знаходиться в розробці, збігаються селектори.

Приклад CSS заміни міксина project-block:

.p-jribbble,
.p-jribbble a:matches(:hover, :focus) {
background-color: var(—color-jrb);
& a {
color: var(—color-jrb);
}
}

Змінні кольори є кольорами :root вище у файлі. Плагін cssnext компілює CSS вище в:

.p-jribbble,
.p-jribbble a:hover,
.p-jribbble a:focus {
background-color: #ff0066
}
.p-jribbble a,
.p-jribbble a:hover a,
.p-jribbble a:focus a {
color: #ff0066;
}

Останні два селектора …a a:hover і …a a:focus не збігаються ні з одним елементом. Вони необов’язкові, але крім пари байт вони ніяк не впливають на код. Для кращої читаності я вкладав селектор a.

Ще більше PostCSS

Повернувши стилі в порядок, я вирішив додати ще кілька PostCSS плагінів. Для об’єднання медіа запитів з однією умовою я використовував css mqpacker. Для оптимізації коду я взяв плагін cssnano.

Саме із-за плагінів я хочу використовувати PostCSS. У Sass я був обмежений функціями поточної версії. PostCSS працює як колекція плагінів, він розширюваний. Якщо мені щось потрібно, я можу написати для цього плагін, дивовижний потенціал.

Висновок

Попрацювавши з цими налаштуваннями пару днів, я зовсім вымотался. Переключитися з Sass на новий синтаксис CSS було легко. І це після 5-6 років використання Sass у всіх своїх проектах.

Мені подобається, як змінилося моє мислення. У плагіна cssnext є схожий підхід для CSS, як у Babel для JS. Обидва підходи дозволяють писати нормальною мовою, а також на його майбутньої версії.