У нас, у фронтендеров, есть такая категория инструментов, которые никак не решают стоящие перед нами задачи, а скорее влияют на сам процесс их решения. Изменяют его. Отношение к таким инструментам самое разное – начиная от мании в духе “давайте эту штуку пихать везде, это же так круто” и заканчивая отговорками вроде “раз не решает задачи бизнеса, значит оно нам не нужно”. Но, так или иначе, сегодня мы поговорим про PostCSS — один из таких инструментов.
Волна хайпа уже давно прошла, в последнее время про PostCSS говорят очень мало. Многие новички даже не знают, что это такое. Думаю самое время посмотреть на этот инструмент с точки зрения практического использования в самых обычных проектах, где люди решают задачи, а не играются с модными технологиями.
PostCSS vs SASS
Ох… Видимо стоит сказать пару слов про это. Думаю сейчас редкий верстальщик не встречался с препроцессорами. SASS или любимый мною LESS, реже Stylus, применяют и на больших проектах, и на маленьких. Кто-то пытается выжимать из них максимум, кто-то использует минималистичный набор – вложенность, переменные, импорты. Но, так или иначе, эти инструменты помогают с вопросами синтаксиса. Они делают так, чтобы нам было удобнее писать код.
Года два-три назад PostCSS постоянно сравнивали с препроцессорами. И это понятно. Формально с его помощью можно сделать все то же самое, сделать какой-то синтаксис, который будет удобнее, чем чистый CSS. Но все это вызывало бурления в массах, в основном потому, что каждый с помощью PostCSS делал что-то свое. Бесчисленные неизвестные плагины, миллионы комбинаций и кроме автора того или иного конфига никто не понимал, как он работает и что делает. Это как Vim или Emacs – можно из них сделать космический корабль, но научить другого разработчика им пользоваться будет очень непросто.
Но если эти сравнения отбросить, то PostCSS – это инструмент, который позволяет взять наш CSS и что-то с ним сделать. Никто не мешает использовать SASS ради синтаксиса, а после сборки воткнуть PostCSS и что-то сделать с результатом. Они друг другу не противоречат.
Старое – не значит неработающее
В последнее время у нас модно создавать комбайны, которые умеют делать все, что только в голову придет, и их разработка никогда не прекращается. А если в репозитории уже пару месяцев нет свежих коммитов, то все – можно считать, что он устарел и пользоваться им теперь – не комильфо. Я утрирую, конечно, но думаю вы и сами замечали, до какого абсурда это иногда доходит.
В мире PostCSS обычно один плагин решает одну задачу. Можно тут увидеть элементы философии Unix. Из этого следует логичный вывод – если плагин уже решает свою задачу, то больше с ним ничего особо делать не нужно. Вы можете встретить плагины, которые годами не обновлялись, но это не значит, что они вдруг перестали решать задачи, для которых были созданы.
Но приступим… Я собрал десяток плагинов, которые на практике показали свою способность упрощать жизнь верстальщикам и экономить время при разработке. Но вы всегда можете добавить что-то в комментариях.
№1. Doiuse
https://github.com/anandthakker/doiuse
Думаю все мы сталкивались с такой проблемой: пишешь код, проверяешь в хроме – все ок. Проверяешь в FF – ок. А потом в мобильном Safari все разваливается. Или в Edge. И ты сидишь и не понимаешь, что не так. Потом долго пялишься в код, пьешь чай, и вдруг приходит озарение, что какое-то свойство не поддерживается в каком-то браузере. Идешь на caniuse и видишь подтвержение очевидного.
Конечно, с опытом руки сами запоминают, какие свойства нужно избегать, но всякое бывает. Можно не выспаться, могут быть сжатые сроки и нервы, может поменяться список браузеров, которые нужно поддерживать. И тут опыт начнет подводить. Doiuse – это инструмент, который очень выручает в таких ситуациях.
Принцип работы прост – мы скармливаем ему список браузеров и наш CSS. Плагин идет в базу caniuse и в реальном времени выдает нам ответ, что мы поиспользовали из того, что не поддерживается.
Список браузеров мы можем задавать прямо в package.json. Просто и удобно. PostCSS использует browserslist и, если вы не видели раньше, то выглядит это примерно так:
"browserslist": [
"> .5% and last 2 versions",
"not dead",
"not OperaMini all",
"ie >= 11",
"Edge >= 12"
]
Также есть конфиг самого doiuse, в котором можно заставить его игнорировать некоторые группы свойств, если вы уверены, что это ни на что не влияет. Например если вы используете полифилы или от потери поддержки какого-то свойства ничего не изменится:
ignore: [
'will-change',
'object-fit'
]
Стандартный лог, который дает плагин, не очень читаемый. Он содержит много информации и воспринимать его не очень удобно. Но это дело поправимое. В том же конфиге мы можем сделать свою функцию для формирования лога.
Используйте console.log чтобы сообразить, как устроен объект, который передает PostCSS в эту функцию. Там много всего интересного.
Моя практика показала, что самый удобный вариант – это выводить селекторы и конкрентые свойства, которые не поддерживаются, без уточнения браузеров и строк кода. Если в проекте используется БЭМ или какие-то аналоги, и код компонентов распределен по отдельным файлам, то такой подход позволяет быстро находить проблемное место не нагружая
onFeatureUsage(info) {
const selector = info.usage.parent.selector;
const property = `${info.usage.prop}: ${info.usage.value}`;
let status = info.featureData.caniuseData.status.toUpperCase();
if (info.featureData.missing) {
status = 'NOT SUPPORTED'.red;
} else if (info.featureData.partial) {
status = 'PARTIAL SUPPORT'.yellow;
}
console.log(`n${status}:nn ${selector} {n ${property};n }n`);
}
Чтобы не писать специальные последовательности символов для цветов в консоли, можно подключить пакет colors, с ним будет удобнее.
При сборке будет примерно такой вывод в консоли:
NOT SUPPORTED:
html {
-ms-text-size-adjust: 100%;
}
NOT SUPPORTED:
html {
-webkit-text-size-adjust: 100%;
}
PARTIAL SUPPORT:
body {
display: flex;
}
№2. Autoprefixer
https://github.com/postcss/autoprefixer
Даже как-то неловко про него говорить, но уж слишком часто вижу людей, которые в 2019 году пишут префиксы руками и еще уверяют окружающих, что они точно знают, какие из них нужны, а какие – нет. Такие действия приводят к тому, что код зарастает кучей ненужных префиксов и становится совершенно нечитаемым. Это влияет на производительность труда. С другой стороны, если нужна поддержка динозавров, то всегда можно что-то забыть. Так что от ручного труда при решении этой задачи стоит избавляться.
Автопрефиксер работает все с той же базой caniuse, использует тот же browserslist и может добавлять в CSS те префиксы, которые действительно нужны в указанных нами браузерах. При этом сам код становится чище, а работа идет быстрее.
№3. Stylelint
https://github.com/stylelint/stylelint
Когда много и быстро печатаешь, то рано или поздно начинаешь допускать много ошибок, совершенно их не замечая. Глаз замыливается. В случае с CSS это может давать забавный (на самом деле нет) эффект, когда ты смотришь в браузер – видишь проблему с версткой. Смотришь в код – ее там нет. Смотришь в браузер – она есть. А в коде – нет. В результате можно долго искать сложную проблему, совершенно не замечая, что просто очепятался. Чтобы такого не было, придумали линтеры.
Stylelint – это популярный вариант. Он умеет работать с синтаксисами основных препроцессоров, знает о последних веяниях в CSS, можно настраивать на свой вкус – конфиги похожи на те, что у eslint. Формально этот инструмент можно использовать и сам по себе, без PostCSS, но не упомянуть его здесь было бы неправильно.
№4. Postcss-flexbugs-fixes
https://github.com/luisrudge/postcss-flexbugs-fixes
Или в более широком смысле postcss-fixes, в состав которого этот плагин входит. Медленно, но верно, флексы вытесняют старый подход к верстке на флоатах. Это хорошо, но все мы знаем, что с ними связан набор багов. Они описаны в репозитории flexbugs. Некоторые из них требуют к себе особого внимания, но также есть несколько штук, которые настолько простые, что постоянно вылетают из головы. Например IE игнорирует функцию calc в сокращенной записи свойства flex. Это не так часто нужно, но если понадобится, то руки могут сами написать сокращенный вариант и потом придется долго думать, в чем проблема. К счастью это дело можно исправить в автоматическом режиме. На помощь приходит плагин postcss-flexbugs-fixes.
В примере с calc он найдет в коде фрагменты вроде этого:
.foo {
flex: 1 0 calc(1vw – 1px);
}
И развернет их:
.foo {
flex-grow: 1;
flex-shrink: 0;
flex-basis: calc(1vw - 1px);
}
Просто и удобно.
№5. Postcss-preset-env
https://github.com/csstools/postcss-preset-env
Раз уж мы говорим про поддержку браузерами, то будет не лишним сказать про postcss-preset-env. Раньше ту же роль выполнял cssnext. Этот плагин будет полезен, если вы интересуетесь новыми веяниями в CSS.
Многие из нововведений технически можно реализовать и старыми методами, просто это будет долго, многословно и некрасиво. Preset-env помогает писать код по-новому, экономить на этом время, а потом преобразовывать его в старый надежный вариант. Разумеется, некоторые вещи вроде кастомных свойств совсем не реализованы в старых браузерах, так что там будут применяться фолбеки.
Как можно догадаться по названию инструмента, он напоминает одноименный пресет у Babel. Здесь все так же – много преобразователей, собранных в один стабильный набор. Некоторые преобразования требуют последующее подключение скриптов-полифилов на клиенте, но большинство реализуется чисто средствами CSS. Насколько я понимаю, для Stage2+ скрипты не нужны. Во всяком случае не сталкивался с их необходимостью. Поправьте меня, если я что-то там пропустил.
№6. Postcss-animation
https://github.com/zhouwenbin/postcss-animation
Часто слышу от разных людей (в основном это бэкендеры, которые не очень сильны в CSS), что они хотят использовать отдельные анимации из animate.css, но считают плохой идеей подключать всю библиотеку целиком. Вполне логично. Но в результате они тратят много времени пытаясь повторить эти анимации самостоятельно.
Плагин postcss-animation очень ускоряет этот процесс. Мы пишем только название анимации, например:
.foo {
animation-name: bounce;
}
А он сам подтягивает из animate.css реализацию и вставляет ее в код.
.foo {
animation-name: bounce;
}
@keyframes bounce {
from, 20%, 53%, 80%, to {
animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
transform: translate3d(0,0,0);
}
40%, 43% {
animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transform: translate3d(0, -30px, 0);
}
70% {
animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transform: translate3d(0, -15px, 0);
}
90% {
transform: translate3d(0,-4px,0);
}
}
№7. List-selectors
https://github.com/davidtheclark/list-selectors
Когда у вас есть несколько верстальщиков и много стилей, встает вопрос о code review, о том, что было бы неплохо иногда глазами видеть общую картину со всеми селекторами, которые у нас есть. Знать, какие ID используются, есть ли селекторы по тегам или насколько соблюдается принятая методология. Особенно это важно, когда вы проверяете код новичка, который может писать странные вещи, которые формально будут работать, но фактически будут идти вразрез с принятыми соглашениями (далеко не везде эти соглашения хорошо зафиксированы и есть возможность такие вещи автоматизировать). Самому пролистывать многочисленные файлы со стилями, чтобы проверить адекватность селекторов, долго. Нужен способ вычленить их и показать отдельно. List-selectors как раз решает эту задачу.
Точно так же, как и doiuse, этот плагин позволяет использовать свою функцию для подготовки информации к выводу на экран. Можно вывести только то, что интересует, или раскрасить все в разные цвета. Как пример:
require('list-selectors').plugin((list) => {
const inspect = require('util').inspect;
console.log('SELECTORS:'.blue);
console.log(inspect(list.selectors, { maxArrayLength: null }).blue);
console.log('IDS:'.red);
console.log(inspect(list.simpleSelectors.ids, { maxArrayLength: null }).red);
})
В этом примере получится длинный-длинный список селекторов:
SELECTORS:
[
'.mui-progress-bar',
'.mui-progress-bar > .indicator',
'.mui-progress-bar > .value',
'.mui-progress-bar.-radial',
'.mui-progress-bar.-radial > .indicator',
'.mui-progress-bar.-radial > .indicator > .background',
'.mui-progress-bar.-radial > .indicator > .progress',
'.mui-progress-bar.-radial > .value',
. . .
№8. Immutable-CSS
https://github.com/johno/immutable-css
Еще одна вещь, за которой стоит следить – это перебивание стилей из сторонних библиотек. Если мы подключили какую-то библиотеку, а потом начинаем для селекторов из нее писать свои стили, то в конечном счете получаем запутанный код, в котором не разобрать, что откуда взялось. Это может приводить к случайным багам, которые потом отнимают слишком много времени на ровном месте. Чем больше раз мы что-то переопределяем, тем сложнее в конечном счете понять, что происходит, хотя сама проблема, которую нужно решить, может быть очень простой. В этой ситуации может пригодиться инструмент под названием immutable-css.
В целом принцип его работы прост: берет файлы со стилями, если находит совпадения по селекторам – начинает возмущаться:
! .button was mutated 2 times
[line 93, col 1]: /css/basscss.css
[line 3, col 1]: /css/custom.css
[immutable-css]
! .left was mutated 2 times
[line 291, col 1]: /css/basscss.css
[line 4, col 1]: /css/custom.css
[immutable-css]
Единственная проблема у данного инструмента – это то, что он не поддерживает не-CSS синтаксис. Так что если в проекте используются препроцессоры, то сравнивать приходится уже собранные файлы. Но в целом, если задача состоит в том, чтобы просто убедиться, что никто случайно не переписал стили из сторонней библиотеки, то это не так важно.
№9. Bye-Bye!
https://github.com/AoDev/css-byebye
Думаю всем знакома ситуация, когда мы постепенно добавляем какие-то компоненты на работающий сайт. Какие-то из них отправляются сразу в продакшен, а какие-то долго сидят и ждут своей очереди (например сверстать-то мы сверстали, а не бэкенде еще что-то не доделали). Что-то может быть экспериментом или временным решением на праздники. Ситуаций может быть много, но их объединяет то, что у нас набирается куча компонентов, а на боевом сайте используются лишь малая часть из них. Было бы хорошо убрать все, что не используется, из текущей сборки. Это может заметно уменьшить ее размер, а также снизить головную боль в перспективе, когда нужно будет делать редизайн к примеру, и встанет вопрос, что же из всего этого действительно нужно переписывать сейчас, а что — нет.
Есть разные подходы к этому вопросу. На ум сразу приходит uncss. Этот инструмент в автоматическом режиме определяет, какие стили используются на страницах и убирает лишнее. Но на практике это почти всегда приводит к тому, что никто не знает, что реально используется, а что – нет. А еще я все время сомневаюсь, не удалил ли этот инструмент чего лишнего. Но это наверное уже моя паранойя. Хотя...
Bye-bye – это более простой инструмент, которому мы сами скармливаем список селекторов, которые нужно убрать из CSS. Причем можно использовать регулярные выражения. Если вы применяете БЭМ или что-то еще в этом духе, то одной простой регуляркой можно удалять блок со всем, что к нему относится. Bye-bye!
Такой подход оказался довольно удобным. Сразу ясно, какие стили сейчас еще не используются или были убраны за ненадобностью, при этом все исходники на месте, все настройки в одном файле, ничего не потеряется, не вызывает трудностей сделать несколько разных сборок, а главное – решение простое и предсказуемое.
№10. PostCSS-trolling
https://github.com/juanfran/postcss-trolling
Все предыдущие инструменты могут незначительно повысить производительность труда ваших верстальщиков, но этот дает просто феноменальные результаты. Очень рекомендую.
Заключение
PostCSS – это хорошее подспорье для верстальщика. Если им не злоупотреблять, конечно. Для многих проблем, отнимающих много времени, есть готовые решения в виде плагинов, и, хотя они зачастую не развиваются и кажутся заброшенными, это не мешает их использовать.
Автор: Ivan Bogachev