Pull to refresh

Comments 64

UFO just landed and posted this here
Спасибо за уточнение! Обновил ссылку на актуальный парсер.
По-моему у PostCSS проблемы с позиционированием. Это название постоянно мелькает перед глазами, но я так и не понял, что и зачем. То ли это убийца sass/less, то ли просто таскраннер вроде gulp/grunt. Так и не хватило мотивации разобраться. Хоть убей, не понимаю зачем мне запускать autoprefixer через PostCSS если я могу просто воткнуть его в gulp.
Вы правы, разницы между gulp-autoprefixer и gulp-postcss(autoprefixer) особо нет — мы перешли на gulp-postcss чтобы самим меньше программировать обёрток и чтобы пользователи быстрее получали обновления.

Но если у вас несколько плагинов PostCSS — то тут преимущество подхода gulp-postcss очевидно — CSS парситься только один раз, что сильно ускоряет процесс.
Проблема в том, что PostCSS — это новый класс инструментов. В том-то и дело, что это и не просто замена Sass, и не таск раннер.

Но может вам поможет такое сравнение — PostCSS — это как Babel 6 (который с плагинами и может делать всё что угодно, а не только ES6), только для CSS. У PostCSS даже есть cssnext, который как раз «CSS4» делает.
Спасибо. Всё встало на свои места.
А что не так с названием?
Оно однозначно ассоциируется с постпроцессингом.
Постмодерн или построк тоже только с постпроцессорами? :D

Пост- — это в значении после.
При чем тут постмодерн? Всё воспринимается в своем контексте.
В контексте CSS доминируют препроцессоры, они общеизвестны, они де-факто уже базовая технология. Все новые технологии неизбежно сравниваются с ними и противопоставляются им. Какие можно поиметь ассоциации, сравнивая «пост-» с «пре-»? Вполне однозначные.
Ну эта та вещь, которые мы не можем исправить — бессмысленно на неё жаловаться тогда
UFO just landed and posted this here
PostCSS это по сути совокупность плагинов как подхода к обработке CSS. PostCSS это не отдельная технология, это совокупность плагинов, повторюсь. Используйте ваш любимый сборщик Webpack или Gulp, прогоняйте файлы через отдельные плагины PostCSS ( cssnano — минификатор, autoprefixer и другие) и радуйтесь. Мне в свое время понравилась вот эта презентация: ai.github.io/about-postcss
Сравнивать Gulp/webpack и PostCSS — совсем не корректно.

PostCSS — это в первую очередь парсер CSS. Используя этот парсер вы и можете создавать плагины. Как чисто в PostCSS, так и для Gulp и webpack.

На самом деле сам webpack (точнее css-loader) и использует PostCSS, чтобы разворачивать import и url.
Но можно и сравнить сами плагины — например, gulp-postcss с autoprefixer и cssnano внутри или gulp-autoprefixer и gulp-cssnano (оба случая построены на базе PostCSS, просто в первом случае это явно, а в другом нет). В таком случае у gulp-postcss будет огромное преимущество перед отдельными плагинами для Gulp — gulp-postcss будет парсить CSS только один раз. А если у вас просто плагины для Gulp, то каждый из них будет заново парсить CSS.

А парсинг CSS — это один из самых длинных шагов в обработки CSS. Зависит от задачи, но часто 50-80% (можете поиграться в бенчмарке postcss).
Так ведь для Webpack есть postcss-loader, который довольно органично вписывает PostCSS в экосистему Webpack, какой бы вы подход к сборке не использовали. Он так же легко чейнится как и любой другой loader для CSS.
Забавно, судя по комментариям многие действительно не понимают, что такое postcss. На самом деле сам по себе это парсер + код-принтер. То есть без плагинов postcss просто распарсит ваш css и запишет его обратно. Дальше есть плагины, вроде autoprefixer, которые изменяют css перед записью.
Это как babel, только в мире css.

zharikovpro css-loader под капотом использует webpack.
Miklos потом вам понадобится еще какой-то плагин, который работает поверх postcss и он заново будет парсить css, вместо того, чтобы сделать это внутри postcss. Это тоже вариант, просто не стоит себя обманывать, что вы обходитесь без postcss, он уже внутри gulp-autoprefixer.
Теперь-то всё ясно. Были статьи про использование postcss, и везде приводили элементарные примеры с autoprefixer, которым все пользуются и без postcss, что создавало дополнительное непонимание идеи.
Которым все пользуются не без postcss, а с ним под капотом.
UFO just landed and posted this here
Мне кажется или есть проблема с порядком подключения плагинов? ведь каждый плагин работает только исходным файлом и ничего не знает о других плагинах, то есть очередность подключения плагинов имеет значение и сборная солянка плагинов вполне реально не взлетит, а если полетит, то каждое новое подключение плагина это всегда проблема, так как надо идти курить, что же делает уже существующие плагины, верно понимаю? Опять же народ пытается использовать postcss вместе sass/less, и фактически каждый проект получается как новый препроцессор, потому что набор плагинов уникален каждый раз.
Да, это большая проблема — у нас как раз есть решение с помощью событийных плагинов, которые будут в версии 6.0.

Но а пока обе проблема можно решить просто с помощью пакетов плагинов — не нужно выбирать их самому, лучше взять пакет PreCSS или cssnext.
Слушал ваше (или не ваше) описание postCSS в подкасте Веб-стандарты. Вникать пока было некогда. Понравилась идея о том, что можно написать плагин, который может на входе сразу получить распарсенный CSS и модифицировать в нём только то, что необходимо, передав вожжи следующему плагину. Вопрос: можно ли без крови написать плагин, который будет изменять правила, в которых есть какое-нибудь собственное CSS-свойство (допустим base64: background), таким образом, чтобы в указанном свойстве заменять значение с URI на base64, а само синтетическое свойство удалять? Если я правильно вас понял, то такое должно быть на раз плюнуть. Пример немного грубый, но всё же...?
Примерно для таких вот костылей он и задуман?
Статью писал и переводил не я :).

Да, можно и довольно легко.

Но лучше использовать не свойства, а функцию — тогда base64 можно буде использовать в разных свойствах (и background, и mask). Уже даже несколько написаны: для любых файлов, для SVG со сменой цвета.
Готовые решения не учитывают специфику моих хотелок. Я хочу чтобы весь этот изврат с base64 был только при сборке. Вариант с опционально подключаемым самописным плагином выглядит вкусно.
в webpack с css-loader + url-loader можно сделать чтобы ваш файл автоматически инклюдился в css в виде base64 если он не превышает определенный размер который вы зададите. При этом внутри css будут обычные backround: url('...')
Полагаю, что на первой же не идеально-написанной библиотеке, оно вам задаст жару. К примеру вы подключите какой-нибудь удобный сторонний контрол, а в его CSS будет подключён маловесный спрайт. И этот спрайт будет указан в стилях раз 18. Ух…
Я пока склоняюсь к ручному указанию какие свойства в каких правилах подключать inline, а какие нет. Вариант с псевдо-свойством мне кажется довольно удобным. Потому что в качестве альтернативы я вижу возможность указывать этот список где-то в конфигах, в отрыве от самих стилей.
В postcss-assets просто добавляется новая функция inline(), которая используется вместо url().
Я хочу чтобы весь этот изврат с base64 был только при сборке

К тому же inline-ы и в compass-е есть
А что значит только при сборке? Только при деплое (сборке на продакшене)?
Сборки для production-а, да. Во время разработки меня не улыбают все эти тормоза на ровном месте. Это же получается, что при каждом пересохранении SCSS файла я получу повторный inline-инг, который будет считывать каждое необходимое изображение целиком, формирует его base64 вариацию и несёт её в раздутый CSS. Меня и без таких шаманств скорость SCSS не очень устраивает.
А у вас старый Ruby Sass? Тогда подумайте о переде на PreCSS на базе PostCSS — он в 28 раз быстрее.

Но можно делать и инлайн при деплое. Но только учтите, что тогда кастомное свойство уже не подходит — без сборки оно будет невалидно.
без сборки оно будет невалидно.

учитывая что это не уходит дальше dev-машины — не вижу никакой проблемы :)
Так ваш браузер же не покажет картинку.
Вы видимо меня не правильно поняли. В dev:
.some {
  background: url('1.png');
  _base64: 'background'; 
}

На production:
.some { background: url(data....); }
Дело ваше, конечно — можно и так.

Но проще будет не писать два раза. PostCSS настолько быстр, что во время разработки его можно запускать на каждое изменение. У нас он отрабатывает меньше секунды (а мы очень много инлайним).
PostCSS настолько быстр

А причём тут postCSS? Он работает на магии и единорогах? Если программе при каждом запуске потребуется считывать множество файлов целиком и конвертировать их в base64, то оно просто не может не тормозить. Это же изнасилование файловой системы.
меньше секунды

1000ms это очень медленно.
а мы очень много инлайним

больше 100 KiB?
Главная причина тормозов — не чтение с файла или base64-кодирование, а парсер Ruby-версии Sass — он написан очень неоптимально.

PostCSS из-за модульной архитектуры проще оптимизировать — всегда видно, где самый затык по скорости.

Да, у нас около 10 файлов по 200—400 КБ.
по 200—400 КБ

Уговорили, попробую напрямую. Хорошо, что dev-тулы уже умеют показывать base64 значения в сжатом виде… А не как раньше, целиком :D
Автоматический инлайн всех url() — не самое лучшее решение (кстати оно в css-loader делается тоже с помощью скрытого плагина PostCSS) — некоторые картинки не нужно инлайнить, так как они показывается редко. А некоторые большие иллюстрации — нужно.

Хороший пример — шрифты. Я инлайню главное начертание, а жирное (если оно используется редко) — нет.

Я поэтому тоже предпочитаю инлайнить вручную с помощью postcss-assets.
Я не совсем понял логику — зачем инлайнить большие иллюстрации? Как раз их бы и сделать внешними ресурсами, чтобы кэширование работало.
Кеширование для CSS тоже работает.

Конечно, инлайнить нужно не все большие картинки — но иногда важнее заинланить одну большую картинку сверху страницы (которая сразу видна), а куча маленбких картинок снизу проще догрузить лениво.
Вторая проблема (разбил на два сообщения, чтобы было удобнее отвечать) — инлайн SVG. Тут было бы круто при инлайне сразу менять цвет картинки. Поэтому тут авто-url() точно не подойдёт. А вот postcss-inline-svg — лучше.
Может, имеет смысл посмотреть в сторону инжектинга css? Это поможет снизить тормоза при разработке.
Например, browsersync позволяет сделать так
Если есть парсинг и возможность использовать констукции языков постпроцессоров, то можно ли полностью заменить LESS на postcss + postcss-less? И на сколько это ударит по производительности?
postcss-less только парсит Less, но не применяет примеси или математику. Но в теории это возможно — нужно только написать плагины для всех функций Less.

Итог, наверное, будет даже быстрее 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));
});
Существуют ли какие-либо идеи с подсветкой синтаксиса? На мой взгляд, это мешает распространению. Разработчики предлагают самостоятельно прописывать правила подсветки в IDE, выходит, что настраивать надо под каждый сторонний модуль, инструкции которого имеют расхождение с базовым css/scss/less синтаксисом.

Аннотации?!
Для Атома и Саблайна есть плагины с подсветкой.

Для ВебШторма бы написали — но команда Шторма нормально не открывает модуль и сама писать не хочет. Но там можно выставить подсветку SCSS и всё будет нормально.
Полностью. Автопрефиксер заменяет примеси с префиксами. postcss-assets заменяет инлайн картинок.

Команда Compass уже прекратила его развитие и тоже считает, что Автопрефиксер работает на порядок лучше.
Команда Compass уже прекратила его развитие и тоже считает, что Автопрефиксер работает на порядок лучше.

Звучит бредово. Кто-то использовал compass только из-за миксинов автопрефиксера? :) Дурь же…
Скорее вы хотели сказать, что "postCSS работает на порядок лучше", ибо там нужна уйма плагинов.
Кстати говоря, я думаю не стоит повсеместно применять выражение "на порядок". Это ж в 10 раз лучше. В 10, Карл, в 10!
Вы не путаете Compass и Sass? Sass — это тот язык, который даёт вам примеси, переменные и циклы поверх CSS. А Compass — просто набор примесей для Sass. Большая часть этих примесей была про префиксы. Ещё часть была про спрайты (это тоже есть в PostCSS).

Собственно, на прошедшем SassSummit Крис Эпштейн и заявил, что Compass закрыт — будут только мелкие обновления типа безопасности.

Ну и в Париже на CSSConf он мне это подтвердил.
Вы не путаете Compass и Sass?

Вроде не путаю. Тут в разделе All Ruby Based Functions под сотню пунктов. Я, правда, из них пользуюсь всего 4-5. Примесями я в нём практически не пользовался.
Их тоже можно перенести на PostCSS.

Например, функция работа с цветом уже стала частью «CSS4» — и тут лучше использовать стандартный синтаксис из будущего, с помощью cssnext на базе PostCSS. Это как ES6 для многих лучше CoffeeScript.
Этим postCSS и подкупает: можно добавить всё по своему вкусу, включая то, чего нет из коробки, написав руками. Аля grunt для css.

В общем вы убедили меня попробовать разобраться с 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" происходит очень быстро.

советовал бы поглядеть плагины gulp-if, чтобы не копипасть скрипты для сборки отдельно
gulp-plumber — для навешивания обработчика ошибки на весь поток, а не только на gulp-sass
Из обсуждений у меня сложилось впечатление, что если, помимо nested правил из SCSS, я ещё использую ещё циклы, миксины, переменные, то postCSS мне придётся запускать уже поверх сгенерированной Sass-ом CSS-ки? Или сам Sass тоже можно подключить как один из плагинов? Как вы эти проблемы решаете?
Примеси, переменные, математика и цикли есть в виде плагинов. Проще взять уже готовый набор плагинов PreCSS, в котором всё это есть
Похоже, что всё что мне нужно есть. Хороший повод попробовать на досуге.
Если не мешать сложной логики для стилей (да и не нужно в стилях мешать ложную логику, css должен быть прозрачным), то PreCSS хорош и быстр.

Ещё очень интересен cssnext. Поначалу напрягает синтаксис, но это дело привычки. Сначала кажется странным, что для математики надо использовать calc (при парсинге значения вычисляются и подставляются), а для переменных, особых медиа-условий и цветовых функций — новый синтаксис. Однако, со временем это станет стандартом, почему бы не привыкать заранее.
Sign up to leave a comment.

Articles