Pull to refresh

Comments 32

Хороший пример, точно так же как и со строками селекторов, единицы измерения не более типизированы чем в самом CSS, так что улучшать есть ещё куда.

Работы уже ведутся (доступно в Chrome):


CSS Typed OM

image

(property) justifyContent?: string | `var(--${string})` | `var(--${string}, ${string})` | `var(--${string}, ${number})` | string[] | (string | `var(--${string})` | `var(--${string}, ${string})` | `var(--${string}, ${number})`)[]

Не очень понимаю зачем вообще в этом типе есть хоть что-то кроме string |, при условии что string | уже есть. И какой толк от таких стилей? Типа я не могу сюда boolean поставить? В этом суть? :)


Вот тут вот была попытка сделать типизированные стили. А в чём смысл vanilla-extract я так и не понял.

Ну в общем-то, тот подход можно переложить на vanilla-extract без особого труда. Я бы рассматривал его как высокоуровневый генератор CSS, который запускается в билдтайме и может быть связан с рантаймом. Рассматривайте его как любой препроцессор CSS, только вместо кастомного диалекта у вас тайпскрипт, а вместо плагинов — обычные функции, которые вы сами применяете по мере необходимости.

Ну т.е. всё то что мы не любим в css-in-js :) А каковы преимущества?

Ну не знаю как вы, а мне вполне нравится. Из преимуществ — максимальная гибкость, при этом никакой расплаты за неё в рантайме.

UFO just landed and posted this here

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

Я уже со счета сбился в перечислении недостатков, которые css-in-js вносит в проект, по сравнению с модулями. И тем не менее иногда встречаются проекты, использующие этот нежизнеспособный концепт, запутываясь в сотнях одинаковых с лица но кардинально разных компонентах Button / StyledButton (в лучшем случае), тоннах omitProps, смешении стилей и компонентов, ужаснейше выглядящих и не поддающихся форматированию template-вставках, постоянных "> * {}" для переписывания стилей любых чайлдов, и список этот настолько длинен, что на вот такую статью как наверху потянет, чисто перечисление...

Скорей бы это смешение стилей и логики ушло в историю.

А почему оно должно уйти? Всё связано и взаимодействует со всем. Скриптам в браузере необходимо эффективно и гибко менять как объекты в памяти, так и объекты в разметке и стилях. CSS-модули конечно могут предоставить управление стилями при помощи классов для большинства случаев, но вам не кажется, что как раз это и есть костыль?
Современные браузеры унаследовали слишком много черт того времени, когда интернетом владели веб-страницы. Для доминирующих сейчас веб-приложений по-хорошему нужны браузеры, основанные совсем на других принципах, а не DOM/CSSOM/JS. Скорее WASM+WEBGPU

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


Управление стилями при помощи добавления-удаления классов очень эффективно, так как позволяет за раз переключать сразу несколько параметров и переиспользовать эти классы в других компонентах. Схема через template literals ${isActive => isActive ? 'margin: 0; color: red;' : 'margin: 1px; color: green;'} как раз выглядит хаком, а не &.active {margin: 0; color: red;}.


В целом не могу сказать, что что-то в отдельном CSS меня не устраивает — это долго развивавшийся язык, с отличной поддержкой в IDE, многочисленными инструментами для добавления функционала через пре- и пост-процессинг, линтерами/форматтерами. Часто говорят, что css-in-jss это мощно, потому что можно написать какие угодно инструменты на js — но они и так есть для CSS, и тотальное переписывание, чтобы было так же удобно работать, как и с CSS, приведет к тому, что получится то же самое. Просто файлы не с расширением .scss, а .ts и дополнительным оверхедом по синтаксису, экспортам и торможению основной сборки. Но для этого "светлого будущего" нужно еще написать сотни инструментов, исправить тысячи багов, интегрироваться во все IDE, стандартизировать параметры и значения (а текущий TS этого не позволяет в должной мере, string и все тут). В то время как все давно уже есть, и ради маленькой фичи "не хочу писать cn(styles.class1, isActive && styles.class2), хочу писать class1({ isActive }) и логику внедрять внутрь стилей, потому что так смогу все размазать в единый слой" все эти усилия… Стоит ли оно того, или пора все же в историю?

В целом это можно долго обсуждать, но хочу заметить что "маленькая фича" в виде более удобной композиции класснеймов, это только первый предвестник тех фич, которые можно сделать, в том числе и самому, без всякой расплаты в рантайме. Вопрос здесь только в том, как скоро эти отдельные маленькие удобства накопятся до состояния, когда нативный CSS станет просто целью для компиляции, как это уже произошло с HTML. Посмотрите на тот же sprinkles, который позволяет сделать DSL для стилей, заточенный под конкретно вашу дизайн-систему.


А по поводу производительности — это очень сложный вопрос. Лично мне кажется что используемая схема "убрали типы и запустили сразу в ноде" может оказаться быстрее препроцессоров традиционных диалектов.


Про оверхед по синтаксису же… Ну, если стремиться к сходству с обычным CSS, то безусловно оверхед будет. Если же делать на его основании DSL, то уже CSS будет выглядеть вербозным.

При единых выходных файлах действительно расплата будет не в рантайме, но в билдтайме. Стилевые TS файлы нагружают парсер IDE и общий лоадер для ts-файлов, что приведет к деградации скорости сборки, поиска по проекту, подсветки типов, линтера. Конечно, работа с CSS тоже не бесплатна, но она параллелится, а тут все в большой куче получается.


Sprinkles посмотрел — это переизобретенные mixins, в которых давно реализовано то же самое:


.class { @include paddingX(10px); }
.class { display: inline; @mobile { display: block; } }
@mobile { .class { display: block; } } // предпочтительней этот вариант, чем в каждом отдельном классе прописывать адаптивное поведение
.class { padding: $gap-small; }
.class { padding: var(--gap-small); }

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


"Более удобная композиция класснеймов" — спорно, я не вижу ни одной неудобной строчки в таком варианте:


  get wrapperClassName() {
    const { className, inputConfig } = this.props;

    return cn({
      [styles.inputWrapper]: true,
      [styles.focused]: inputConfig.isFocused,
      [styles.disabled]: inputConfig.disabled,
      [styles.hasValue]: inputConfig.value !== '',
      [styles.hasErrors]: inputConfig.errors.length > 0,
      [styles.hasIcon]: Boolean(inputConfig.icon),
      [className]: Boolean(className),
    });
  }

В CSS файле все удобно разложено и красиво отформатировано. Приоритет стилей определяется порядком их следования в стилевом файле и усиленной специфичностью. В css-in-js в большинстве реализаций описание подобного превратилось бы в ад, как и стилевой файл.


По поводу вербозности — каким бы ни был лаконичным DSL, он максимум что сможет сделать — приблизиться к композиционному подходу с миксинами, при этом сохранятся все вот эти обертки типа createAtomicStyles, createAtomsFn, экспорты, нетипизированные значения без подсказок от IDE и соответственно с большой вероятностью опечаток, кастомное структурирование типа conditions, defaultCondition, properties. Все это абсолютно лишний бойлерплейт — через устоявшиеся подходы все делается удобней и не нужно никакого дополнительного обучения для разработчиков, достаточно изучить файлы с константами и миксинами при переходе в новый проект.

Стилевые TS файлы нагружают парсер IDE

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


общий лоадер для ts-файлов, что приведет к деградации скорости сборки

Как раз вот нет, учитывая что vanilla-extract использует esbuild в фоне — эти стилевые файлы обрабатываются параллельно в отдельном лоадере, тут разницы с CSS особой нет.


Разве что полезную работу производит конкретно написанный вами код, а не дженерик компилятор, обходящий AST написанного вами кода. Разница в скорости пока не ясна (надо бы попроводить замеры), но, умозрительно, есть вероятность что так окажется даже побыстрее.


Sprinkles посмотрел — это переизобретенные mixins

Есть важное отличие — sprinkles это атомарный CSS, так что результирующие стили будут состоять, условно, из пары килобайт атомарных классов, при том что вёрстка от этого вообще никак не изменится. Как вам такая оптимизация на ровном месте?


не вижу ни одной неудобной строчки в таком варианте:

Я вижу, в основном, в том, что стили которые по замыслу должны работать вместе, в самом коде CSS никак не связаны. Надеюсь, важность инкапсуляции вы отрицать не будете? Условный BEM решает эту проблему через строгие правила именования, а тут она решается бесплатно, самым органичным (чистая функция) и наименее вербозным образом.


каким бы ни был лаконичным DSL, он максимум что сможет сделать — приблизиться к композиционному подходу с миксинами

Тут опять же есть крайне важное отличие — DSL того же sprinkles абсолютно типизирован, так что вам даже не нужно изучать константы и миксины, всё находится на кончиках пальцев — вернее, в окошке автодополнения редактора.


А бойлерплейт не особо и отличается от тех самых файлов с миксинами и константами, так что тут различия не вижу.


нетипизированные значения без подсказок от IDE и соответственно с большой вероятностью опечаток

Ну это уже наследственная болезнь CSS — да и то, проверять значения в билд-тайме (а при пущем желании и в компайл-тайме, с учетом template types в TS 4.1) — это дело нескольких дополнительных строк кода.

По поводу атомарных классов — в препроцессорах можно включить extend, либо просто прогонять результирующие файлы через CSSO — сомневаюсь, что будут отличия в размерах, либо в моем варианте все же будет получше, потому что не руками оптимизируется, а автоматически:


// source
.foo { color: #ff0000; }
.bar { color: rgba(255, 0, 0, 1); }
.text { display: inline; color: red; }
.text2 { display: inline; }

// result
.bar,.foo,.text{color:red}.text,.text2{display:inline}

По скорости билда если и не будут различий, все равно создается дополнительная нагрузка на IDE и тайпчекинг — IDE включит ваши файлы в индекс и так или иначе часто будет их процессить даже при закрытых вкладках. Тайпчекинг тоже замедлится и в целом непонятно, зачем он — разве что для нахождения несуществующих классов, чтобы было удобней рефакторить. Единственный плюс, пожалуй.


То, что все эти кастомные структуры будут в автоподсказках не значит, что их не требуется изучать и что они вообще нужны.


Мы очень сузили в обсуждении темы для сравнения, надо было видимо написать пятисотстрочник с недостатками css-in-js, чтобы было больше материала) А по обсуждаемым пунктам — да, ваш вариант где-то на горизонте видит экосистему CSS и изо всех сил бежит к ней, в чем-то сравниваясь по скорости, в чем-то по удобству. Но чтобы догнать нужны совсем другие усилия и намного более основательные причины, чем "можно тайпчекать наличие классов и писать js-логику прямо в стилях", при этом с кучей недостатков.


Чуть не забыл сказать про инкапсуляцию:


.class {
  .class2 {}
}

Пожалуйста — nested структура, внутренние классы работают только если заключены в обертку .class. Структура вложенности для удобства должна отражать html-структуру разметки, чтобы при изменении стилей можно было практически не лезть в файлы с разметкой. Добавляем модули = изоляция, инкапсуляция. И ни одного createAtomicStyles, createAtomsFn, export и т.п.

UFO just landed and posted this here
По моему, вся тема CSS-in-JS — это идеальное олицетворение пословицы про молоток и гвозди.
А то что в статье — это не венец, это апофеоз.
Я написал ниже аналогичный комент про молоток и гвозди еще не видя ваш коммент. Совпадение какое :)

Я вот наелся этого - аж целый фреймворк был на css-in-js. И вернулся в css modules с sass. По двум причинам:

  • офигеешь разбираться что сам навернул

  • тупо нельзя скопировать в код, то что накрутил в инспекторе

Каменты прям вдохнули жизненной уверенности, что не все так плохо на этой планетке)

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

Он займётся мозгоипанием своим ООП всех до кого дотянется и скорбно будет "так-и-быть-соглашаться" с "этими-вашими-костылями" ибо дедлайн а "как-надо", вы мартышки нивтащили, сколько я вам ни объяснял!

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

Просто те, кому всё понравилось, молча добавили в закладки и поставили звезду на гитхабе ;) И таковых в два раза больше чем комментов.


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

UFO just landed and posted this here

Неожиданный сайд-эффект: по запросу в Яндексе "какашата" данная статья вылезает на 3 позиции. Может, эти лиды ставят звезды на гитхабе и в закладки сохраняют…


P.S. Извини автор за такие шутки, но видеть в проектах css-in-js это такая боль. Почему-то тысячи стилевых багов мне встречались исключительно в таких проектах.

У меня ощущение последние несколько лет, что мы (программисты, любители типизаций и т. д.), будучи молотком, во всем видим гвоздь. Вот в данном случае мы пытаемся типизировать то, парадигма чего лежит полностью за пределами области программирования. Можно попытаться типизировать типографию, например, но что мы, собственно этим решим? Не тупиковый ли это путь? Может решения лежат в совершенно другом направлении (если вообще есть проблема)?

P.S. Только что увидел аналогичный комент про «молоток и гвозди» выше.

Какое же безумие творится на фронте.

Вы наверное не видели Stitches. Это лучший опыт использования CSS-In-JS, и банлд всего ~5кб.

Кстати, теперь в vanilla-extract есть вдохновленные stitches рецепты!

Подскажите, а есть ли возможность генерировать Critical CSS при SSR? Или он только полный css-файл генерит со всеми стилями?

Пока вроде до этого не дошло, но в целом думаю возможно.

UFO just landed and posted this here

Ну и ещё оно полностью статическое, js нужен только для выбора классов. Zero-runtime!

Sign up to leave a comment.

Articles

Change theme settings