Pull to refresh

Comments 52

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

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

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

С Рамдой это хорошо делать, через селект пропов или линзы. Но вот простой пример
const ifCondition => (propName, valueTrue, valueFalse) =>
    props => props[propName] ? valueTrue : (valueFalse || 'inherit');

const Component = styled.div`
  color: ${ifCondition('error', 'red')};
`;

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

CSS из этого не билдится, только js и шаблонные строки, а уже в рантайме — на клиенте, текст парсится и вставляется в DOM. Это еще круто тем, что стили полностью зависят от JS, за которым следит сборщик (не беря мертвый код в бандл) и который можно лениво загружать с динамическими импортами. Работает это очень бысто, если что.
C SSR все хорошо, можно почитать здесь.
Later on client-side, the consolidateStreamedStyles() API must be called to prepare for React’s rehydration phase

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


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

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


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

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

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

Ну например:


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

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

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

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

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

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


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

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

Все динамическое динамическое что происходит в CSS in JS описывается через JS, возможности которого очень широки, стоит лишь привыкнуть к этой мысли и подумать:
const IfPrimary => (ifTrue, ifFalse) => props.primary ? ifTrue : ifFalse

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

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


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


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


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

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


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


.button {
  // core styles
}

.button.primary {
  // primary variant styles
}

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


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


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

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

Прелесть CSS-in-JS в данном контексте в том, что if*() функции могут использовать не только статически заданные данные (селекторы и значения свойств), но и динамические.
const getButtonStyles = ({ type, theme }) => {
  switch (type) {
    case 'primary':
      return css`
        // primary styles
      `;
     case 'brand':
      return css`
        
      `;
     default:
       return css`
          // default styles
       `;
  }
}

const Button = styled.button`
  // common styles
  ${getButtonStyles}
  ${media.mobile`
    // mobile styles
  `}
`;
Чудесно, как раз то что нужно.

Очень странно, что в официальном туториале это не показано

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


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. Без лямбд, тернарных операторов и прочего визуального мусора. Но без динамической магии.

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

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

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

Так проблема локального скоупа имён классов уровня компонента (корневого элемента и детей) он уже решает без использования JavaScript или иных сборщиков? Соглашения об именовании — это костыль.
BEM ничего чужеродного, недокументированного, кривого, необычного в стили не вносит. Наоборот, вводит понятные общие правила в отношении имен стилей. Отличное простое решение ни на миллиметр не выходящее за спецификации CSS. Так что BEM никак не костыль.
Вот именно, что вводит дополнительные правила для проблем, решения которым CSS на уровне языка не предлагает. Это как эмуляция приватных свойств в JS с помощью замыканий или эмуляция нейспейсов в PHP с помощью имён классов типа Vendor_Package_Module_Class. О, что-то мне это напоминает.
Это именно решение не выходящее за рамки CSS. Кому-то нравится — кому-то нет. Не стоит усложнять. Верстальщики активно и успешно такими (или подобными) решениями пользуются (иногда даже не подозревая об этом).
Мало того, что оно не выходит, так оно ставит рамки более узкие чем в самом CSS. Чтобы решить некоторые проблемы CSS предлагает отказаться от некоторых его преимуществ.
Ну и глупости же вы говорите
При использовании BEM вам никто не помешает в разных компонентах, случайно заюзать одно имя класса более одного раза…
С SC этой проблемы вообще не возникает
Никто не помешает, кроме трезвого ума и здравой памяти. Правило, что имя должно соответствовать пути в файловой системе, очень простое и естественное. Нарушить его случайно крайне сложно.

Легко: опечатался при создании файла или именованной сущности, а потом ide автоподстановку делает и не замечаешь.

Ну вот если использовать MAM сборщик при этом, то сразу заметите — стили не будут включены в бандл.

Уверены, что это сразу заметно будет?

Я обычно не проверяю бандлы на предмет всё в них вошло или нет, особенно когда всё больше 1000.

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

faiwer justboris коллеги, простите, с моей точки зрения вы в упор не видите проблемы и, соответственно, релевантные решения, а так же закостенели в устарелых подходах. В своем докладе и статье я попытался, хоть и сумбурно, описать какую фундаментальную проблему решает SC в частности, попробуйте начать с этого, если вам еще интересно.
Каждый такой компонент — это атомарный элемент нашего приложения, который абстрагирует и совмещает в себе… набор стилей и их зависимость от аргументов (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.

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

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


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

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


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

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

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

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

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

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

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

Все это упрощается шикорим спектром готовых хорошо работающих инструментов и типичным флоу для разработчиков. А CSS декларация хорошо читается и весьма функциональна. Конечно же со временем это будет меняться, CSSinJS может вырасти, но пока чего-то особенного не предлагает.
Ну как не предлагает? Предлагает единый подход к генерации «html» и сss в js. Какой-то index.html служит лишь «master boot record» для JS, а всё остальное под управлением программистов. Это как раз типичный флоу для разработчиков, если не ограничивать понятие «разработчик» теми, кто начинал разработку как создание html, потом прикрутил css, потом js, а больше ничего и не делал, ну или делал матерясь «какой же в этом C нетипичный флоу, за всем надо самому следить».
1. Нет, он не звучит так, что данная проблема до StyledComponents никак не решалась. Styled Components просто ее эффективно решает.
2. Может код будет не всегда компактней, но JSX будет всегда читаемей. А снижение когнитивной нагрузки повышает продуктивность.
3. Нет, вы уж сравните:

<ol>
  <li>
    <FirstName>Foo</FirstName>
    <LastName>Bar</LastName>
  </li>
</ol>


4. Код этих расширенных стилей с использованием стилей Styled Components, читается гораздо проще.

5. Представьте в виде css:
<SomeComponent
  color={color}
  size={size}
/>


6. Глупости, это никак не усложняет отслеживание, а практика размещения CSS и JS хорошо себя показала в больших проектах и больших командах, анализ кода быстрей, а работать удобней. Не пытайтесь выдавать свое сугубо субъективное мнение за истину для всех.

7. Для отображения имен селекторов в babel-plugin-styled-components можно передать опцию displayName, о которой вы, видимо, не знали. Плагин доступен для всех популярных IDE и отлично работает.

8. Пруф на миф, пожалуйста. Вы явно что-то путаете. В интернете полно статей с бенчмаками, что ставит под сомнение существование приведенного вами мифа.

Статья, мягко говоря, с душком и вряд ли может претендовать на объективность.

К слову, закончил пару больших проектов на StyledComponents. Я бы без зазрения совести назвал библиотеку лучшим инструментом который приходилось использовать в React проектах.
Не пытайтесь выдавать свое сугубо субъективное мнение за истину для всех.

Но вы же занимаетесь ровно тем же!? Правда, в куда более грубой форме.

закончил

а поддерживать пробовали?

Да. Отсутствие селекторов в исходном коде во многом этому способствует.
Сколько лет поддерживали? Сколько редизайнов пережили?

Сколько разработчиков поддерживало это?

Sign up to leave a comment.

Articles