Автопрефиксер: мир без CSS-префиксов

Андрей Ситник, Злые марсиане

Автопрефиксер мир без CSS-префиксов

Андрей Ситник, Злые марсиане

Глава 1 Боль

Привет из прошлого

@include border-radius(5px)
-webkit-border-radius: 5px-moz-border-radius: 5px-khtml-border-radius: 5pxborder-radius: 5px

border-radius

Компас не прячет от нас префиксы

  1. Это свойство из CSS 3?
  2. Это свойство ещё требует префиксов?
  3. Пишем примесь или обычное свойство.

Машины должны страдать

Релизы Компаса

С последнего стабильного релиза (0.12) прошло:

Стайлус и nib

border-radius 3px
-webkit-border-radius: 3pxborder-radius: 3px

Стайлус и nib

-prefix-free

Идеальный интерфейс, но проблемы с производительностью

Глава 2 Анализ

Принципы Автопрефиксера

  1. Без интерфейса
:fullscreen a {  transition: transform 1s}

Принципы Автопрефиксера

  1. Без интерфейса
  2. Универсальность
    • Сасс
    • Стайлус
    • Новые препроцессоры
    • Чистый CSS в старом коде или библиотеках

Принципы Автопрефиксера

  1. Без интерфейса
  2. Работа с чистым CSS
  3. Самые актуальные префиксы

Принципы Автопрефиксера

  1. Без интерфейса
  2. Работа с чистым CSS
  3. Самые актуальные префиксы
  4. Автообновление

Хорошие препроцессоры

.quote  position: relative  top: 100px  +size(100px, 50px)  .arrow    +triangle

Плохие препроцессоры

@import "shared";$default-transition-property: all !default;$default-transition-duration: 1s !default;$default-transition-function: false !default;$default-transition-delay: false !default;$transitionable-prefixed-values: transform, transform-origin !default;@mixin transition-property($property-1: $default-transition-property, $property-2 : false, $property-3 : false, $property-4 : false, $property-5 : false, $property-6 : false, $property-7 : false, $property-8 : false, $property-9 : false, $property-10: false) {  @if type-of($property-1) == string { $property-1: unquote($property-1); }  $properties: compact($property-1, $property-2, $property-3, $property-4, $property-5, $property-6, $property-7, $property-8, $property-9, $property-10);  @if $experimental-support-for-webkit    {       -webkit-transition-property : prefixed-for-transition(-webkit, $properties); }  @if $experimental-support-for-mozilla   {          -moz-transition-property : prefixed-for-transition(-moz,    $properties); }  @if $experimental-support-for-opera     {            -o-transition-property : prefixed-for-transition(-o,      $properties); }                                                          transition-property : $properties;}@mixin transition-duration($duration-1: $default-transition-duration, $duration-2 : false, $duration-3 : false, $duration-4 : false, $duration-5 : false, $duration-6 : false, $duration-7 : false, $duration-8 : false, $duration-9 : false, $duration-10: false) {  @if type-of($duration-1) == string { $duration-1: unquote($duration-1); }  $durations: compact($duration-1, $duration-2, $duration-3, $duration-4, $duration-5, $duration-6, $duration-7, $duration-8, $duration-9, $duration-10);  @include experimental(transition-duration, $durations,    -moz, -webkit, -o, not -ms, not -khtml, official  );}@mixin transition-timing-function($function-1: $default-transition-function, $function-2 : false, $function-3 : false, $function-4 : false, $function-5 : false, $function-6 : false, $function-7 : false, $function-8 : false, $function-9 : false, $function-10: false) {  $function-1: unquote($function-1);  $functions: compact($function-1, $function-2, $function-3, $function-4, $function-5, $function-6, $function-7, $function-8, $function-9, $function-10);  @include experimental(transition-timing-function, $functions,    -moz, -webkit, -o, not -ms, not -khtml, official  );}@mixin transition-delay($delay-1: $default-transition-delay, $delay-2 : false, $delay-3 : false, $delay-4 : false, $delay-5 : false, $delay-6 : false, $delay-7 : false, $delay-8 : false, $delay-9 : false, $delay-10: false) {  @if type-of($delay-1) == string { $delay-1: unquote($delay-1); }  $delays: compact($delay-1, $delay-2, $delay-3, $delay-4, $delay-5, $delay-6, $delay-7, $delay-8, $delay-9, $delay-10);  @include experimental(transition-delay, $delays,    -moz, -webkit, -o, not -ms, not -khtml, official  );}@mixin single-transition(  $property: $default-transition-property,  $duration: $default-transition-duration,  $function: $default-transition-function,  $delay: $default-transition-delay) {  @include transition(compact($property $duration $function $delay));}@mixin transition(  $transition-1 : default, $transition-2 : false, $transition-3 : false, $transition-4 : false, $transition-5 : false, $transition-6 : false, $transition-7 : false, $transition-8 : false, $transition-9 : false, $transition-10: false) {  @if $transition-1 == default {    $transition-1 : compact($default-transition-property $default-transition-duration $default-transition-function $default-transition-delay);  }  $transitions: false;  @if type-of($transition-1) == list and type-of(nth($transition-1,1)) == list {    $transitions: join($transition-1, compact($transition-2, $transition-3, $transition-4, $transition-5, $transition-6, $transition-7, $transition-8, $transition-9, $transition-10), comma);  } @else {    $transitions : compact($transition-1, $transition-2, $transition-3, $transition-4, $transition-5, $transition-6, $transition-7, $transition-8, $transition-9, $transition-10);  }  $delays: comma-list();  $has-delays: false;  $webkit-value: comma-list();  $moz-value: comma-list();  $o-value: comma-list();  @each $transition in $transitions {    $property: nth($transition, 1);    $duration: false;    $timing-function: false;    $delay: false;    @if length($transition) > 1 { $duration:        nth($transition, 2); }    @if length($transition) > 2 { $timing-function: nth($transition, 3); }    @if length($transition) > 3 { $delay:           nth($transition, 4); $has-delays: true; }    @if is-time($timing-function) and not $delay { $delay: $timing-function; $timing-function: false; $has-delays: true; }    $delays: append($delays, if($delay, $delay, 0s));    $webkit-value: append($webkit-value, compact(prefixed-for-transition(-webkit, $property) $duration $timing-function));       $moz-value: append(   $moz-value, compact(prefixed-for-transition(   -moz, $property) $duration $timing-function $delay));         $o-value: append(     $o-value, compact(prefixed-for-transition(     -o, $property) $duration $timing-function $delay));  }  @if $experimental-support-for-webkit    {       -webkit-transition : $webkit-value;    @if $has-delays                       { -webkit-transition-delay : $delays;       } }  @if $experimental-support-for-mozilla   {          -moz-transition : $moz-value;    }  @if $experimental-support-for-opera     {            -o-transition : $o-value;      }                                                          transition : $transitions;}@function comma-list($list: ()) {  @return join((), $list, comma);}@function prefixed-for-transition($prefix, $property) {  @if type-of($property) == list {    $new-list: comma-list();    @each $v in $property {      $new-list: append($new-list, prefixed-for-transition($prefix, $v));    }    @return $new-list;  } @else {    @if index($transitionable-prefixed-values, $property) {      @return -;    } @else {      @return $property;    }  }}@function is-time($value) {  @if type-of($value) == number {    @return not not index(s ms, unit($value));  } @else {    @return false;  }}

Программируем на Сасс

Постпроцессоры

Постпроцессоры

CSS
PostCSS
Парсер
Сохранение
JS-дерево
Новое JS-дерево
Ваш JS-код обработки
Новый CSS

Создаём постпроцессор

processor = postcss (css) ->  css.eachRule (rule) ->     if rule.selector.match(/::(before|after)/')       if rule.every (i) -> i.prop != 'content'         rule.prepend(prop: 'content'', value: '""')

Применяем постпроцессор

output = processor.process(input).css
a:before  width: 10px  height: 10px  background: blue
a:before  content: ""  width: 10px  height: 10px  background: blue

Постпроцессоры ♥ Сасс и Стайлус

Сасс
CSS
Карта кода
PostCSS
Парсер
Сохранение
JS-дерево
Новое JS-дерево
Ваш JS-код обработки
Новый CSS
Новая карта

Примеры постпроцессоров

Глава 3 Внутри Автопрефиксера

Поддерживаемые
браузеры
Данные с Can I Use
нужные префиксы →
ненужные префиксы →
CSS
Автопрефиксер
CSS с префиксами

Быстрое обновление

Скрипты проверки обновления Can I Use:

@feature 'css3-boxsizing', (browsers) =>  prefix 'box-sizing', browsers: browsers
  1. Запускаю скрипт ./bin/autoprefixer --update
  2. Если есть обновления — n cake publish

Браузеры по умолчанию

Свойства

box-sizing: border-box
-webkit-box-sizing: border-box-moz-box-sizing: border-boxbox-sizing: border-box

Значения

transition: transform 1s
-webkit-transition: -webkit-transform 1stransition: transform 1s

Функции

width: calc(10% + 10em)
width: -webkit-calc(10% + 10em)width: calc(10% + 10em)

Кадры

@keyframes anim {  to {    transform: rotate(360deg); } }
@-webkit-keyframes anim {  to {    -webkit-transform: rotate(360deg);    transform: rotate(360deg); } } @keyframes anim {  to {    -webkit-transform: rotate(360deg);    -ms-transform: rotate(360deg);    transform: rotate(360deg); } }

Селекторы

:fullscreen a {  transition: transform 1s }
:-webkit-full-screen a {  -webkit-transition: -webkit-transform 1s;  transition: transform 1s; } :-moz-full-screen a {  transition: transform 1s; } :fullscreen a {  -webkit-transition: -webkit-transform 1s;  transition: transform 1s; }

Градиенты

background: linear-gradient( to left, white, black );

           ↓

background: -webkit-gradient( linear, top right, top left,                             from(white), to(black));background: -webkit-linear-gradient( right, white, black );background: linear-gradient( to left, white, black );

Флексбокс

display: flex
display: -webkit-box;display: -webkit-flex;display: -moz-box;display: -ms-flexbox;display: flex

Сложный флексбокс

flex-direction: row
-webkit-box-orient: horizontal;-webkit-box-direction: normal;-webkit-flex-direction: row;-moz-box-orient: horizontal;-moz-box-direction: normal;-ms-flex-direction: row;flex-direction: row

Хаки

Чистка

-webkit-border-radius: 10px-moz-border-radius: 10pxborder-radius: 10px
border-radius: 10px       

Но не чистит хаки

-moz-transform: translateZ(0)

Глава 4 Самые важные слова

Шаг 1Автоматизуйте фронтенд

Мощные и гибкие

Grunt
gruntjs.com

Broccoli
github.com/joliss/broccoli

Mincer
github.com/nodeca/mincer

Самый простой вариант

Prepros alphapixels.com/prepros

Шаг 2. Включите Автопрефиксер

Шаг 3. Забудьте о префиксах

Чистый CSS

:fullscreen body {  transition: transform 1s;  transform: rotate(90deg)}

Вопросы