Изоляция CSS

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

Злые марсиане

Работаем над

Наш опенсорс

Глава 1 Проблема

Зачем нам ИТ?

Рост сложности

3 объекта

6 объектов

3 связи

15 связей

Решение роста

Программирование — контроль сложности

Компоненты сети

Компоненты ОС

Компоненты JavaScript

import Logo from '../logo';
 
export const Header = () => (
    <div class="header">
      <Logo></Logo>
    </div>
);

Компоненты дизайна

Глобальный CSS :-(

* {
    box-sizing: border-box;
}
.title {
    font-size: 30px;
}

Глава 2 Четыре всадника CSS

Всадник 1 Конфликт селекторов

/* logo.css */
.name {
    color: gray;
}
/* header.css */
.name {
    color: red;
}

БЭМ

window.prefixA = …;
window.prefixB = …;

Всадник 2 Глобальный сброс

* {
    box-sizing: border-box;
}

Всадник 3 Наследуемые свойства

body
  .header
​    .logo
line-height: 1.4
line-height: 1.4
line-height: 1.4

Агрессивные селекторы

.article p {
    margin-bottom: 1em;
}

Всадник 4 Медиа-выражения страницы

.logo:container( width <= 100px ) {
    .name {
        display: none;
    }
}

Четыре всадника

Конфликт селекторов

Глобальный сброс

Наследуемые свойства

Медиа-выражения страницы

Ждать Веб-компонентов?

Глава 3 Революция

PostCSS

CSS

карта кода

Генератор

Парсер

Плагин

Плагин

Новый CSS

новая карта

Задачи

Sass

PostCSS

Код

return gulp.src('src/*.scss')
    .pipe( sass() )
    .pipe( postcss(plugins) )
    .pipe( gulp.desc('build/') );

Глава 4 Побеждаем глобальный CSS

Шаг 1 Чистая комната

gulp.task('css:new', () => {
    return gulp.src('src/new/')
        .pipe( postcss([
            // other plugins
            require('autoprefixer')
        ]) )
        .pipe( gulp.dist('build/') )
});

Шаг 2 Нарежьте дизайн на блоки

Шаг 3 Папка для компонента

logo/
  logo.js
  logo.css
  company.svg
header/
  header.js
  header.css
js/
  logo.js
  header.js
css/
  logo.css
  header.css
images/
  company.svg
Шаг 4 postcss-modules
postcss([,
    require('postcss-modules'),
    require('autoprefixer')
])

Пишите любые селекторы

.name {
    color: red;
}
.Logo_name_jbds3 {
    color: red;
}

Шаблон

var style = require('./logo.css.json');

export const Logo = () => (
    <div className={ style.name }>
    </div>
);

Работает с PHP и Rails

- style = load_json('logo.css.json');

%div{ class: style.name }

CSS Modules против БЭМ

  1. Стили чище
  2. Переносимость между проектами
  3. Безопаснее для виджетов

Первая победа

Конфликт селекторов

Глобальный сброс

Наследуемые свойства

Медиа-выражения страницы

Локальный сброс

h1, h2, …, div {
    /* сброс */
}
.header {
    /* стили */
}
.logo {
    /* стили */
}
.header, .logo {
    /* сброс */
}
.header {
    /* стили */
}
.logo {
    /* стили */
}

Локальный сброс

body
  .header
​    .logo
line-height: 1.4
line-height: 1
line-height: 1

Плюсы локального сброса

  1. У каждого — свой ресет
  2. Переносимость между проектами
  3. Защищает от наследуемых свойств

Сброс по W3C

.logo {
    all: initial;
}

Шаг 5 postcss-autoreset

require('postcss-autoreset')({
    reset: {
        all:       'initial',
        font:      'inherit',
        boxSizing: 'border-box'
    }
})

Шаг 6 postcss-cssnext

postcss([
    require('postcss-modules'),
    require('postcss-autoreset'),
    require('postcss-cssnext'),
    require('autoprefixer')
])

Полифил будущего CSS

.logo {
    all: initial;
}
.logo {
    display: block;
    border: none;
    padding: 0;
    margin: 0;
    …
}

Ещё две победы

Конфликт селекторов

Глобальный сброс

Наследуемые свойства

Медиа-выражения страницы

Шаг 7 cq-prolyfill

<script src="cq-prolyfill.min.js" async>
</script>
postcss([
    …,
    require('cq-prolyfill/postcss-plugin'),
    …
])

Медиа-выражения контейнера

.logo:container( width >= 100px ) {
    …
}

.logo:container( text-align = right ) {
    …
}

.logo:container( background-color lightness > 20% ) {
    …
}

Полная изоляция

Конфликт селекторов

Глобальный сброс

Наследуемые свойства

Медиа-выражения страницы

Глава 5 Плюсы

Без вопросов

  1. Виджеты на сторонние сайты
  2. Компоненты в npm
  3. Плагины для браузера
  4. Большие команды с кучей проектов

Проще тестировать

Проще обновлять технологии

old/
  logo/
new/
  header/

Авто. оптимизации

.Logo_name_jb4 {
    color: black;
}
.Header_top_e63 {
    color: black;
}
.Logo_name_jb4,
.Header_top_e63 {
    color: black;
}

Глава 6 Советы

Главное зло

.logo {
    &.is-in-header {
        width: 100px;
        height: 100px;
        padding: 10px 0;
    }
    &.is-in-footer {
        …
    }
}

Совет 1 Пишите размеры в обёртках

<div className={ style.place }>
    <Logo>
</div>
.place {
    width: 100px;
    height: 100px;
    padding: 10px 0;
    position: relative;
}
.logo {
    width: 100%;
    height: 100%;
}

Совет 2 Вкладывайте друг в друга

<Button icon="remove" />
<Button>
    <RemoveIcon>
</Button>

Финал

Полная изоляция

postcss([
    // Изоляция селекторов
    require('postcss-modules'),

    // Локальный сброс
    require('postcss-autoreset'),
    require('postcss-cssnext'),

    // Контейнерные выражения
    require('cq-prolyfill/postcss-plugin'),

    require('autoprefixer')
])

@evilmartians

evl.ms/chronicles