С ростом кодовой базы становится все более очевидной необходимость использования компонентного подхода, когда каждая логическая часть обособлена. Если говорить про JavaScript, то в нем есть области видимости, опираясь на которые можно соорудить изолированные компоненты. Но в CSS нет подобных механизмов, поэтому и придумываются Shadow DOM (Web Components) и различные методики вроде БЭМ.
Но что если взглянуть на проблему под другим углом? Адаптируя подходы, что уже используются для других задач, можно получить куда больше выгоды, чем просто изолированные стили!
FrontendConf, Москва, 21 мая 2015
WSD, Санкт-Петербург, 20 июня 2015
Запись трансляции: https://youtu.be/V7bnSOwuO4M?t=1h31m33s
25. Другие проблемы
• Уникальность обеспечивается человеком
• Сложность автоматизированного анализа
• Нет механизмов интеграции сторонней
верстки в свою или свою в чужое окружение
• …
22
39. 35
function init(container) {
var shadowRoot = container.createShadowRoot();
!
var content = document.createElement('div');
content.innerHTML = 'some markup';
!
var styles = document.createElement('style');
styles.textContent = '/* some css */';
!
shadowRoot.appendChild(styles);
shadowRoot.appendChild(content);
}
Создаем корень Shadow Tree
40. 36
function init(container) {
var shadowRoot = container.createShadowRoot();
!
var content = document.createElement('div');
content.innerHTML = 'some markup';
!
var styles = document.createElement('style');
styles.textContent = '/* some css */';
!
shadowRoot.appendChild(styles);
shadowRoot.appendChild(content);
}
Создаем DOM фрагмент
41. 37
function init(container) {
var shadowRoot = container.createShadowRoot();
!
var content = document.createElement('div');
content.innerHTML = 'some markup';
!
var styles = document.createElement('style');
styles.textContent = '/* some css */';
!
shadowRoot.appendChild(styles);
shadowRoot.appendChild(content);
}
Создаем стили
42. 38
function init(container) {
var shadowRoot = container.createShadowRoot();
!
var content = document.createElement('div');
content.innerHTML = 'some markup';
!
var styles = document.createElement('style');
styles.textContent = '/* some css */';
!
shadowRoot.appendChild(styles);
shadowRoot.appendChild(content);
}
Вставляем все в Shadow Tree
46. А Shadow DOM-то – протекает
• Часть стилей наследуется от хоста
font, line-height, color и т.д.
• Можно стилизовать извне, используя
комбинатор >>> (бывш. /deep/ и ^^)
42
dev.w3.org/csswg/css-scoping/
50. Надо «все» переделать
• Будет два режима open (то что сейчас)
и close (более закрытый)
• Отказ от комбинатора >>> (м.б. будут слоты)
• Потребуется переделать текущий API
• ...
46
tinyurl.com/oqkv5u6
55. Предложение от команды React –
пишем CSS в JavaScript
51
speakerdeck.com/vjeux/react-css-in-js
speakerdeck.com/vjeux/react-css-in-js-react-france-meetup
63. Плюсы
• Изолированные стили без селекторов
• Все возможности JavaScript для стилей
• Нет проблемы специфичности
59
64. Минусы
• Подходит только для решений в стиле React
• Полное слияние логики и представления
• Нельзя использовать пре- и пост-процессоры
• Нельзя применять анализ и оптимизировать
• Бесполезность браузерных Developer Tools
60
74. Предусловия
• В JavaScript не используем CSS-классы
(абстрагируемся от верстки)
• В шаблонах явно указываются используемые
файлы стилей (нет глобальных)
70
75. 71
<b:style src="block.css"/>
<div class="block block_{hidden}">
{caption}
</div>
.block { … }
.block_hidden { … }
block.css
block.tmpl
Вот так
Инструкция шаблонизатору
о необходимости
подключить файл стилей
Префикс b: (сокр. от basis)
стандартный механизм
неймспейсов в XML
(для избежания конфликта
имен)
76. Взяв любой шаблон,
мы «знаем» всю его разметку
и используемые им стили
72
107. Понимание границ верстки дает
возможность для больших
оптимизаций
101
Границы обеспечивает изоляция стилей
108. 102
<b:style src="style.css"/>
<b:isolate/>
!
<div class="foo bar">
...
</div>
.foo {
color: red;
width: 100px;
}
.bar {
color: green;
}
example.tmpl style.css
У нас есть все информация об использовании
foo и bar встречаются только
на одном элементе
112. 106
<b:style src="example.css"/>
!
<span class="foo never-used">
...
</span>
.foo {
/* ... */
}
.dead-style {
/* ... */
}
example.tmpl example.css
Если класс используется в разметке, но
не используется в стилях или наоборот…
Не используемые имена классов
125. Трансформация имен классов
• В шаблоне:
.example
• В документе – режим разработки:
.i123__example
• В документе – боевая среда:
.h5fjy1bkfb4zcskh__example
116
126. Трансформация имен классов
• В шаблоне:
.example
• В документе – режим разработки:
.i123__example
• В документе – боевая среда:
.h5fjy1bkfb4zcskh__example
• В документе – боевая среда + сжатие имен:
.Gh
116
154. 140
loader: 'css?localIdentName=' + (
process.env.NODE_ENV === 'development' ?
'[name]__[local]___[hash:base64:5]' :
'[hash:base64:20]'
)
Можно управлять видом замены
В режиме разработки:
MyComponent__foo___1rJwx
В боевом окружении:
rJwx92gmbvaLiDdzgXiJ
155. 141
import React from 'react';
import styles from './MyComponent.css';
!
class MyComponent extends React.Component {
render() {
return (
<div className={styles.foo}>
<div className={styles.bar}>
Local scope!
</div>
</div>
);
}
};
Используем оригинальные имена,
не зная их текущего вида
156. В самом начале пути,
но в правильном направлении
142
Hot! Появилось всего два месяца назад
157. Все идет к тому, что это будет
стандартной функцией
загрузчика CSS в Webpack
143