Комментарии 64
Но если у вас несколько плагинов PostCSS — то тут преимущество подхода gulp-postcss очевидно — CSS парситься только один раз, что сильно ускоряет процесс.
Но может вам поможет такое сравнение — PostCSS — это как Babel 6 (который с плагинами и может делать всё что угодно, а не только ES6), только для CSS. У PostCSS даже есть cssnext, который как раз «CSS4» делает.
Пост- — это в значении после.
В контексте CSS доминируют препроцессоры, они общеизвестны, они де-факто уже базовая технология. Все новые технологии неизбежно сравниваются с ними и противопоставляются им. Какие можно поиметь ассоциации, сравнивая «пост-» с «пре-»? Вполне однозначные.
PostCSS — это в первую очередь парсер CSS. Используя этот парсер вы и можете создавать плагины. Как чисто в PostCSS, так и для Gulp и webpack.
На самом деле сам webpack (точнее css-loader) и использует PostCSS, чтобы разворачивать import и url.
А парсинг CSS — это один из самых длинных шагов в обработки CSS. Зависит от задачи, но часто 50-80% (можете поиграться в бенчмарке postcss).
Это как babel, только в мире css.
zharikovpro css-loader под капотом использует webpack.
Miklos потом вам понадобится еще какой-то плагин, который работает поверх postcss и он заново будет парсить css, вместо того, чтобы сделать это внутри postcss. Это тоже вариант, просто не стоит себя обманывать, что вы обходитесь без postcss, он уже внутри gulp-autoprefixer.
postCSS
в подкасте Веб-стандарты
. Вникать пока было некогда. Понравилась идея о том, что можно написать плагин, который может на входе сразу получить распарсенный CSS и модифицировать в нём только то, что необходимо, передав вожжи следующему плагину. Вопрос: можно ли без крови написать плагин, который будет изменять правила, в которых есть какое-нибудь собственное CSS-свойство (допустим base64: background
), таким образом, чтобы в указанном свойстве заменять значение с URI
на base64
, а само синтетическое свойство удалять? Если я правильно вас понял, то такое должно быть на раз плюнуть. Пример немного грубый, но всё же...?Примерно для таких вот костылей он и задуман?
Да, можно и довольно легко.
Но лучше использовать не свойства, а функцию — тогда base64 можно буде использовать в разных свойствах (и background, и mask). Уже даже несколько написаны: для любых файлов, для SVG со сменой цвета.
Я пока склоняюсь к ручному указанию какие свойства в каких правилах подключать inline, а какие нет. Вариант с псевдо-свойством мне кажется довольно удобным. Потому что в качестве альтернативы я вижу возможность указывать этот список где-то в конфигах, в отрыве от самих стилей.
Я хочу чтобы весь этот изврат с base64 был только при сборке
К тому же inline-ы и в compass-е есть
Но можно делать и инлайн при деплое. Но только учтите, что тогда кастомное свойство уже не подходит — без сборки оно будет невалидно.
без сборки оно будет невалидно.
учитывая что это не уходит дальше dev-машины — не вижу никакой проблемы :)
dev
:.some {
background: url('1.png');
_base64: 'background';
}
На
production
:.some { background: url(data....); }
Но проще будет не писать два раза. PostCSS настолько быстр, что во время разработки его можно запускать на каждое изменение. У нас он отрабатывает меньше секунды (а мы очень много инлайним).
PostCSS настолько быстр
А причём тут
postCSS
? Он работает на магии и единорогах? Если программе при каждом запуске потребуется считывать множество файлов целиком и конвертировать их в base64, то оно просто не может не тормозить. Это же изнасилование файловой системы. меньше секунды
1000ms это очень медленно.
а мы очень много инлайним
больше 100 KiB?
PostCSS из-за модульной архитектуры проще оптимизировать — всегда видно, где самый затык по скорости.
Да, у нас около 10 файлов по 200—400 КБ.
Хороший пример — шрифты. Я инлайню главное начертание, а жирное (если оно используется редко) — нет.
Я поэтому тоже предпочитаю инлайнить вручную с помощью postcss-assets.
Например, browsersync позволяет сделать так
Итог, наверное, будет даже быстрее Less. Sass и Less — монолитные огромные проекты, которые сложно оптимизировать. А PostCSS модульный, каждый делает только один модуль и старается делать его оптимально. В итоге у нас сейчас один из самых быстрых парсеров CSS (самый быстрый на JS из тех, кто парсят без ошибок) — а время парсинга один из самых длинных процессов.
Если говорить только о примесях, вложенности и математике, то PostCSS уже быстрее Less в 4 раза.
gulp.task('styles', function () {
var processors = [
autoprefixer({browsers: ['last 5 versions']}),
mqpacker, // объединяем «одинаковые селекторы» в одно правило
cssSimple, // полифилы, хаки для браузеров, удаление ненужного кода
csswring({preserveHacks: true}) // Minify CSS file with source maps.
];
return gulp
.src(paths.devroot.scss)
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(postcss(processors).on('error', onError))
.pipe(sourcemaps.write("./"))
.pipe(gulp.dest(paths.webroot.base));
});
Аннотации?!
Команда Compass уже прекратила его развитие и тоже считает, что Автопрефиксер работает на порядок лучше.
Команда Compass уже прекратила его развитие и тоже считает, что Автопрефиксер работает на порядок лучше.
Звучит бредово. Кто-то использовал compass только из-за миксинов автопрефиксера? :) Дурь же…
Скорее вы хотели сказать, что "postCSS работает на порядок лучше", ибо там нужна уйма плагинов.
Кстати говоря, я думаю не стоит повсеместно применять выражение "на порядок". Это ж в 10 раз лучше. В 10, Карл, в 10!
Собственно, на прошедшем SassSummit Крис Эпштейн и заявил, что Compass закрыт — будут только мелкие обновления типа безопасности.
Ну и в Париже на CSSConf он мне это подтвердил.
В общем вы убедили меня попробовать разобраться с PostCSS
и "выбросить" Compass
. Здесь я опишу свой опыт внедрения.
Сейчас я работаю над проектом, построенном на Django
. Всю "статику" я положил в папку public/static/
, в которой еще 6 папок: css
, fonts
, img
, js
, maps
и sass
. Перво-наперво установим NodeJS в систему, потом переходим в папку с проектом и спомощью комманды: npm init
создаём package.json
. Далее через npm install
ставим "gulp" (его понадобилось установить два раза — глобально и локально). Далее ставим такой набор модулей: gulp-sass, postcss-scss, gulp-postcss, autoprefixer, postcss-assets, postcss-font-magician, cssnano, postcss-inline-svg, gulp-sourcemaps, gulp-cached.
Далее также в папке проект создаём файл gulpfile.js
, в него помещаются задачи для Gulp-а, я для себя сделал так:
'use strict';
var gulp = require('gulp');
var sass = require('gulp-sass');
var syntax = require('postcss-scss');
var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer')({browsers: ['last 2 versions']});
var assets = require('postcss-assets')({basePath: 'public/', loadPaths: ['static/img/', 'static/fonts/']});
var fonts = require('postcss-font-magician')();
var cssnano = require('cssnano')();
var inlineSVG = require('postcss-inline-svg')();
var sourcemaps = require('gulp-sourcemaps');
var cache = require('gulp-cached');
gulp.task('devel', function () {
var pre = [assets, inlineSVG];
var post = [autoprefixer, fonts];
return gulp.src('public/static/sass/*.scss')
.pipe(cache('handled'))
.pipe(postcss(pre, {syntax: syntax}))
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(postcss(post))
.pipe(sourcemaps.write('../maps'))
.pipe(gulp.dest('public/static/css'));
});
gulp.task('product', function () {
var pre = [assets, inlineSVG];
var post = [autoprefixer, fonts,cssnano];
return gulp.src('public/static/sass/*.scss')
.pipe(postcss(pre, {syntax: syntax}))
.pipe(sass().on('error', sass.logError))
.pipe(postcss(post))
.pipe(gulp.dest('public/static/css'));
});
gulp.task('watch', function () {
gulp.watch('public/static/sass/*.scss', ['devel']);
});
gulp.task('default', ['watch', 'devel']);
Как видно из кода я использую две основные задачи, первая — devel
, для генерации CSS-стилей во время разработки, вторая для подготовки стилей чтобы отправить в "продакшн", пришлось сделать две так как для минификации стилей я использую cssnano
, а он у меня отрабатывает примерно за 20 секунд (не могу сказать много это или мало).
Для разных разделов сайта пишу стили в отдельных файлах (потом django-compress их склеивает в один) и чтобы gulp не обрабатывал зря файлы, которые я "не трогал" использую для этого модуль gulp-cached
.
Плагины для PostCSS я разделил на две группы: в первой работают плагины перед компиляцией SASS в CSS, во второй после компиляции. Это я сделал для того, чтобы например, получать размеры картинок и присваивать их переменным (чтобы потом можно было проделывать арифметические операции).
Тепрь в консоли можно дать команду: gulp
(или gulp watch
) и спокойно кодить стили на SassyCSS (Ураа, я сделал это :-)).
В итоге теперь можно писать примерно такой "стиль":
.table-of-contents {
$margin-from-icon: 15px;
$left-pad-item: 70px;
$marker-width: width('inline/marker_ice.png');
$marker-height: height('inline/marker_ice.png');
padding-left: $left-pad-item + $margin-from-icon + $marker-width;
& > li {
h3 {
text-indent: -1 * ($marker-width + $margin-from-icon);
vertical-align: baseline;
&::before {
content: ' ';
display: inline-block;
width: $marker-width;
height: $marker-height;
margin-right: 15px;
vertical-align: -5px;
background: no-repeat inline('inline/marker_ice.png');
}
}
}
}
и вся компиляция в "CSS" происходит очень быстро.
Ещё очень интересен cssnext. Поначалу напрягает синтаксис, но это дело привычки. Сначала кажется странным, что для математики надо использовать calc (при парсинге значения вычисляются и подставляются), а для переменных, особых медиа-условий и цветовых функций — новый синтаксис. Однако, со временем это станет стандартом, почему бы не привыкать заранее.
4 мифа о PostCSS