emotion

Следующее поколение CSS-in-JS

Andrey Melikhov
devSchacht
5 min readJul 31, 2017

--

Иллюстрация от https://twitter.com/ChrisMCarrasco

Перевод статьи Kye Hohenberger: emotion. The Next Generation of CSS-in-JS.

Emotion — это высокопроизводительная, легкая библиотека css-in-js. Основная идея исходит из библиотеки glam Сунила Пая, и её философия изложена здесь. Ключевая идея очень проста. Вам не нужно жертвовать производительностью ради удобства разработчиков при написании CSS. Emotion минимизируют стоимость исполнения css-in-js, анализируя ваши стили с помощью babel и PostCSS. Ядро библиотеки в рантайме занимает 2,3кб и поддержка React — 4кб. Всего.

Первый взгляд

API покажется вам знакомым, если вы знаете styled-components. Мы также черпали вдохновение в glamorous и css-modules.

Бенчмарки

Этот бенчмарк нагружает библиотеки, очень быстро изменяя динамическое значение в блоке стиля.

Против styled-components — emotion более чем в 25 раз быстрее при использовании высокодинамичных значений props и при этом меньше на треть.

Styled-components предупреждают об опасности использовании этого паттерна и вместо этого рекомендуют использовать инлайн-стили для высокодинамических значений. Emotion не имеют таких ограничений.

Против glamorous — emotion до 2,5 раз быстрее на ререндере и в половину меньше.

CSS

import { css } from 'emotion'

CSS это ❤️ emotion. Большая часть API, включая styled, является просто обёрткой над css.

css - это тегированный литерал шаблона, который принимает стандартный css-текст с несколькими дополнительными функциями, такими как вложенность, псевдоселекторы и медиа-запросы.

css возвращает строковое имя класса, которое может использоваться для любого элемента. Для нашего блока стиля imageBase, описанного выше, это будет что-то вроде css-imageBase-12345.

Чтобы помочь с композицией, css принимает специальное свойство в блоке стиля, называемое composes.

С помощью composes мы можем использовать наш imageBase, чтобы быстро создавать стили аватаров.

Внутренняя реализация emotion добавит эти css-классы к сгенерированному результату. avatarStyleполучит имя класса вида css-imageBase-12345 css-avatarStyle-12345. Это позволяет создать действительно мощную композицию, которая особенно хорошо показывает себя вместе со styled.

Объекты стилей не обрабатываются авто-префиксером.

styled

import styled from 'emotion/react'

styled это тонкая обертка вокруг css, которая поддерживает тот же стиль текста и выражений, что и css.

Использование styled очень похоже на использование styled-components.

styled также работает как вызов функции. Первым аргументом может быть любой html-тег или React-компонент, который имеет поддержку свойства className.

Вы также можете использовать другой стилизованный компонент в качестве селектора.

Композиция также работает.

В styled, значение интерполяции composes может быть функцией. Она вызывается с текущими props во время рендера. Эта функция должна возвращать className или объект стиля.

Помните, что css просто возвращает className, так что это работает.

Истинная сила композиции раскрывается при её использовании с чем-то вроде styled-system Брента Джексона.

Поддержка тем

import { ThemeProvider } from 'emotion/react'

Поддержка тем реализована с помощью библиотеки theming. Детали API подробно изложены по ссылке. Она основана на системе тем styled-components и мощно протестирована, что сделало её беспроблемной.

Всякий раз, когда вы предоставляете тему ThemeProvider, любой стилизованный компонент имеет доступ к этим стилям через props.theme. Неважно, как глубоко вложен ваш компонент внутри ThemeProvider, у вас все еще есть доступ к props.theme.

Extract Mode против Inline Mode

Babel-плагин для emotion по умолчанию работает в так называемом «extract mode». В этом режиме мы берем все ваши css, определенные в каждом файле, извлекаем их в [filename].emotion.css и автоматически импортируем в верхнюю часть вашего JavaScript-файла. Динамические значения обрабатываются с помощью CSS-переменных. Единственные обновления во время выполнения - это просто изменения в CSS-переменных! Недостатки режима «extract mode» — отсутствие поддержки IE11 из-за CSS-переменных и невозможность извлечь критический CSS для рендеринга на стороне сервера.

В «inline mode» emotion работает несколько иначе.

В этом режиме используется CSS Object Model (CSSOM) для управления CSS из JavaScript. Так же работает любая другая библиотека css-in-js. Что отличает emotion, так это то, что мы можем прекомпилировать все ваши CSS-правила. Нам не нужно анализировать и дополнять ваши стили префиксами в рантайме, потому что мы уменьшаем ваши стили до непосредственных вызовов insertRule.

Самые большие преимущества режима «inline mode» заключаются в том, что он работает на IE9 и выше, и у него есть поддержка рендеринга на стороне сервера с помощью extractCritical. Вот отличный пример этого в репозитории next.js.

Под капотом

Следующий пример предназначен для режима «inline mode». Режим «extract mode» работает практически также.

Этот код

С помощью Babel компилируется в следующий

Всякий раз, когда вызывается метод рендеринга H1:

  1. styled проходит через каждое динамическое значение в вашем блоке CSS. Когда он итерируется через этот список, любое значение, которое является функцией, вызывается и получает текущие props.
  2. createEmotionStyledRules вызывается с использованием конечных значений с шага 1 в качестве аргументов. В нашем примере результатом props => props.color будет x0.
  3. Результат этого вызова затем вставляется в обёртку StyleSheet emotions, где он агрессивно кэшируется.
  4. Сгенерированные имена классов добавляются к свойству className компонента.

Взгляните на исходники styled и css.

Бонус

CSS-анимации

Анимации поддерживаются с помощью функции keyframes.

Свойство css

Любой компонент в вашем приложении, который принимает свойство className, теперь может принимать свойство css.

Свойство себя точно так же, как функция css. Полученное имя класса добавляется к свойству classNameэлемента.

Пойдите, напишите немного CSS.

Я хочу поблагодарить Сунила Пая за его руководство, терпение и за доверие ко мне, в том, чтобы выполнить его идею. 🙏

Огромное спасибо Митчеллу Гамильтону, потому что без него emotion не работали бы так хорошо. Его вклад был неоценим в том, чтобы мы достигли того, чего достигли.

Спасибо всем контрибьюторам, создателям ишью и тестировщикам ранних релизов!

emotion.sh — вебсайт

slack.emotion.sh — канал в Slack, заходите поздороваться! 👋

Спасибо, Nadim.

Слушайте наш подкаст в iTunes и SoundCloud, читайте нас на Medium, контрибьютьте на GitHub, общайтесь в группе Telegram, следите в Twitter и канале Telegram, рекомендуйте в VK и Facebook.

Статья на GitHub

--

--

Andrey Melikhov
devSchacht

Web-developer in big IT company Перевожу всё, до чего дотянусь. Иногда (но редко) пишу сам.