Pull to refresh

CSS-in-JS — мифы и реальность (на примере styled-components)

Reading time 8 min
Views 59K

CSS-in-JS, будучи не совсем новой технологией и реализованной во множестве библиотек, до сих пор вызывает сомнения и споры в целесообразности ее использования. Свои точки над «i» в спорах о CSS-in-JS в общем, и о styled-components в частности, расставил еще год назад, ( 27 Apr 2017 ), и Gajus Kuizinas, автор react-css-modules и babel-plugin-react-css-modules, во все еще, на мой взгляд, актуальной публикации «Прекратите использовать CSS-in-JavaScript в веб-разработках».
Ниже предлагается слегка сокращенный ее перевод с некоторыми добавлениями и выводами:


CSS никуда не уходит. Во множестве проектов выбор в пользу стилизации в JavaScript делается ошибочно. Мы приведем перечень распространенных заблуждений(мифов) и соответствующих им решений посредством CSS.


История Css и JavaScript


CSS был создан для описания представления документа, написанного на языке разметки. JavaScript был создан, как «язык-клей» для сборки компонентов, таких, как изображения и плагины. Спустя годы, JS рос и изменялся, приспосабливаясь ко все новым сферам применения. И, как результат, мы сегодня живем в эру одностраничных приложений (SPA), приложений собранных из компонентов.


А что же с CSS?


Приведем цитату из документации styled-components:

Проблема обычного CSS состоит в том, что он был создан в эру, когда веб состояла из документов. Web была создана для обмена по преимуществу научными документами в 1993 году и CSS был введен, как решение для стилизации этих документов. Однако, сегодня мы разрабатываем развитые, интерактивные, ориентированные на пользователя приложения, а CSS просто не предназначен для этого.

Это не так.


CSS уже учитывает все требования современных пользовательских интерфейсов. Количество новых функций, реализованных в последнее десятилетие таково, что их все невозможно здесь даже перечислить (pseudo-classes, pseudo-elements, CSS variables, media queries, keyframes, combinators, columns, flex, grid, computed values, …).
С точки зрения пользовательского интерфейса, «component» — это изолированный фрагмент документа (<button />- это «component»). CSS создан для стилизации документов, а документ охватывает все компоненты. В чем же проблема?
Как говорится: «Используйте правильный инструмент для работы».


Styled-components


styled-components дает возможность написания CSS в JavaScript используя т.н. тегированные шаблонные строки. Библиотека удаляет сопоставление между компонентами и стилями — компонент  превращается в конструкцию с низкоуровневой стилизацией, например:


// Create a <Title> react component that renders an <h1> which is
// centered, palevioletred and sized at 1.5em
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;

styled-components сегодня пользуется популярностью и известна, как новый способ стилизации компонентов в React, хотя иногда ее представляют даже, как «вершину развития CSS»:
CSS Evolution: From CSS, SASS, BEM, CSS Modules to Styled Components.


Но давайте уясним следующее: styled-components — это всего лишь надстройка над CSS. Эта библиотека разбирает стили CSS, определенные вами в JavaScript и создает соответствующие JSX элементы.

Популярность styled-components сопряжена со множеством заблуждений. Обзор ответов программистов (найденных на IRC, Reddit и Discord) на вопрос о причинах, побудивших их применить эту библиотеку, позволил составить список наиболее упоминаемых. Назовем их мифами.


Миф #1: styled-components решает проблемы глобального пространства имен и конфликтов стилей


Это миф, потому что звучит так, якобы упомянутая проблема еще никак не решалась. Однако CSS Modules, Shadow DOM и бесчисленные соглашения по именованиям ( такие как BEM) предложили решения проблемы давным давно.
styled-components (точно так же, как и CSS modules) снимает с человека проблему ответственности за наименования. Человеку свойственно ошибаться, компьютеры ошибаются не столь часто.
Сам по себе, это еще недостаточно веский довод для использования styled-components.


Миф 2: Использование styled-components дает возможность получать более компактный код


В подтверждение часто приводят пример:


<TicketName></TicketName>
<div className={styles.ticketName}></div>

Прежде всего — это не имеет значения. Разница незначительна.
Во-вторых, это неправда. Общее количество символов зависит от имени стиля.


<TinyBitLongerStyleName></TinyBitLongerStyleName>
<div className={styles.longerStyleName}></div>

То же самое применимо и к созданию стилей, что мы увидим позже в этой статье
(Миф5: styled-components облегчает условную стилизацию компонентов). styled-components выигрывает в краткости только в случаях самых базовых компонентов.


Миф 3. Использование styled components вынуждает больше думать о семантике


Сам первоначальный посыл ошибочен. Стилизация и семантика представляют собой разные проблемы и требуют различных решений. Прочтите, например, это Adam Morse (mrmrs).


Тем не менее, рассмотрим:


<PersonList>
  <PersonListItem>
    <PersonFirstName>Foo</PersonFirstName>
    <PersonLastName>Bar</PersonLastName>
  </PersonListItem>
</PersonList>

Семантика занимается применением правильных тегов для разметки. А вы знаете, какие HTML теги будут использованы для рендеринга такого компонента? Нет, не знаете.
Cравните:


<ol>
  <li>
    <span className={styles.firstName}>Foo</span>
    <span className={styles.lastName}>Bar</span>
  </li>
</ol>

Миф 4: Проще расширять стили


Сравните:


const Button = styled.button`
  padding: 10px;
`;
const TomatoButton = Button.extend`
  color: #f00;
`;

Замечательно! Но то же самое вы можете сделать и в CSS (или использовать CSS module composition, а также SASS inheritance mixin @extend).


button {
  padding: 10px;
}
button.tomato-button {
  color: #f00;
}

И чем проще первый вариант?


Миф 5: Облегчается условная стилизация компонентов


Идея состоит в том, что вы можете стилизовать элементы используя props, например:


<Button primary />
<Button secondary />
<Button primary active={true} />

Это имеет смысл в React. В конце концов, поведение компонента контролируется через props. Есть ли смысл в прямой привязке prop значений к стилям? Может быть. Но давайте рассмотрим имплементацию такого компонента:


styled.Button`
  background: ${props => props.primary ? '#f00' : props.secondary ? '#0f0' : '#00f'};
  color: ${props => props.primary ? '#fff' : props.secondary ? '#fff' : '#000'};
  opacity: ${props => props.active ? 1 : 0};
`;

Создание условных стилей при помощи JavaScript дает массу возможностей. Однако, это также означает, что стили будет намного сложнее интерпретировать. Сравните с CSS:


button {
  background: #00f;
  opacity: 0;
  color: #000;
}
button.primary,
button.seconary {
  color: #fff;
}
button.primary {
  background: #f00;
}
button.secondary {
  background: #0f0;
}
button.active {
  opacity: 1;
}

В этом случае, CSS короче (229 символов против 222) и проще для понимания (субъективно). Более того, в CSS вы могли бы использовать препроцессор, чтобы получить еще более короткий и сгрупированный результат:


button {
  background: #00f;
  opacity: 0;
  color: #000;
  
  &.primary,
  &.seconary {
    color: #fff;
  }
  &.primary {
    background: #f00;
  }
  &.secondary {
    background: #0f0;
  }
  &.active {
    opacity: 1;
  }
}

Миф 6: Улучшается организация кода


Некоторые говорят о том, что им нравится styled-components, потому что появляется возможность размещать стили и скрипты в одном файле. Можно понять, что наличие множества файлов для одного компонента может показаться утомительным, но впихивание стилей и разметки в единый файл — это ужасно. Это не только системе контроля версий усложнит отслеживание изменений, но и приведет к бесконечному «скроллингу» на любом элементе посложнее простой кнопки.
Если же вам непременно нужно разместить CSS и JavaScript в одном и том же файле, попробуйте css-literal-loader. Последнее позволит вам собирать стили во время «build» посредством extract-text-webpack-plugin и использовать стандартную конфигурацию лоадера для обработки CSS.


Миф 7: «Developer Experience (DX) » становится прекрасным. Инструмент потрясающий!


Очевидно, что вы не использовали styled-components.


  • Если что-то пошло не так со стилями, все приложение «падает» с длинной стековой трассировкой ошибки. Противоположность этому — CSS, где ошибка в стилях приведет просто к неправильному отображению элемента.
  • У элементов отсутствуют различаемые className, поэтому при отладке придется бесконечно переключаться между React element tree и DevTools DOM tree.
  • И хотя плагины для линтинга, подсветки кода, автозавершения кода, и другие подобные «прелести» уже существуют и для styled-components, они все еще могут быть недоступны для вашего IDE. Если вы работаете с финансами в правительственном агенстве, есть шансы, что Atom IDE будет недоступна.

Миф 8: Все становится «шустрее», все становится «легче»


  • Как выяснилось, styled-components стили не могут быть экстрагированы в статический
    CSS файл (например используя extract-text-webpack-plugin). Это значит, что браузер не сможет начать интерпретацию стилей до тех пор, пока styled-components не «распарсит» их и не добавит в DOM.
  • Совмещение стилей и скриптов в одном файле означает, что раздельное их кеширование невозможно.
  • Природа styled-components такова, что все они обернуты в дополнительный HOС. А это ненужное понижение производительности. Такой же недостаток привел к прекращению поддержки react-css-modules и появлению babel-plugin-react-css-modules.
  • Из-за того же HOC, серверный рендеринг приводит к значительно большему размеру разметки документа.
  • Даже и не пробуйте анимировать компоненты используя динамические стили, а не keyframes.

Миф 9: Появляется возможность разработки «responsive» компонентов


Речь идет о способности стилизовать компонент на основе окружающей среды, например, размеров родительского контейнера, количества наследников и т. д.
Прежде всего, styled-components не имеют ничего общего с этим.
Это выходит за рамки проекта. В данном случае лучше прямо установить значения стиля компонента, чтобы избежать дополнительных нагрузок на процессор.


Минуточку, однако!


Большинство, если не все из этих проблем, могут быть решены в перспективе то ли сообществом, изменениями в React или в самой styled-components. Только зачем? CSS уже широко поддерживается, имеется солидное сообщество и… просто работает.
Но не нужно всегда избегать применения CSS-in-JavaScript или styled-components.
Есть кое-что, что делает styled-components хорошей библиотекой — это лучшая кросс-платформенная поддержка.
Просто не используйте styled-components исходя из ошибочных представлений.


Пара мнений от заинтересованных лиц


Talia Marcassa: Что мы нашли разочаровывающим в styled-components?


Применяя styled-components в нашем проекте мы обнаружили, что имеются некоторые стилевые правила, которые трудно внедрять в styled-components; например, правила, которые управляют размещением элементов на странице ( margins или display свойство). Это трудно поддавалось стандартизации, так что мы по-прежнему были вынуждены в значительной степени опереться на простой CSS для размещения компонентов в потоке элементов.
… хотя и были сложности в применении styled-components, библиотека помогла нам уменьшить кодовую базу.


Prometheus: В итоге что?


(комментарий к «Эволюция CSS: от CSS, SASS, BEM и CSS–модулей до styled-components»)


… Никакая эволюция CSS тут не значится, эволюционируют инструменты.
На мой взгляд, проблемы никакой нету, когда версткой занимается верстальщик, а программист — программированием.
А вот когда программисты занимаются версткой — вот тогда начинается весь этот зоопарк, который вместо ПРОСТОТЫ с дальнейшей поддержкой, дает лишнюю головную боль.

Пишите на чистом CSS, а инструментам отведите роль пространства имен и сборщика — тогда будет всем счастье…


И в заключение, слово автору:


Gajus Kuizinas: — Так что, все-таки, использовать?


  • Еще слишком рано говорить о Shadow DOM, ввиду недостаточно глобальной поддержки.
  • Используйте CSS с каким-либо соглашением об именовании (например BEM).
  • Если вас волнует проблема коллизий имен классов или вы слишком ленивы, чтобы использовать BEM, используйте CSS Modules.
  • Если вы работаете с React — рассмотрите возможность использования babel-plugin-react-css-modules.
  • Если же вы работаете с React native, styled-components — это то, что надо.
Tags:
Hubs:
+14
Comments 52
Comments Comments 52

Articles