Как стать автором
Обновить

Комментарии 37

Изначальная проблема с кнопками элементарно решается с помощью CSS variables.

Отчасти да. Но...

  1. Был кейс когда в проект встраивались два микрофронтеда с использованием одной и той же UI библиотеки на CSS переменных. В одной библиотеке эти переменные были переопределены и что привело к конфликту CSS переменных со вторым микрофрондендом. Пришлось тратить время что бы выкрутиться из конфликта. В Styled Components такая ситуация невозможна в принципе.

  2. Пример с кнопкой наверное слишком простой, но и с CSS переменными вы там на мучаетесь. У меня есть компонент Grid. Что бы он соответствовал сетке из Figma пришлось писать логику. В Figma сетка на десткопах имеет 12 колонок, планшетах 8 колонок, на мобилках 2 колонки. А еще 6 брекпойнтов по размеру экрана. А еще есть сетки вложенные в сетки. Например сетка с колонками 3 и 9, в 9 вложена сетка еще на 9 колонок. А еще в дефолтном положении она имеет 12 колонок. И в таком кейсе вам никакие CSS переменные не помогут. Styled Components справился с задачей идеально, на все расчеты уходит 1 наносекунда.

извините, но это все очень спорно на больших проектах.

ни один инструмент не ультимативен.

хочу сказать еще, что так называемые "преимущества", использование bem как единственной альтернативы.. знаете, пока Вы не умеете это всё готовить. верстка, стилизация - это на самом деле не так сложно, если отойти от кучи вспомогательных инструментов и взглянуть на задачу, и тем более стилизованные компоненты не решают задачу сложности css - значит, у Вас просто что-то не так.

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

с наступившим новым годом, такой боевой настрой насчет фронта - вера в то, что есть энтузиасты) добра!

BEM приведен для примера как самый популярный подход написания компонентных стилей в CSS.

Но как же вы решаете проблемы удаления мертвых стилей, простой переход к CSS селектору, поиск используемых стилей при рефакторинге, изоляции стилей и остального без использования SC?

может быть при помощи PurifyCSS

Попробую предложить вариант: CSS Tree Shaking, Storybook и Emmet LiveStyle.

>>Только у меня разница составляла не 40%, а всего 10%.

Какие-то странные цифры - ни о чем. В каком окружении, на каком устройстве, в каком браузере?

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

Задача. Есть компонент, который встраивается на страницу заказчика, который очень сильно захотел сделать его красненьким, а не зелененьким. В обычных условиях проблема элементарно решается через вынесение основных цветов в CSS переменные и добавлением на странице переопределенных значений этих переменных. Как решить задачу в случае styled components без пересборки бандла компонента?

Вот вам контрпример: вы встраиваете компонет на страницу заказчика, а там используются те же имена стилей, что и в вашем компоненте. В результате чего происходит конфликт стилей.

>> В каком окружении, на каком устройстве, в каком браузере?

Это был тест. 1000 рандомно сгенерированных стилей и 1000 элементов на странице. Браузер Chrome. Процессор Ryzen 5800X.

>> Как решить задачу в случае styled components без пересборки бандла компонента?

На самом деле крайне странно слышать про пересборку SC с учетом того что это фактически JS и он полностью динамический в отличии от CSS.

Для решения задачи есть два варианта:

  1. SC не лишает вас ничего из того что у вас есть в CSS. Поэтому можно использовать все те же CSS переменные =)

  2. Но почему конкретно я не использую CSS переменные во встраиваемых модулях. Есть такой антипаттерн - Глобальные переменные. Фронты уже поняли что в JS его использовать плохо, но почему то не поняли что в CSS переменных его использовать все так же плохо. А CSS переменные это глобальные переменные.

В комментариях выше уже писал пример как я уже ловил багу из-за конфликта CSS переменных. Как эту проблему помогает решить SC? Значения в CSS назначаются через изолированные JS переменные.

Компонент пишется следующим образом:

export const config = {
  colors: {
    primary: "#000",
    secondary: "#001"
  }
}

export const Button = styled.div`
  color: ${() => config.colors.primary};
`;

А кастомизируется на стороне клиента следующим образом:

import {config, Button} from "awesome-button";

config.colors.primary = "#003";

export const Page = () => (
  <div>
    <Button>
      Стильная кнопка
    </Button>
  </div>
)

Это упрощенный пример, но передает суть. При таком раскладе нету ни малейшего шанса на конфликт переменных.

Ну вот вам пример - у меня в проекте заказчик хотел всё то же, но с перламутровыми пуговицами. Как мне это кастомизировать, не залезая в JS код? То, что вы написали, это не кастомизация, а сборка под клиента. Просто вы так написали, как будто эти компоненты серебряная пуля от всех без, хотя это далеко не так.

Этот инструмент сильно упрощает написание стилей. Судя по вашим словам ваша задача лежит за пределами написания стилей.

А ваша задача решается двумя способами. Либо компонент в пропсах принимает какие то кастомные элементы, которые подменяют дефолтные. За пример можно посмотреть MUI. Либо делать две независимые библиотеки.

Styled components и js-in-css абсолютно не работают в современном React 18 (streaming, Server components и все такое) и Next.js 13, если вы хотите использовать все эти последние фишки. Мой любимый MUI (material-ui), к сожалению тоже.

Я думаю они научаться без проблем работать вместе.

Автор опоздал с написанием статьи так лет на 5. Когда все уходят от styled-components (не от css in js) из-за того, что стили генерятся в рантайме. Посмотрите на другие библиотеки и на то, как это сейчас решают в других компаниях, тот же Griffel от Майкрософта. Все понимают, что нужно использовать либы, которые позволяют генерировать стили "behind the runtime". Плюс SC не генерирует атомические стили.

Что бы уйти от SC надо к нему с начало прийти =)

Надо понимать что SC распространен только в мире React. Angular и Vue разработчикам он не доступен. Да и в мире React он распространен только на 25% примерно. У многих он вызывает религиозную неприязнь, что ожидаемо сказалось на карме статьи.

А от рантайме уходить очень не удобно, потому что динамические стили часто сильно упрощают работу.

Кстати вспомнил. В статье целый раздел забыл =)

Бывают стили написанные следующим образом:

.img-1 {
    left: 1rem;
    top: 1rem;
}

...

.img-27 {
    left: 13rem;
    top: 9rem;
}

SC тут сильно выручает, в нем достаточно написать стиль один раз, а значения расставлять уже в верстке на элементы пропсами.

export const FloatImage = styled.img`
    left: ${(props) => props.left ?? 0}rem;
    top: ${(props) => props.top ?? 0}rem;
`;

БЭМ Модификаторами это изящно решается. А когда нужны динамические размеры то style={{left, top}}

Стуледы решают незначительную проблему красоты компонентов. И добавляют массу неприятностей связанных с SSR, отсутствием исправных инструментов линтинга, подсветки и авто модификации кода. Тот же аналог css-comb туда вряд ли прикрутишь, да и никому не надо.
Вся эта динамическая сущность пропсов пригождается в редких ситуациях.

Вы описали все модификатора цвета, вы описали все модификатора вариантов, вы закрасили кнопку серым в случае если она заблокирована, но тут вы понимаете что в разных вариантах кнопка блокировка выглядит по разному, где то фон залит серым, где то белым. И тут вы начинаете множить стили, вкладывать стили блокированной кнопки в варианты кнопок. Код начинает экспоненциально разбухать. И вот уже банальная кнопка превращается в файл стилей на тысячи строчек, а там еще и проблемы с приоритетами стилей начинают всплывать.
Если необходимо сделать заблокированную кнопку более блеклой, это решается обычно прозрачностью (opacity) или, например, с помощью ::after с бэкграундом и свойством mix-blend-mode, которое хорошо поддерживается современными браузерами. Плюс кастомные свойства, как правильно написали выше.

Но, если вы всё-таки не хотите знать ничего новее color и background-color, всю генерацию стилей можно сделать и в scss. Если что, в scss можно писать функции, списки и циклы. Это Тьюринг-полный язык.

Пример с кнопками взят из MUI. Кстати он написан на аналоге SC, библиотеке emotion. В той кнопке цвета меняются местами в зависимости от варианта кнопки. А это строго переменные CSS или JS.

Styled components как и весь css in js - большой неповоротливый костыль. Всё то же самое проще некуда решается на tailwind без необходимости писать стили вообще.

А проблема приведённая а начале выслана из пальца. Приоритетом стилей нужно уметь управлять. А раз верстать не умеешь - нефиг в мой любимый фронт вообще лезть.

О том почему же не стоит использовать styled я могу написать статью и пожирнее

Жду статьи =)

Про неповоротливость ты не прав, потеря на инициализацию всего 10-20%. Зато почти двухкратный прирост по скорости рендеринга. Так что неповоротливый тут голый CSS =)

Мое портфолио убеждает меня что с версткой у меня проблем все таки нет. Без проблем верстаю и однодневные лендинги и десятилетние энтерпрайзы. И пиксель перфект и все экраны. А ты умеешь в пиксель перфект? Или на глазок верстаешь ? ))

Tailwind - это новый бутстрап. Мусор который сейчас генерируется тоннами. Пройдет всего пару лет и от него все будут шарахаться как от бутстрапа в 2019-ом.

Интересно конечно, как можно получить выигрыш в идеальных условиях по приросту рендеринга, если в обоих случаях для рендеринга используется css?)

Все что делает sc это вставляет «динамические стили» в head в тег style.

При этом, нужно понимать, что чтобы дойти до стадии Парсинга стилей которые были добавлены на страницу. Надо скачать js, распарсить, построить ast, исполнить, прогнать полный цикл рендеринга браузера и только потом браузер начнёт парсить css. Ваши тесты игнорируют все эти шаги. При использовании чистого css, этот шаг первый)

Если вам действительно нужны динамические стили, которые меняются параметрами. Есть отличный атрибут - style. Он инкапсулирован в каждом элементе, размер 0кб и не имеет оверхеда в виде целой библиотеки)

А секрет прост. Движок CSS не бесплатно работает, он тоже имеет свои расходы. Просто об этом никто не пишет на хабре, поэтому вы о стоимости стилей и их рендеринга не задумываетесь. И чем больше в движке стилей, тем медленнее он делает выборки в этих стилях и следовательно рендерится страница. Сложные селекторы тоже убивают скорость движка CSS. SC готовит стили таким образом что во первых готовятся только те стили что реально используются и не тянет в прод мусор, во вторых имеет крайне простые селекторы. За счет чего движку CSS проще работать.

Да, подготавливает строку CSS и передает в движок. Примерно тоже самое что скормить CSS файл. Но SC скармливает не все стили сразу, а порционно, по мере необходимости.

Для того что бы запустить обычный сайт тоже надо скачать js и распарсить его. На самом деле в загрузке огромного файла CSS перед кодом нету никакой необходимости. Вы его все равно не увидите. А если вы будете добавлять CSS вместе с созданием компонента вы ничего не теряете. Даже выигрываете. Например можно использовать этот трюк https://habr.com/ru/post/684836/. Огромный CSS файл вы никак не положите в 14КБ. А в SC его нету. И можно получить лучший FCP в метрике перформанса.

Через атрибут stylе далеко не все можно сделать. Например нельзя отрисовать разный стиль в хроме и сафари.

Есть кейсы, где styled-components просто убивает производительность. У нас есть довольно большое приложение, где всё-всё-всё на styled components свёрстано.
И мы отгребли проблем с производительностью, когда styled компоненты рендерятся в ячейках гридов (пробовал grid из ant, aggrid и самописный) — происходит очень много созданий и удалений компонентов при скроле, и styled постоянно вставляет и удаляет в DOM дерево CSS стили. И это очень медленно. Баг на эту тему уже много лет существует у них в трекере, но сделать ничего не могут.

Пытался найти эту багу, не нашел.

Используем самописную сетку на гридах, ничего подобного не наблюдаем. Да и в MUI ничего подобного не встречал, а он на emotion.

Судя по описанной вами проблеме она находиться на уровне реакта, а не SC. Поскольку SC ничего не знает о тех стиля с которыми он работает, в т.ч. о гридах. У вас в каком то месте происходит пересоздание компонента, вероятнее всего из-за динамического контента или некорректно заданного key.

И комментарий @jodaka поддерживаю. С рендерингом styled в массивах infinite scrolls или drag-drop, в компонентах с большим деревом вложенностей дикие тормоза. И key тут не при чем - не надо из нас дестадовцев делать. Эта фигня удаляет и создаёт дочерние обноалянмому компоненту style тэги со всеми вытекающими проблемами с производительностью и морганием стилей

Зная внутренности работы библиотеки styled-components вы либо пишите про другую библиотеку, либо в чем то путаетесь. Конкретно в библиотеке styled-components не может такого происходить, там нету такой логики. Так же поиск в гугле не выдал ничего похожего с этой ошибкой.

С двукратным приростом скорости вы лукавите - мой опыт говорит об обратном. Каждый styled оборачивается реакт-компонентом.

В результате виртуальный дом захламлён. Нет ни mixins, ни includes, да почти ничего из тех путей оптимизации собранных стилей, что доступны в реально сильных вещах вроде sass или postcss - в styled нет.

Если прирост в скорости и был - только за счёт веса. Да и тут, опять же, грамотно сложенном связка с sass + tailwind через использование директив apply, extends, includes могут дать ещё больше экономии - тут есть поле для оптимизации. В styled нет. Это максимально простая технология, основанная на конкатенации строк. После вёрстки на tailwind sass наблюдать за восхвалениями styled просто потешно

Имеется ввиду скорость редеринга страницы, а не инициализации. График из чужого теста так же это подтверждает. Оптимизация происходит за счет того что в DOM вставлены только те стили что используются на странице. Например в тайлвинде во всем приложении вы используете стили w-48, w-52, w-56, w-60, w-64, w-72, w-80, w-96. Соответственно все эти стили используются и войду в сборку. Но на странице которую открывает пользователь используется только стиль w-60. В таком случае tailwind все равно загрузит все стили которые есть в сборке, даже если они не используются на странице. Тем самым пользователь проиграет и в трафике и в скорости рендеринга, ведь движку рендеринга надо будет обработать больше CSS правил. SC в таких случаях загружает только один стиль на w-60. Таким образом клиент выиграет на трафике и рендеринге.

Mixins и includes есть, реализуются только не через ключевые слова SASS, а средствами языка typescript. Кроме того у вас вообще есть вся мощь TS и нету ограничений возможностей препроцессора.

Такие вещи как apply, extends, includes работают одинаково в SC и SASS, на выходе в обоих случаях строка которая скармливается браузеру. Только SC это делает покомпонентно, а sass все сразу.

А мне потешно восхваление tailwind при ненависти к bootstrap, хотя по факту это одно и тоже.

Какой-то борщ с котлетами у вас выходит.

Когда вы строите предположения о том, что из-за бОльшего количества CSS пользователь потеряет в производительности — это только ваши фантазии, потому что styled-components добавляет рантайм оверхед (он в рантайме вставляет новые теги style в DOM). Можно себе представить ситуацию, когда на странице одна какая-то простая кнопка и 2MB CSS — в этом случае, действительно, styled-components будут выигрывать, но не потому что технология такая хорошая, а потому что кому-то лень было разобраться с лишними 2MB CSS. Да, парсер CSS жрёт ресурсы, но не надо забывать о том, что в классическом подходе, парсер сожрёт ресурсы 1 раз, когда стили загрузились, а для SC парсер будет запускаться каждый раз, когда создаётся новый компонент и JS сгенерит для него стили. На счёт проигрыша в траффике — тоже вопрос открытый, потому что те, кто не следит за размером CSS, обычно не следят и за размерами JS бандлов, поэтому там будут десятки мегабайт всякого не используемого на странице кода.

Когда вы говорите, что в SC есть mixins и includes, то немного лукавите, потому что styled-components старается изолировать каждый компонент от других, а в настоящих mixins/includes из SASS вся фишка именно в том, что они делают работу с каскадностью чуть удобнее. И, при грамотном написании, CSS кода будет всегда меньше, чем сгенерит styled-components, именно по той причине, что последний пытается делать вид, будто каскадности не существует (да, там тоже можно генерировать глобальные стили, но выглядит это, как костыль).

Когда вы уверяете других, что на выходе у SC и SASS получается строка, которая скармливается браузеру, то так ли это? SC требует для работы JS и не использует каскадность, поэтому ну никак не получатся одно и то же.

P.S. я не пытаюсь накидывать говно на вентилятор. Уже почти три года использую SC с реактом в нескольких проектах. Свою UI либу написали на SC. И в 90% случаев всё хорошо работает и удобно. Но оставшиеся 10% случаев вынудили ряд компонентов переписать c SC на linaria.

P.P.S. У меня параллельно есть ещё один очень большой проект на ангуляре. И как-то ни разу не поймал себя на мысли, что не хватает styled компонент. У ангуляра изоляция стилей работает из коробки, но её можно легко отключить там, где это требуется.

Уважаю styled components только в рамках react native. Иначе не вижу смысла пропускать css через js

А там альтернатив то и нету.

Десятилетия эволюции ушли на разделение стилей, разметки и кода, а потом приходит школота, которая не умеет ни в первое ни во-второе ни в третье, осилившая целую корявую либу для рендеринга (фреймворк слишком сложно для зумеров) и рассказывает про "сольём всё в одну бочку" и заживём счастливо...

Подскажите: это я стал брезжащим дедом или просто мир зациклился и ходит по граблям?

З.Ы.

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

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

Смешались в кучу люди, кони, и залпы тысячи орудий... (C) Лермонтов

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

У меня вот с точки зрения организации кода все остается неизменным. Компонент разбит на 3 файла: верстка, логика, стили. Только у стилей вместо расширения css используется расширения ts.

А у тебя в проектах логика вынесена за пределы вьюхи или все в куче и в одном файле? )))

Это хорошо, что лично у вас есть понимание, что слить всё в один файл - плохо. Однако SC и прочий JSX это позволяют. Следовательно это скорее всего рано или поздно будет сделано (если конечно на проекте не один дев уровня не ниже "выше среднего"). Немногие соблюдают данное разделение логики, разметки и стилей. Проблема "гибких" решений, к которым относится Реакт в том, что они позволяют творить любую дичь. И вот, чтобы код не превратился в дичь полностью следует довольно многое знать и понимать, что плохо соотносится с "простотой и доступностью" библиотеки для неокрепших умов.

Насчёт логики - она бывает разная. Соответственно находиться она может в разных местах: в компоненте (внутренняя логика компонента) в контейнере (бизнес-логика), в сервисном слое и даже в роутинге (я не про убогий реакт-роутер). Вопрос в целом холиварный и к теме SC не особо относится.

Насколько я помню по предыдущим обзорам у SC лютая проблема с производительностью (всё-таки браузеры оптимизированы под нативный CSS), что сразу делает его хуже любого препроцессора. Кроме того в комментариях отметили проблемы совместимости. Добавим отсутствие кроссплатформенности.

Итого имеем: сомнительный инструмент узкой сферы применения. Я верю, что для определёных задач и условий он может подходить лучше остальных, хотя и не представляю для каких, но не советую считать его единственно правильным инструментом и останавливаться именно на нём.

Так то любую дичь и JS позволят творить ) По вашей логике Веб должен был бы развалиться, но нет. Веб жив. =)

Вот тут мы и выясняли кто тут школота. Любой дед знает что во вьюхе не может быть никакой логики. Поэтому любой дед разделяет компонент на MVC. Поэтому возвращаемся к исходному коменту про разделение. И получается что вы сами себя школотой обозвали ))

А что для движка CSS нативно? Файл CSS? Не угадали. Это всего лишь файл данных, примерно как JSON для V8. Нативно для для движка CSS это массивы объектов в памяти. И тут SC гораздо ближе к нативно чем CSS. А с точки зрения движка между CSS и SC разница лишь в том что первый скармливает сразу все стили, а второй порционно по мере необходимости. Какая проблема с производительностью? 10% на инициализацию? Не смертельно. Зато скорость рендеринга почти в два раза возрастает что напрямую влияет на пользовательский опыт. Какие еще проблемы совместимости? Это js, его полифилить хоть до ie6 можно. Какое еще отсутствие кроссплатформенности? Работает во всех браузерах и операционних системах.

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

Я где-то написал про вьюхи? А почему ваши деды используют исключительно MVC, а не MVVM или MVP? Любой компонент следует разделять на MVC? А вы в разработке руководствуетесь исключительно паттернами или ещё и здравым смыслом? Любую идею (даже самую верную) можно довести до абсурда.

Как ни странно, для обработки формата CSS нативным является формат CSS.

А чего вы от "нулей и единичек" сразу к массивам объектов перешли? Хотите донести мне, что всё в итоге трансформируется в машинный код и JS к нему ближе, чем CSS? Отнюдь.

Так-то и 100% не смертельно. Да и тысяча тоже. Но 10% это много. Если не согласны - попросите "немного" снизить ваш рейт и ответьте много это или нет.

Для освежения памяти: https://habr.com/ru/post/707510/#comment_25070240
Я имел ввиду не пользовательские платформы, а поддержку фреймворков (да и с поддержкой либы судя по комментарию выше дела не ахти).

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории