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 — это то, что надо.

Комментарии (32)


  1. artalar
    24.07.2018 11:39

    1)

    звучит так, якобы упомянутая проблема еще никак не решалась
    — нет, это так не звучит. По такой логике можно сказать что CSS Modules не нужны, т.к. они решают проблему, которую уже решил БЕМ.
    2) Ваш пример далек от жизни. Пишу на SC давно и у меня нет компонентов с большими названиями, т.к. в этом нет необходимости при правильной организации модулей и их скоупов.
    4) Добавьте в этот пункт пример использования расширенных компонентов и сами все поймете (с классами кода будет больше)
    5) Если кто-то пишет код так же, как в вашем примере, он не умеет использовать SC. На динамические стили пишуться отдельные селекторы, которые уменьшают бойлерплейт и улучшают читаемость.
    7) * и это хорошо, т.к. позволяет отловить ошибку, а не проглядеть ее * есть бабель-плагин, который исправляет это * высосано из пальца, подсветка есть даже в саблайме.
    8) такого «мифа» нет. SC, конечно, имеет свою стоимость, но она не значительна.

    Самое главное, SC убирает необходимость в биндинге компонентов к стилям в виде классов, предлагая по другому смотреть на абстракции технологий, я говорил об этом в своем докладе, рекомендую к ознакомлению.


    1. justboris
      24.07.2018 22:38

      5) Если кто-то пишет код так же, как в вашем примере, он не умеет использовать SC. На динамические стили пишуться отдельные селекторы, которые уменьшают бойлерплейт и улучшают читаемость.

      А можете показать пример? Документация предлагает писать именно стену лямбда-функций, что не всегда удобно.


      1. artalar
        25.07.2018 08:35

        С Рамдой это хорошо делать, через селект пропов или линзы. Но вот простой пример

        const ifCondition => (propName, valueTrue, valueFalse) =>
            props => props[propName] ? valueTrue : (valueFalse || 'inherit');
        
        const Component = styled.div`
          color: ${ifCondition('error', 'red')};
        `;
        


        1. faiwer
          25.07.2018 08:56

          А как такие вещи в итоге выносить в отдельные файлы стилей в финальном билде? Или такая цель отбрасывается изначально? Если отбрасывается изначально, то продумана ли система для использования SSR?


          1. artalar
            25.07.2018 09:04

            CSS из этого не билдится, только js и шаблонные строки, а уже в рантайме — на клиенте, текст парсится и вставляется в DOM. Это еще круто тем, что стили полностью зависят от JS, за которым следит сборщик (не беря мертвый код в бандл) и который можно лениво загружать с динамическими импортами. Работает это очень бысто, если что.
            C SSR все хорошо, можно почитать здесь.


            1. faiwer
              25.07.2018 09:20

              Later on client-side, the consolidateStreamedStyles() API must be called to prepare for React’s rehydration phase

              Ага. Значит этот момент постарались учесть.


              CSS из этого не билдится, только js и шаблонные строки,

              Понятно, стало быть это для совсем отчаянных джедаев.


              Хорошо, а если, скажем, я не настолько отчаянный, и всё таки хочу иметь отдельный CSS файл (или даже несколько), который можно кешировать и грузить отдельно и вообще не хочу никакого лишнего css-runtime-а, могу ли я, скажем, избегая всех этих динамических привязок к JS, при финальном билде выносить всё в отдельный файл? Разумеется так, чтобы без изменений в стилях я не получал новые значения классов и пр., и это можно было нормально кешировать.


              1. artalar
                25.07.2018 09:25

                Вам дают новый подход с избавлением от кучи лишних действий, а вы спрашиваете как бы это использовать по старом, с лишними действиями? :)
                Расскажите зачем (надеюсь в процессе осмысления поймете, что это не нужно, ну либо я попытаюсь в очередной раз парировать ваши аргументы)?

                Как бы то ни было, я могу ответить на ваш вопрос и утвердительно — emotion. Сам не пробовал, но слышал что он умеет билдиться в статику.


                1. faiwer
                  25.07.2018 09:49
                  +1

                  Ну например:


                  • Мы можем использовать без всяких SSR html-болванку, пока приложение грузится, используя стили приложения. Мы так делаем.
                  • Минорные релизы часто будут обновлять только JS файлы, не трогая CSS, что определённо плюс, а не минус.
                  • Эти стили можно переиспользовать в других частях проекта, где наше SPA не используется. Да и наш SPA вполне может быть не SPA, а просто A, и share-ить общие стили с другими такими A, присутствующими на странице.

                  Я пока как не пыжился не смог найти ни одного плюса от CSS-in-JS в моих текущих проектах. Складывается ощущение, что каждая строчка кода против. И то-ли лыжи не едут, то-ли я… Новые технологии, новые возможности я люблю, но вот конкретно эта ветвь развития прогресса выглядит особенно отвязанной от привычного положения вещей. Она как-будто отвечает на те вопросы, которые мы не задавали, игнорируя те, которые нам нужны.


                1. m512781 Автор
                  25.07.2018 11:12

                  А от каких, все-таки лишних действий избавляет CSS-in-JS?
                  Ведь, что лишне, а что нет — очень субъективно.
                  Многие считают, например, что почти всегда именно CSS-in-JS — это лишние действия.


                  1. faiwer
                    25.07.2018 11:27

                    Причём если взять достаточно сложную CSS схему (регулярное явление в больших проектах), то CSS-in-JS заставит нас весь код просто завалить импортами, либо радикально упрощать схему стилизации (что в той же степени усложнит её в другой плоскости).


                  1. VolCh
                    26.07.2018 07:08

                    Как минимум от создания css файлов и их подключения к html. :)


        1. justboris
          25.07.2018 09:43

          Вот пример из статьи (даже немного упрощенный):


          styled.Button`
            background: ${props => props.primary ? '#f00' : '#00f'};
            color: ${props => props.primary ? '#fff' : '#000'};
            padding: 0.5rem 1rem;
          `;

          Чтобы переопределить стили для <Button primary={true} />, нужно написать Х инлайновых функций, по числу свойств, которые нужно переопределить. Враппер ifCondition от дублирования помогает не сильно.


          1. artalar
            25.07.2018 09:52

            Все динамическое динамическое что происходит в CSS in JS описывается через JS, возможности которого очень широки, стоит лишь привыкнуть к этой мысли и подумать:

            const IfPrimary => (ifTrue, ifFalse) => props.primary ? ifTrue : ifFalse

            ^ тоже самое можно было бы сделать через композицию с ifCondition и т.д.
            Конкретно по этому пункту (#5) уже точно JS всегда будет в выйгрыше, т.к. всегда есть возможность либо написать любые селекторы самому, либо взять готовые. Это явно лучше, чем работать с захардкоженными в препроцессор методами и собственным синтаксисом.
            В этом плане CSS in JS — это эволюционное развитие и при этом упрощенние препроцессоров и тягаться с ними не вижу никакого смысла, нативный язык (JS) всегда будет функциональнее и проще (его не надо дополнительно учить).
            P.S. по поводу препроцессоров, их встроенные методы-хелперы так же прекрасно заменяются.


            1. faiwer
              25.07.2018 10:07

              нативный язык (JS) всегда будет функциональнее и проще (его не надо дополнительно учить).

              Вы когда-нибудь писали на PHP? Сталкивались с кодом, который совмещает в себе сборку SQL, CSS, JS, HTML и PHP-условия в рамках одного файла? Там используются широкие возможности PHP как динамического языка. И да, такой подход по определению более функциональный и "простой". Но вы понимаете к чему я клоню, да?


              Каждый DSL решает свою задачу не так универсально, как некое анархичное решение. Но, если он сделан по уму, решает её более наглядно и удобно. DSL в итоге приходится учить, да. И преимущества от его использования должны превышать недостатки от его освоения.


              В данном случае мы столкнулись с тем, что пытаемся в domain стилей засунуть чуждую им динамику. И делаем это через template string. Совершенно не декларативно. В результате очень сильно падает наглядность, код очень визуально зашумлён, результат трудно предсказуем (пока мы внимательно под микроскопом не изучим код). Но мы получили возможности добавить такую динамику, которая ранее никому и не снилась. Отсюда вопрос — а стоило ли оно того. Нужна ли эта динамика в таком вот виде? Наверное, это, как минимум сильно зависит от проекта.


              Это я к чему. То что вы называете эволюционным развитием и упрощением, многие видят как деградацию и усложнение. Тут вопрос лишь в том, в каких очках и под каким углом посмотреть. Вопрос как минимум спорный ) Скажем я в таких делах почти всегда предпочту декларативное решение.


            1. justboris
              25.07.2018 10:13

              А если у нас вариантов больше? Объявлять функцию на каждый случай? ifPrimary, ifSecondary, ifDisabled?


              В обычном CSS можно сделать так


              .button {
                // core styles
              }
              
              .button.primary {
                // primary variant styles
              }

              Такой подход легко масштабируется, добавлять новые варианты очень легко.


              В styled-components тоже можно что-то подобное для :hover.


              styles.Button`
                 // core styles
                 &:hover {
                   // hover styles
                 }
              `

              А то, что для props-based вариантов нужно добавлять функцию-хелпер, это минус в эргономике, конечно.


              1. VolCh
                26.07.2018 07:27

                Прелесть CSS-in-JS в данном контексте в том, что if*() функции могут использовать не только статически заданные данные (селекторы и значения свойств), но и динамические.


          1. faiwer
            25.07.2018 09:59

            Наверное предполагается, что так:


            styled.Button`
              background: ${ifPrimary('#f00' : '#00f')};
              color: ${ifPrimary('#fff' : '#000')};
              padding: 0.5rem 1rem;
            `;

            или даже так:


            ${ifProp('primary').then('#f00').else('#00f')}

            А вот традиционное решение:


            &[data-primary] { 
              background: #f00; 
              color: #fff;
            }
            &:not([data-primary]) { 
              background: #000; 
              color: #000;
            }

            Насколько я понимаю, многие css-in-js решения позволяют писать традиционные &... из SCSS\Less\Stylus. Без лямбд, тернарных операторов и прочего визуального мусора. Но без динамической магии.


      1. justboris
        25.07.2018 09:42

        del


  1. inoyakaigor
    24.07.2018 14:21

    привел к прекращению поддержки react-css-modules

    Очень спорное заявление. Последний коммит в репозиторий был две недели назад


  1. m512781 Автор
    24.07.2018 14:59

    Это заявление сделал сам автор react-css-modules еще в прошлом году. Он же и там же рекомендует присмотреться к его же babel-plugin-react-css-modules, как менее ресурсоемкой альтернативе.


  1. VolCh
    24.07.2018 19:46

    > Это не так.

    > CSS уже учитывает все требования современных пользовательских интерфейсов

    Так проблема локального скоупа имён классов уровня компонента (корневого элемента и детей) он уже решает без использования JavaScript или иных сборщиков? Соглашения об именовании — это костыль.


  1. m512781 Автор
    24.07.2018 21:40

    BEM ничего чужеродного, недокументированного, кривого, необычного в стили не вносит. Наоборот, вводит понятные общие правила в отношении имен стилей. Отличное простое решение ни на миллиметр не выходящее за спецификации CSS. Так что BEM никак не костыль.


    1. VolCh
      24.07.2018 22:35

      Вот именно, что вводит дополнительные правила для проблем, решения которым CSS на уровне языка не предлагает. Это как эмуляция приватных свойств в JS с помощью замыканий или эмуляция нейспейсов в PHP с помощью имён классов типа Vendor_Package_Module_Class. О, что-то мне это напоминает.


      1. m512781 Автор
        24.07.2018 23:11

        Это именно решение не выходящее за рамки CSS. Кому-то нравится — кому-то нет. Не стоит усложнять. Верстальщики активно и успешно такими (или подобными) решениями пользуются (иногда даже не подозревая об этом).


        1. VolCh
          26.07.2018 07:02

          Мало того, что оно не выходит, так оно ставит рамки более узкие чем в самом CSS. Чтобы решить некоторые проблемы CSS предлагает отказаться от некоторых его преимуществ.


  1. artalar
    25.07.2018 10:54
    -1

    faiwer justboris коллеги, простите, с моей точки зрения вы в упор не видите проблемы и, соответственно, релевантные решения, а так же закостенели в устарелых подходах. В своем докладе и статье я попытался, хоть и сумбурно, описать какую фундаментальную проблему решает SC в частности, попробуйте начать с этого, если вам еще интересно.


    1. faiwer
      25.07.2018 11:22
      +1

      Каждый такой компонент — это атомарный элемент нашего приложения, который абстрагирует и совмещает в себе… набор стилей и их зависимость от аргументов (props).

      Вот пример того, о чём я писал выше. Не получается увязать стили с атомарным представлением. То, что является атомарным с точки зрения семантики или JS взаимодействий, не является атомарным с точки зрения стилей. Это разные плоскости и в них разные решения/подходы. Взаимосвязи в CSS могут столь коренным образом отличаться от взаимосвязей в JS, что любые попытки как-то их сблизить тщетны. Во всяком случае у меня так. Поэтому несмотря на множество SCSS файлов их структура лишь косвенно связана со структурой JS-кода. Плюс мне всегда было гораздо удобнее стилизовать единый набор сущностей в рамках одного файла, а не разбрасывать их по 10-ам и полностью лишиться общей картинки. Подход каждый сам за себя уместен, когда его отдельные части независят друг от друга. У меня таких проектов не было.


      Но управляете ими в используемом компоненте!

      В очень малой мере. Мы задаём скорее семантику, от которой в итоге отталкиваемся в том числе и в CSS. Эти вещи могут быть даже не связаны напрямую.


      и делаете это внутри компонента, который, казалось бы, должен отвечать за другую абстракцию

      Вот как раз в HTML и видится уместным расстановка всех флагов вроде -selected, различные режимы, disabled и пр. Т.е. как раз внутри компонента оно лежит не зря. HTML говорит "что", CSS говорит "как".


      Вот смотрите. На вашем же примере:


      const Button = styled.button`
        border-radius: 0.2rem;
        border-color: ${p => (p.disabled ? 'gray' : 'black')};
      `;

      Мы имеем семантическое disabled, которое должно быть задано в HTML. Вы же предлагаете задать его в стилях. Вы теперь при стилизации отталкиваетесь не от того "что мы показываем", а от более высокого уровня, от данных по которым можно понять "что мы показываем". Сломали саму парадигму. Связались напрямую.


      ИМХО стандартный подход как раз не устарел. Отчасти закостенел и ждёт новых решений. Но предлагаемые решения не являются решениями. Отвечают на те вопросы, которые не задавали, тем образом который неприемлем (для многих из нас). Рискну нарваться на минуса, но такой подход больше напоминает php-css-sql-js-html hype-портянку костылей, нежели на строгое элегантное решение. Даже сама мысль базировать оформление основываясь не на семантике итогового HTML а прямо на данных для формирования этого тега уже, честно говоря, очень плохо "пахнет". Обратите внимание на то, что CSS идеологически и фактически базируется на HTML.


      1. artalar
        25.07.2018 11:45

        Я с вами, опять, не согласен :)
        По поводу разделения ответственностей и абстракций у меня есть аргументированный ответ — компоненты системы как раз должны зависить от данных и меньше думать о их технической реализации.
        P.S. по мне так очень хорошая аналогия заключается в том что CSS in JS очень похож и повторяет историю JSX. На него же уже можно ссылаться как на «благо»? А изначально его не понимали и хейтили, прямо как данный топик :)


        1. faiwer
          25.07.2018 12:24

          На него же уже можно ссылаться как на «благо»?

          Смотря кого спросите. Мой ответ: зло. Но тут больше претензии к реализации. Само наличие DSL внутри JS-синтаксиса для описания динамической HTML-разметки — наверное, скорее добро, во всяком случае для SPA. По сути ребята напоролись на те же грабли, что и создатели других шаблонизаторов: разрешили произвольный JS в любых местах (аки в PHP). Но при этом добавили ложкуцистерну дёгтя — не реализовали ни одного примитива для итерирования и вветвления. В итоге React это худшее что я видел с точки зрения читаемости среди HTML-шаблонизаторов. И наверное почти худшее с точки зрения генерации говно-кода.


          А изначально его не понимали и хейтили, прямо как данный топик :)

          И продолжают. Ничего же не изменилось. Кроме </> в JSX не добавили ничего. Народ уже не первый год сочиняет как исправить язык, но воз и поныне там.


          у меня есть аргументированный ответ

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


    1. justboris
      25.07.2018 11:41

      Я понимаю пользу от использования styled-components. А еще я вижу определенные недостатки, и для меня они кажутся существенными.

      Вот как завезут с SC поддержку чего-то похожего на модификаторы из БЭМа, можно посмотреть еще раз. А пока — нам и с CSS неплохо.


  1. navix
    25.07.2018 23:34

    Могу сказать по Angular.

    Под капотом идет отличная система инкапсуляция стилей, сейчас они эмулируют поведение ShadowDOM с некоторыми оговорками. И это работает хорошо, БЭМ и подобные системы больше не выполняют никакой роли, уже упрощение.

    Я пробовал CSSinJS некоторое время и могу сказать, что для Angular в нем нет смысла вообще. Через биндинг классов управляем отображением, все организационные плюшки через SCSS. Редкие случаи, когда нужно передать какие-то конкретные значение — биндинг стилей.

    Все это упрощается шикорим спектром готовых хорошо работающих инструментов и типичным флоу для разработчиков. А CSS декларация хорошо читается и весьма функциональна. Конечно же со временем это будет меняться, CSSinJS может вырасти, но пока чего-то особенного не предлагает.


    1. VolCh
      26.07.2018 07:38
      -2

      Ну как не предлагает? Предлагает единый подход к генерации «html» и сss в js. Какой-то index.html служит лишь «master boot record» для JS, а всё остальное под управлением программистов. Это как раз типичный флоу для разработчиков, если не ограничивать понятие «разработчик» теми, кто начинал разработку как создание html, потом прикрутил css, потом js, а больше ничего и не делал, ну или делал матерясь «какой же в этом C нетипичный флоу, за всем надо самому следить».