- PVSM.RU - https://www.pvsm.ru -

CSS-препроцессоры против постпроцессоров

CSS-препроцессоры прекрасны, они сделали революцию в мире интернет-вёрстки. Создание кросс-браузерного CSS стало гораздо проще, потому что все вендорные префиксы и хаки можно завернуть в примеси, заглушки или что у вас там. До сих пор этого вполне хватало, но так как мы неистово одержимы контролем, хотим большего. Всегда. БОООООЛЬШЕ. Скажи привет CSS-постпроцессорам!

Postprocessing? я запутался!

Это неудивительно, мне кажется “postprocessing” не слишком подходящим словом, но он вполне способно донести саму суть – CSS-препроцессоры (Sass, Less и т.д.) читают и собирают язык расширения в CSS, тогда как постпроцессоры читают и собирают сам CSS. Это ужасно, простите, но если вы но если было непонятно, то теперь всё должно встать на свои места.

Уже существует несколько постпроцессоров, например – Autoprefixer [1], PostCSS [2] и rework [3].

Зачем использовать постпроцессор?

Что ж, давайте возьмём для примера Autoprefixer, он читает ваш CSS и добавляет вендорные префиксы, используя при этом базу данных Can I Use [4]. Представьте, что вы пишете на Sass и хотите применить правило из CSS3, плохо поддерживаемое без префиксов, так что используете примесь:

@mixin box-sizing($value) {
  -webkit-box-sizing: $value;
     -moz-box-sizing: $value;
          box-sizing: $value;
}
.box {
  @include box-sizing(border-box);
}

Почему Autoprefixer лучше? Потому что можно вот так:

.box {
  box-sizing: border-box;
}

Пишите на Sass/Less/Stylus/CSS без забот, потому что готовый CSS будет прочтён и в него будут добавлены нужные вендорные префиксы:

.box {
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}

Есть хотя бы 3 преимущества этого подхода:

  1. Не нужно думать о том, какие правила нужно повторять с префиксами (или нужно ли вот это правило использовать как примесь)
  2. Потом можно выбрать браузеры, которые вы будете поддерживать, просто настроив Autoprefixer. Подробности ниже.
  3. Быстрее, чем Sass. (сомнительное высказывание – примечание переводчика)

У Autoprefixer отличная поддержка любых инструментов сборки [5], которые вы можете использовать. Для дальнейших примеров я буду использовать Gulp [6] (простите, кто использует что-то другое), так вот ваша задача может выглядеть так:

var sass = require('gulp-ruby-sass');
var autoprefixer = require('gulp-autoprefixer');

gulp.task('styles', function() {
  return gulp.src('app/styles/main.scss')
    .pipe(sass())
    .pipe(autoprefixer({browsers: ['last 3 versions']}))
    .pipe(gulp.dest('dist/styles'));
});

Я попросил Autoprefixer добавить вендорные префиксы для 3 последних выпусков любого браузера.

Новый уровень

Можно заметить, что Autoprefixer не добавляет браузерные хаки [7], он только следит за префиксами. Вот тогда-то PostCSS и выходит на сцену.

Представьте, что вы хотите использовать прозрачность, как белый человек:

.box {
  opacity: 0.5;
}

Но IE8 говорит “Что это за прозрачность такая? Это что-то, что ты ешь?”, так что вам нужно добавить хак [8]. Вы действительно собираетесь использовать примесь просто потому, что нужно добавить один хак для одного правила, который впоследствии будет лишним? Вместо этого можно написать простой обработчик PostCSS [9]:

function(css) {
  css.eachDecl(function(decl, i) {
    if (decl.prop === 'opacity') {
      decl.parent.insertAfter(i, {
        prop: '-ms-filter',
        value: '"progid:DXImageTransform.Microsoft.Alpha(Opacity=' + (parseFloat(decl.value) * 100) + ')"'
      });
    }
  });
}

Он сделает цикл на каждом объявлении, и, если он встретит opacity, добавит для IE8 хак. Теперь нужно подключить его к нашей задаче Gulp:

var sass = require('gulp-ruby-sass');
var autoprefixer = require('gulp-autoprefixer');
var postcss = require('gulp-postcss');
var opacity = function(css) {
  css.eachDecl(function(decl, i) {
    if (decl.prop === 'opacity') {
      decl.parent.insertAfter(i, {
        prop: '-ms-filter',
        value: '"progid:DXImageTransform.Microsoft.Alpha(Opacity=' + (parseFloat(decl.value) * 100) + ')"'
      });
    }
  });
};

gulp.task('styles', function() {
  return gulp.src('app/styles/main.scss')
    .pipe(sass())
    .pipe(autoprefixer({browsers: ['last 3 versions']}))
    .pipe(postcss([opacity]))
    .pipe(gulp.dest('dist/styles'));
});

Если вы хотите быть крутым, можете добавить Autoprefixer как обработчик PostCSS вместо расширения Gulp, так что вместо gulp-autoprefixer [10] придётся требовать autoprefixer-core [11]:

var sass = require('gulp-ruby-sass');
var autoprefixer = require('autoprefixer-core');
var postcss = require('gulp-postcss');
var opacity = function(css) {
  css.eachDecl(function(decl, i) {
    if (decl.prop === 'opacity') {
      decl.parent.insertAfter(i, {
        prop: '-ms-filter',
        value: '"progid:DXImageTransform.Microsoft.Alpha(Opacity=' + (parseFloat(decl.value) * 100) + ')"'
      });
    }
  });
};

gulp.task('styles', function() {
  return gulp.src('app/styles/main.scss')
    .pipe(sass())
    .pipe(postcss([
      autoprefixer({browsers: ['last 3 versions']}),
      opacity
    ]))
    .pipe(gulp.dest('dist/styles'));
});

Теперь после каждого выполнения задачи у нас будет такое правило:

.box {
  opacity: 0.5;
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
}

Кошмар… но это именно то, чего мы хотели. Теперь, если мы захотим прекратить париться об IE8, сможем просто отключить обработчик из нашей задачи Gulp.

Так как же выбрать между пре- и пост-процессорами?

Избегайте использовать препроцессоры для кросс-браузерной поддержки вроде вендорных префиксов или поли-заполнителей, пусть препроцессоры занимаются своим делом. Вы можете использовать препроцессоры для чего-то куда более весёлого, как цветовые схемы, примеси шрифтов, примеси раскладки и так далее.

И постпроцессоры не ограничивайте только браузерной поддержкой. Гляньте список существующих обработчиков PostCSS [12], чтобы узнать, что вы можете сделать, потому что мы здесь копнули только самую верхушку.

Меня это действительно волнует, а вас?

Автор: Grawl

Источник [13]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/css/69122

Ссылки в тексте:

[1] Autoprefixer: http://github.com/postcss/autoprefixer

[2] PostCSS: http://github.com/postcss/postcss

[3] rework: http://github.com/reworkcss/rework

[4] Can I Use: http://caniuse.com

[5] любых инструментов сборки: http://github.com/postcss/autoprefixer#usage

[6] Gulp: http://gulpjs.com/

[7] не добавляет браузерные хаки: http://github.com/postcss/autoprefixer#does-it-add-polyfills-for-old-browsers

[8] добавить хак: http://css-tricks.com/snippets/css/cross-browser-opacity/

[9] обработчик PostCSS: http://github.com/postcss/postcss#write-own-processor

[10] gulp-autoprefixer: http://github.com/Metrime/gulp-autoprefixer

[11] autoprefixer-core: http://github.com/postcss/autoprefixer-core

[12] обработчиков PostCSS: http://github.com/postcss/postcss#tools

[13] Источник: http://habrahabr.ru/post/235929/