Комментарии 52
звучит так, якобы упомянутая проблема еще никак не решалась— нет, это так не звучит. По такой логике можно сказать что 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?
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 схему (регулярное явление в больших проектах), то CSS-in-JS заставит нас весь код просто завалить импортами, либо радикально упрощать схему стилизации (что в той же степени усложнит её в другой плоскости).
Вот пример из статьи (даже немного упрощенный):
styled.Button`
background: ${props => props.primary ? '#f00' : '#00f'};
color: ${props => props.primary ? '#fff' : '#000'};
padding: 0.5rem 1rem;
`;
Чтобы переопределить стили для <Button primary={true} />
, нужно написать Х инлайновых функций, по числу свойств, которые нужно переопределить. Враппер ifCondition
от дублирования помогает не сильно.
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 вариантов нужно добавлять функцию-хелпер, это минус в эргономике, конечно.
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
. Без лямбд, тернарных операторов и прочего визуального мусора. Но без динамической магии.
del
привел к прекращению поддержки react-css-modules
Очень спорное заявление. Последний коммит в репозиторий был две недели назад
> CSS уже учитывает все требования современных пользовательских интерфейсов
Так проблема локального скоупа имён классов уровня компонента (корневого элемента и детей) он уже решает без использования JavaScript или иных сборщиков? Соглашения об именовании — это костыль.
С 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 в своей плоскости, где есть взаимосвязи.
Вот как завезут с SC поддержку чего-то похожего на модификаторы из БЭМа, можно посмотреть еще раз. А пока — нам и с CSS неплохо.
Под капотом идет отличная система инкапсуляция стилей, сейчас они эмулируют поведение ShadowDOM с некоторыми оговорками. И это работает хорошо, БЭМ и подобные системы больше не выполняют никакой роли, уже упрощение.
Я пробовал CSSinJS некоторое время и могу сказать, что для Angular в нем нет смысла вообще. Через биндинг классов управляем отображением, все организационные плюшки через SCSS. Редкие случаи, когда нужно передать какие-то конкретные значение — биндинг стилей.
Все это упрощается шикорим спектром готовых хорошо работающих инструментов и типичным флоу для разработчиков. А CSS декларация хорошо читается и весьма функциональна. Конечно же со временем это будет меняться, CSSinJS может вырасти, но пока чего-то особенного не предлагает.
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 проектах.
CSS-in-JS — мифы и реальность (на примере styled-components)