Pull to refresh

Comments 98

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

В Angular вопрос изоляции даже не стоит, там это идет из коробки.
Даже в полностью нативном будущем пока не предусмотрено возможности синхронизировать значения в JS с CSS-переменные. Например, вы захотите задать ширину блоку в CSS, а потом использовать это значение в JS, например, чтобы не рендерить часть контента. В предложенном в статье подходе можно легко вынести это значение в константу и переиспользовать.
UFO just landed and posted this here

Допустим, с этим можно что-то сделать (хотя и тут есть нюансы с ShadowDOM).


А в обратную сторону JS->CSS как сделать?

Так же как с любыми другими css свойствами, через style.

Но так не выйдет поменять переменную, меняется конкретный стиль одного элемента.
Переменные наследуются по иерархии элементов.
Мы у себя пару лет назад попробовали CSS-in-JS — запилили библиотеку компонент и несколько приложений.

Проблем там много, например что:
— потребители CSS-in-JS компонент обязаны использовать ту же CSS-in-JS библиотеку
— подход «поправил в devtools — скопировал в код» — не пашет, из-за разного синтаксиса
— постоянный WTF: нельзя просто взять человека, знающего CSS, и посадить верстать
— hover/focus — или JS-кой, или хитрые хаки чтобы вынуть селектор парента себе, и опять же сделать каскадинг от parent:hover

Но главная проблема, внезапно, это что каскадить, блин, удобно. Возможность там-сям немного подхачить каскадингом чужой компонент — сильно упрощает и удешевляет разработку. Когда «вот тут мне надо в кнопке жирный текст» оборачивается целой итерацией типа: «согласовать с дизайном -> согласовать новую prop -> патч в библиотеку -> дождаться версии -> обновить npm-пакет в проекте» — это может и супер-правильно, но оооочень долго и дорого.

Сейчас мы на CSS Modules, и все равно мы на ключевые элементы добавляем :global()-селекторы — чтобы была возможность чуть что подхачить каскадингом.
Если дорого — то, значит, не так уж и правильно. CSS — это слой декларативной стилизации, специальный DSL, предназначенный для эффективного управления стилями, и каскады, действительно, одна из самых центральных парадигм этого языка (она даже в названии отражена первой буквой), позволяющая строить наиболее компактные и понятные описания. Кажется, что замена этих возможностей пусть даже максимально удобной библиотекой пробрасывания всей этой «стилизационной семантики» через JS — это фронт войны между верстальщиками и программистами. И лучше оставить зону отвественности стилизации приложения верстальщикам и их языку выражения, даже если роль этого верстальщика приходится выполнять программисту, разговаривающему на JS. Просто семантика CSS для этого удобнее, и реализовывая все её возможности на JS мы всё равно рано или поздно переизобретём аналогичный DSL, только с другим синтаксисом.

Я недавно закончил работать над проектом с использованием styled-components, мне понравилось, буду использовать эту библиотеку еще.


потребители CSS-in-JS компонент обязаны использовать ту же CSS-in-JS библиотеку

Необязательно. Вы экспортируете компоненты, использование CSS-in-JS это внутренняя деталь реализации. Потребители могут писать свои компоненты как хотят. Например, material-ui использует JSS, но в своей документации они об этом не пишут, для работы с их компонентами это знать необязательно.


подход «поправил в devtools — скопировал в код» — не пашет, из-за разного синтаксиса

Со styled-components работает, потому что они используют синтаксис CSS, заключенный в template strings. А вообще, я этим нечасто пользуюсь, пишу сразу в редакторе, страница перезагружается сама через live reload.


постоянный WTF: нельзя просто взять человека, знающего CSS, и посадить верстать

Постоянное обучение всегда было частью занятия программированием. Нужно учиться новым технологиям в любом случае.


hover/focus — или JS-кой, или хитрые хаки чтобы вынуть селектор парента себе, и опять же сделать каскадинг от parent:hover

В styled-components делается вот так


const Button = styled.button`
   background: white;
   &:hover {
     background: blue;
   }
`;

Каскад тоже возможен:


const Panel = styled.div`
  /* какие-то стили */
`;

const Button = styled.button`
   background: white;
   ${Panel}:hover & {
     background: blue;
   }
`;

Нормальное CSS-in-JS решение никак не ограничивает использование фишек CSS. Только вдобавок вы получаете хорошую инкапсуляцию и удобную интеграцию с Javascript. Я еще использую Typescript, поэтому эти стили оказываются еще и статически типизированы, то есть я не смогу использовать Panel в качестве селектора, если он не является правильным значением. Аналогично, неиспользуемые компоненты тоже подсвечиваются и их намного легче удалять, чем в ситуации с отдельным CSS-файлом.

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


For the sake of simplicity, we expose our styling solution to users. You can use it, but you don't have to.
— потребители CSS-in-JS компонент обязаны использовать ту же CSS-in-JS библиотеку
— подход «поправил в devtools — скопировал в код» — не пашет, из-за разного синтаксиса

Совсем не обязательно, все подобные библиотеки поддерживают как нотацию JSS, так и чистый css через тегированные шаблоны.
Из личного опыта: У меня есть два проекта: один на тегированных шаблонах, второй на JSS. Могу сказать, что шаблоны удобнее, да. Но не из-за возможности копирования из девтулз.

— постоянный WTF: нельзя просто взять человека, знающего CSS, и посадить верстать

Ну в эпоху толстых js-приложений и JSX, человек, знающий только CSS — в любом случае должен будет хоть немного понимать JS.
— hover/focus — или JS-кой, или хитрые хаки чтобы вынуть селектор парента себе, и опять же сделать каскадинг от parent:hover

Даже без CSS-in-JS hover часто приходится костылить через тот же `setState`. Но при этом обычный :hover в тех же styled-components работает вполне легко: и для html-тегов, и для других стилизованных компонент
CSS-in-JS дает возможность автоматизировать генерацию уникальных селекторов и идентификаторов.

Серьезно? Объявить в «главные фичи» примитивный момент, с которым спокойно справятся devtools на этапе билда? Это смешно.

Главное в CiJ — это рантайм, разумеется. Можно творить стили прямо в рантайме, со статикой вы такого размаха близко не достигните даже с var(). Вот это — действительно принципиальный момент. Однако за его наличие вы далее начинаете платить:
1) У вас нет каскадности и перекрываемости (кроме той, которую вы предусмотрели заранее в самом коде);
2) У вас нет модификаторов селекторов, или же есть велосипед / посторонняя библиотека, которая их эмулирует. Со всеми вытекающими из этого потенциальными проблемами в будущем;
3) Любой, кто захочет модифицировать вашу стилизацию, будет обязан использовать то же решение для CiJ, что и у вас. Или же собирать грабли;
4) Это всё (любые добавки поверх простого инлайна, работающего из коробки) работает гораздо медленнее обычного голого css, ибо представляет из себя эмуляцию поддержки css, написанную в яваскрипте.

И вишенка на торте: даже если у вас CiJ нет — это тем не менее не значит, что вам кто-то запретил пользоваться инлайном в местах, где это очень необходимо (где вам надо рантаймово стиль сгенерить, например).
У вас нет каскадности и перекрываемости (кроме той, которую вы предусмотрели заранее в самом коде);

Непонятно, как это попало в список недостатков. В этом же и есть изначальный смысл – предохранить стили от нечаянного определения, чтобы случайный класс panel в коде одного модуля не разломал стили в совсем другом.


Любой, кто захочет модифицировать вашу стилизацию, будет обязан использовать то же решение для CiJ

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


У вас нет модификаторов селекторов, или же есть велосипед / посторонняя библиотека, которая их эмулирует

Я так понимаю, речь про hover/focus? Поддержка синтаксиса &:hover есть во всех популярных библиотеках, что с этим не так, чего не хватает?


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

Большая часть CSS будет сгенерирована при старте страницы (или вообще вынесено в build-time, если есть желание). В процессе работы страницы браузер будет работать с обычным ванильным CSS. Откуда взялся вывод про "гораздо медленнее", да еще и курсивом?

В этом же и есть изначальный смысл – предохранить стили от нечаянного определения, чтобы случайный класс panel в коде одного модуля не разломал стили в совсем другом.

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

Мы закрываемся от непреднамеренных модификаций, и открываем API для намеренных.

Вы пишете так, как будто голый css этого «api» не имеет. Меж тем это очевидно не так, и API вида «положи еще один файлик css» по простоте уделывает любые варианты CiJ.

Поддержка синтаксиса &:hover есть во всех популярных библиотеках, что с этим не так, чего не хватает?

Тем, что очень многие в гробу видели эти ваши популярные библиотеки? Скажите, какой TTL вашего кода? Что будет с вашими «популярными библиотеками» через 10 лет? А если вам ваш код всё еще надо поддерживать? А если ваш код даже и через 10 лет обладает бизнес-ценностью, и лучше бы ему быть открытым для модификаций?

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

Большая часть CSS будет сгенерирована при старте страницы (или вообще вынесено в build-time, если есть желание).

Это зависит от конкретных решений и библиотек. Далеко не весь CiJ мегаоптимизирован по быстродействию.
И в любом случае, быстродействие вы исключительно теряете. Другое дело, что можете потерять не так уж и много. Но тот, у кого сразу обычный ванильный css с вкраплениями инлайна — ничего не теряет.
Что будет с вашими «популярными библиотеками» через 10 лет? А если вам ваш код всё еще надо поддерживать?

Лучше иметь хорошо задокументированную, протестированную, но неподдерживаемую библиотеку, которую в свое время (10 лет назад) поддерживало много программистов (а не максимум 2-4, которое было в вашей команде), с возможностью форкнуть исходный код библиотеки и поправить что-либо, или даже переехать с нее (ведь документация и исходный код на руках), чем самописный велосипед, который на 100% окажется менее задокументированным, менее продуманным (вам еще и бизнес-логику писать), и не факт, что будущие члены этой команды (или другая команда вовсе) поймут основные посылы этого велосипеда.

Неплохой пример из первых рук, как говорится:
Была команда, которая угорала по ФП. Ну… точнее по функциональному стилю в JS. Они выбрали как основу для своего реакт-приложения библиотеку recompose. Написали проект, он почти что вышел из альфа-версии, а тут создатель recompose такой и пишет: Спасибо всем, но я не буду больше развивать библиотеку, может быть фиксить баги буду, используйте React.Hooks теперь.
Ничего страшного не произошло, библиотека по-прежнем работает, а те же самые Хуки могут через 10 лет повторить историю миксинов, или React повторит историю jQuery. Кто знает.
Лучше иметь хорошо задокументированную, протестированную, но неподдерживаемую библиотеку, которую в свое время (10 лет назад) поддерживало много программистов (а не максимум 2-4, которое было в вашей команде)

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

И «документация» вида «спроси Васю из соседнего отдела, он это писал» — легко может оказаться более полноценной, чем многокилобайтный readme.md очередной чудо-библиотеки вместе с её кодом или даже гитхаб-вики из сотни страниц.
Это даже не говоря о том, что документация, которая лежит не у вас — штука интересная. Вам рассказать историю, как RxJS в один прекрасный день залил новую (убогую) документацию, безвозвратно выкинув старую, и поставив многих разработчиков в весьма… гхм… положение? Нет, потом они это конечно поправили всё. Потом.

чем самописный велосипед, который на 100% окажется менее задокументированным, менее продуманным (вам еще и бизнес-логику писать), и не факт, что будущие члены этой команды (или другая команда вовсе) поймут основные посылы этого велосипеда.

И этой вашей части тезиса тоже следует быть в разы менее безапелляционной, чем вы написали. Во-первых велосипед будет решать ваши проблемы, а не сборную солянку из проблем 100 000 пользователей в 10 000 разных сценариев. Возможно, 9 999 сценариев вам просто нафиг не сдались, а возможно и что авторы библиотеки, раздавленные необходимостью поддерживать всё и вся — сделали множество компромиссных решений (по производительности, качеству кода, связности, и тэ дэ), в то время как в вашем велосипеде с этим всё гораздо лучше.
Во-вторых — можно долго теоретизировать про документацию, однако реальность очень проста: переносить знания внутри конторы — намного проще, чем вне её, даже в чудном мире опенсорса и тому подобного. Разумеется, если у конторы bus factor нормальный, а не единица. Внутри конторы знания переносятся вместе с ценным контекстом (бизнес-процессами), а внешние знания каждый программист будет потом натягивать на контекст сам, и не факт, что хорошо натянет.
Они выбрали как основу для своего реакт-приложения библиотеку recompose. Написали проект, он почти что вышел из альфа-версии, а тут создатель recompose такой и пишет: Спасибо всем, но я не буду больше развивать библиотеку, может быть фиксить баги буду, используйте React.Hooks теперь.
Ничего страшного не произошло, библиотека по-прежнем работает, а те же самые Хуки могут через 10 лет повторить историю миксинов, или React повторит историю jQuery.

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

А вот когда дело доходит до сложных вещей — там уже другая история. С d3.js вы так просто не слезете (хотя вот конкретно за будущее d3.js я совершенно не волнуюсь) — она специфична и требует определенного подхода, и при этом внутренне существенно сложна. Или тот же не к ночи будь помянутый ангуляр.

Лично я придерживаюсь простого критерия — если я могу взять, и вот прям сходу сесть и переписать чужую либу, в том плане, что нет ни больших вопросов относительно того, что эта либа делает и как (за исключением технических мелочей, конечно), ни больших объемов кода — то такую либу можно включать в dependencies без особых вопросов и совещаний. А если не выполняется первая или вторая часть условия, или обе сразу — тут уже надо присматриваться куда тщательнее.

Только не recompose, а recompact. Вторая позиционировала себя как оптимизированная замена первой. Теперь появился другой путь сделать лучше и автор принял его. Первая нормально живет.

Вы пишете так, как будто голый css этого «api» не имеет. Меж тем это очевидно не так, и API вида «положи еще один файлик css» по простоте уделывает любые варианты CiJ.

Открыть все стили для переопределения – это не API. Нужно разделять публичную часть, открытую для переопределения, и приватную. В ванильном CSS такого нет.


Что будет с вашими «популярными библиотеками» через 10 лет?

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


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

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


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

Не факт что теряете. В классическом подходе CSS из-за отсутствия статически анализируемых связей часто встречается ситуация "лучше оставим эти стили, хрен его знает где они используются, но пусть будут, от греха подальше". В случае styled-components + typescript они просто подсветятся в IDE как неиспользуемые, и легко выпиливаются встроенным в редактор инструментом рефакторинга.

Открыть все стили для переопределения – это не API.

А что же это? ^_^

Примерно такое же отношение было к первым версиям React, но ничего плохого не случилось

А с ангуляром случилось. Что дальше-то? Вам пока что везло, только и всего.

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

Ну я не буду говорить, что 2 года — это исчезающе мало, я думаю я это выше уже донес. Но если вот сказать про styled-components, то я очень ей заинтересовался, дочитал до
It looks like there are several instances of «styled-components» initialized in this application. This may cause dynamic styles not rendering properly, errors happening during rehydration process and makes you application bigger without a good reason.

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

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

CiJ не является панацеей для придания css модульности. CSS Modules справятся с этим нисколько не хуже (и только во время билда), да и вообще, как я писал выше — это очень простая проблема, которую даже убогой самопиской можно решить.

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

Если бардак не разводить — то его и не будет.
Открыть все стили для переопределения – это не API.
А что же это? ^_^

С точки зрения open–closed principle (буква О из SOLID) у компонента должна быть публичная часть и приватная имплементация. На примере стилей какой-нибудь кнопки, изменение цвета – это публичная часть, а позиционирование иконки и выравнивание текста – это приватная. Объявлять все стили доступными для переопределения чревато проблемами.


А с ангуляром случилось. Что дальше-то? Вам пока что везло, только и всего.

Пессимист всегда видит наполовину пустой стакан, а библиотеки – обреченными на провал. Не думаю, что я смогу вас убедить, поэтому на этой ноте этот вопрос и оставим.


CSS Modules справятся с этим нисколько не хуже

CSS-modules не предоставляют интеграцию с Javascript. Как вы будете решать задачу переиспользования брейкпойнтов из media-queries в JS?


Если бардак не разводить — то его и не будет.

А если разрабатывать без багов, то и тесты можно не писать. Но почему-то их все-таки пишут.

На примере стилей какой-нибудь кнопки, изменение цвета – это публичная часть, а позиционирование иконки и выравнивание текста – это приватная.

Я всего лишь писал о том, что не стоит кидаться громкими словами типа «это не API». Еще какое API. От того, что там из коробки нет вашего O из SOLID — оно «не API» не становится.

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

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

CSS-modules не предоставляют интеграцию с Javascript. Как вы будете решать задачу переиспользования брейкпойнтов из meda-queries в JS?

Ничего не понял. А в чём тут проблема-то?
А кто-то другой вас посылает матерными словами и считает не очень умным

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


У вас что, код кнопки сломается, если текст будет по-другому выровнен

В зависимости от реализации выравнивания (либо через float:left/right, либо через flexbox) переопределение может сломаться, и текст с иконкой разъедется на две строки, например. Если разрешить пользователям трогать эти стили – то это означает почти полную заморозку CSS между мажорными релизами. Как при этом разрабатывать новые фичи – непонятно.


Но в подавляющем большинстве ситуаций таки никто не умрёт, если приватным оно не будет.

А вы точно работаете в энтерпрайзе? По закону Мерфи, если проект достаточно большой, это все-таки произойдет.



Как вы будете решать задачу переиспользования брейкпойнтов из media-queries в JS?

Ничего не понял. А в чём тут проблема-то?

Есть CSS


@media(max-width: 768px) {
   // стили для мобильных
}

И JS


if(window.innerWidth < 768) {
   // логика для мобильных
}

Как сделать так, чтобы это число 768 забиралось из одной константы?

Я бы очень не рекомендовал использовать media-breakpoints, так как они меняют стили в зависимости от размера окна браузера, а не размера контейнера, в котором находится компонент. В качестве примера, как делать стоит, могу привести это приложение. Поресайзите окно, и обратите внимание как содержимое правой панели адаптируется к доступному пространству при закрытии/открытии левой.
Я в курсе об этом, есть еще вот такой пример: philipwalton.github.io/responsive-components

В любом случае, надо как-то переиспользовать значения между CSS и JS, как бы там это не реализовывалось.
css-variables элементарно читаются/пишутся через JS и используются в CSS.

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

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

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

У вас есть брейкпоинт 423 и 424 меняется
[mol_app_supplies_position_row] {
flex-wrap: wrap;
}
то есть, то нет, но это не на уровне css. Отладчик не показывает перекрытия. Чем был оправдан этот брейкпоинт?

Я не очень понял о чём вы. Флексбокс сам выстраивает раскладку в зависимости от размеров контейнера и размера контента.

И ничего описанного вами там нет. Возможно вы что-то отредактировали случайно?
Ага. Не то смотрел. Вопрос. Почему у вас в таблице блоки всхлопываются синхронно? В них же текст разного состава, блоки изолированы, flex-wrap должен срабатывать не одновременно. А вся таблица меняется, как будто я брейкпоит сделал на 423px.
Тут суть в том, что когда все они выстраиваются в одну колонку из-за flex, заголовки, например, нужно сделать по центру. Тогда без брейкпоинтов все равно не обойтись.
Зачем? Чтобы пользователю было сложнее их читать?
да не важно что, размер шрифта, его цвет, жирность, его padding-bottom, показ значка или доп кнопки.
1. Вы сейчас подгоняете требования под решение.
2. В любом случае нужно не на размер экрана ориентироваться, а на размер контейнера, что сейчас возможно только скриптом.
Я говорю об обычной усредненной задаче, когда при уменьшении размеров экрана шапка состоящая из 4 элементов лого | телефон | емейл | логин превращается в
лого| телефон над емейлом | меню

скриптом можно понятно что делать, вопрос в производительности и дерганиях.
Обычная задача превращать логин в меню?

Да нет там проблем с производительностью и дёрганьем.
Можно не превращать. Все равно нужен брейкпоинт, где необходимо что-то прятать или менять положение какого то элемента, когда визуально при уменьшении окна это начинает плохо выглядеть.
Опять вы подменяете контейнер окном…
Разве контейнер, занимающий всю ширину экрана самостоятельно не равен окну?
Сейчас занимает. Завтра добавили сайдбар и всё поехало. После завтра решили сделать превью приложения в конфигураторе, а оно не влезает. И тд.
это не снимает вопроса управлениями свойствами элементов внутри контейнера, в зависимости от его ширины. К примеру, мне нужно border-bottom:1px solid black когда сработал flex-wrap и все дочерние элементы остались одни в ряду
Ну так, если это действительно необходимо — нет проблемы сделать это скриптом. Но не media-query.
Я сам последнее время перестал привязываться к конкретным брейкпоинтам. Брал горизонтальные блоки сайта и уже, выставлял разные свойства элементам внутри, когда уже визуально шло что-то не так при изменении окна. Хидер с отдельными брейкпоиинтами, боди и тп. При желании хоть 10 штук каждому. Это когда идешь не Mobile-first, а наоборот. Думал будет тьма брейкпоинтов… а нифига, за счет того, что сам выбираешь каждый раз эту точку, получается меньше корректировок нужно закладывать наперед, подгоняя симпатичность около переходных состояний возле жестких брейкпоинтов.

Меня вот это «что-то не то» настораживает в плане события. С media деваться некуда, а с контейнерами как?

«Что-то не то» выражаться может в следующих событиях

1) изменение размера контейнера
Тут все понятно, как с media, случилось с содержимым «что-то не то». Навешиваем корректирующий класс на требуемом брейкпоинте.

Просто на событии window.onresize плясать от размера контейнера?

2) срабатывания flex-wrap
Три пункта. Последний пункт из трех слетел на второй ряд и растянулся по максималке. Хочу убрать у него padding-top, а у первый двух padding-bottom.
Как подцепится? Привязываться к брейкпоинтам контейнера, забить на возможность flex-wrap рассчитывать их на основе контента — плохая идея.
Приходится привязываться к желаемому элементу с событие на изменение его стартовых значений?

Просто на событии window.onresize плясать от размера контейнера?

requestAnimationFrame + getBoundingClientRect


Хочу убрать у него padding-top, а у первый двух padding-bottom.

Чего-то странного вы хотите. Возможно вам нужен просто отрицательный margin-bottom у элементов и положительный padding-bottom у контейнера?

А как быть с разным размером шрифта без брейкпоинтов?
Я такой пакет использую
www.npmjs.com/package/rfs

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

Есть просто минимальный размер шрифта, который комфортно читать только из-за его размера. Это верно. Но это не означает, что увеличение его размера ведет к ухудшению читаемости.

Ситуация: есть стили оформления контента h1 h2 и body для экрана монитора. Здесь можно значительно крупнее задавать h1 по отношению к h2, а h2 по отношению к body. Но на мобильном экране нет необходимости в таком разбросе пропорций.

На мобильном эффективнее когда h2 и h1 может отличаться от body на 1.2 и 1.8 соответственно (к примеру), тогда как на 24 дюймовом можно 1.6 и 2.1.

В общем, картинка из примера это показывает.
image

Комфорт остается, поскольку никто не опускается ниже «госта» читаемости в ~16px — а пространство заполняется эффективнее. Можно возразить, и сказать ну так и используй самые мелкие пропорции стилей для монитора тоже, но нет — допустим это не админка, а промо страница и там это не симпатично.
Разница в 2 пикселя слишком маленькая, что создаст сложности с пониманием где какой уровень заголовка на маленьком экране. Если же отличие не только в размере, то и от увеличения размера на 2 пикселя стоит отказаться — оставив этот другой фактор.

Если по дизайну надо заполнить пространство текстом, наплевав на удобочитаемость (читать огромные буквы тоже сложно), то тут достаточно указать размер в vmin и не выдумывать брейкпоинтов.

Ну и дизайн, предполагающий огромные буквы и пляшущий как попало вертикальный ритм — такое себе зрелище.
Почти на всех гарнитурах есть такой порог в 1 пиксель когда прыгает толщина линий. Например PT Sans.
с 21px на 20px происходит скачек в толщине линий шрифта. h1 и h2


https://habrastorage.org/webt/75/em/hw/75emhwsie2bllyz_0xcmkevj9gw.png
Рендер шрифтов только фотошоповский.

И тогда они неплохо различимы так как еще и цвет с маркером добавляются.
Верно, фактора размера шрифта гуляющего + 2px для понимания уровней заголовков маловато. Но опять же, как я без брейкпоитов задам новое оформление? Тот же маркер в виде цветного квадрата слева перед заголовком. Или я захочу border-bottom где то увидеть.

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

Если у background-img есть свойство cover, что почти решило проблему масштабирования (но все равно проблема art direction problem решается подстановкой другого изображения) то у текста, который лежит поверх таких бекграундов инструментов корректировки, кроме условий в виде брейкпоинов нет.

Что касается вертикального ритма… штука эта не уловимая. Если редактор текста образмляет абзацы в

то хорошо, можно регулировать высоту отступов, а если просто вставляет
… вобщем это немного другое уже.

фактора размера шрифта гуляющего + 2px для понимания уровней заголовков маловато. Но опять же, как я без брейкпоитов задам новое оформление?

Почему бы не оставить его единообразным независимо от размера экрана?


Что касается вертикального ритма… штука эта не уловимая.

В глаза не бросается, но когда он нарушен — складывается ощущение неопрятности.

Как сделать так, чтобы это число 768 забиралось из одной константы?

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


Мне это не очень нравиться, потому что компонент размазан по файлам, лучше уж компонент в отдельный файл.
Это вкусовщина. Я сам не большой сторонник «размазывания», когда для того, чтоб открыть в IDE какой-то большой связный кусок кода — надо открыть 10+ файлов. Но для достаточно специальных задач (а медиа квери — специальная задача) это более чем нормально. Ну а после билда так и вообще всё раскладывается как душе угодно.
В зависимости от реализации выравнивания (либо через float:left/right, либо через flexbox) переопределение может сломаться, и текст с иконкой разъедется на две строки, например.

А кто вам сказал, что это не то, чего хочет пользователь вашей либы с кнопками?

Если разрешить пользователям трогать эти стили – то это означает почти полную заморозку CSS между мажорными релизами.

Или, если не использовать жесткое связывание цсс с кодом — это означает «business as usual» — вы пишете компоненты приемлемо стилизованные «из коробки», да следите за максимальной адекватностью DOM и назначением опорных классов. А пользователи вашей либы берут, и через опорные классы раскрашивают это дальше как им надо. Все довольны.

А вы точно работаете в энтерпрайзе? По закону Мерфи, если проект достаточно большой, это все-таки произойдет.

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

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


А пользователи вашей либы берут, и через опорные классы раскрашивают это дальше как им надо. Все довольны.

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

То, как компонент выглядит — публичный интерфейс по определению. Как и любые другие побочные эффекты. Любые изменения его стилей, насколько бы минорными они ни казались разработчику, — это всегда ломающие изменения. Именно потому, что стили меняются не просто так, а чтобы так или иначе изменить представление. Так что любое обновление может привести ко кривому отображению, независимо от того, патчился этот компонент или нет. Более того, если он сильно кастомизирован, то вероятность, что что-то поедет ниже, так как фактических изменений при обновлении произойдёт меньше. Но она в любом случае есть, поэтому решаться этот вопрос должен в корне — автоматизированным визуальным регрессионным тестированием. А не надеждой, что новые стили впишутся в существующий дизайн.
Соглашусь, значительные визуальные изменения в минорных релизах не делают, но замораживать стили целиком тоже не выйдет, новые фичи тоже катить как-то надо.

Визуальные регрессионные тесты тоже не выход. Может быть бесчисленное множество вариантов переопределения, протестировать их все в разных комбинациях займет бесконечность. А вот если ограничить переопределения конкретными местами, то это вполне сработает.
UFO just landed and posted this here
<коммент был не туда>
Когда-нибудь я доживу до того дня, когда хабракоммент в последнюю ветку комментариев не будет путаться с новым комментом в корень.

Наличие !important при двух классах на элементе это не проблема CSS, а проблема отсутствия методологии, грамотной архитектуры и разграничения обязанностей у селекторов. Единственное исключение это display none, который всегда должен перезаписывать свойства компонента. Если каскад был основной причиной выбора CSS in JS то это как минимум странно.
Несомненно, CSS in JS имеет своё применение и сильные стороны. Можно ли на нём сделать небольшое приложение? Запросто. Хотел бы я его использовать на большом проекте? Да ни в раз.

Цитата из статьи:


Кодовая база Facebook содержит тысячи использований !important, даже несмотря на то, что код писался квалифицированными программистами с использованием принципов SOLID

Методология все-таки была. Только вот в ванильном CSS сложно предусмотреть все варианты.

Думаю, что нужно спросить у Фейсбука почему так, если у них с самого начала была какая-то методология и они её придерживались. Методология всё же не исключает ошибок разработчика или незнания инструмента. Сделаю глупое предположение что там новый код вперемешку с легаси и нет код ревью для CSS.
БЭМ, CSS переменные и грамотная архитектура решают все проблемы с конфликтами свойств и позволяют вообще отказаться от зависимости на порядок следования правил вне компонентов. Более того, они полностью решают проблему увеличения специфичности селекторов и про всякие !important можно забыть. Другое дело что не каждый хочет в это глубоко погружаться, особенно если человек пришёл во фронтенд не из вёрстки. Вот даже интересно есть ли у фейсбука вопросы по вёрстке в интервью, как например у Яндекса.
Тут более общая проблема: вебпак (по крайней мере 4-й, может в пятом это победят, они ведь грозятся сделать first-class поддержку css) не гарантирует порядок включения css. А если вы победите вебпак или будете использовать свой умный сборщик (опасливо покосился на vintage), то вы всё равно получите это, так как ваши подгружаемые файлы могут подгружаться в любом порядке. Соответственно у вас два селектора с одинаковыми весами, и они будут по-разному работать, в зависимости от того пути, по которому пользователь пришёл к вашему компоненту (путь определяет дозагрузку частей приложения).

У меня эта проблема решена на архитектурном уровне с помощью БЭМ и переменных. Порядок подключения файлов не имеет никакого значения и я действительно не знаю в каком порядке вебпак мне это собирает, потому что я отвязан от этой зависимости. Я управляю порядком только на верхнем уровне архитектуры: глобальные стили, стили компонентов и стили страницы. Более того, специфичность селекторов тоже не имеет никакого значения, всё работает через переменные. Без переменных решить эту проблему невозможно, поэтому если нужна first class поддержка IE нужно искать другие решения типа того же CSS in JS.

В БЭМ есть понятие микса, когда на один HTML элемент навешивется несколько классов от разных блоков. Как в этой ситуации решить, что в итоге должно примениться?

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

Вот пример из статьи по ссылке. Есть menu__item, а есть link, которые висят на одном элементе. Цвет ссылок в меню должен быть другой, а остальные стили (переопределение focus outline, например) применяются как есть. Получается что-то вот такое


.link {
  color: blue;
  // другие стили
}

.menu__item {
   color: black;
}

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


Какие могут быть решения?


  1. Использовать !important для .menu__item. Выглядит как хак
  2. Написать второй селектор как .menu__link.link, но это уже не тру-БЭМ.
  3. Вынести стили ссылки в миксин, использовать его для .menu__link вместо миксования классов. Устанешь на каждый случай свой миксин создавать.
  4. Починить сборщик, получить детерменированную последовательность стилей. Затратно по времени.
  5. Использовать CSS-in-JS

const Link = styled.a`
  color: blue;
  // другие стили
`;

const MenuItem = styled(Link)`
  color: black;
`;

Получается просто и предсказуемо.

Ну и стандартный вопрос, на который я обычно не получаю ответа. Как кастомизировать стили элемента элемента не превращая блок элемента в звездолёт со 100500 свойствами?

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


.menu
  .menu__item.link.link--menu-item

.menu__item
{
  margin-left: 20px;
}

.link
{
  color: var(--link--color, blue);
}

.link--menu-item
{
  --link--color: black;
}

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


@media (--mq-not-mobile)
{
  .mq-mobile-only
  {
    display: none !important;
  }
}

Так как display: none никогда не нужно перезаписывать здесь вполне допустимо использование !important.


Но как быть если хочется вынести раскладку или презентацию в отдельный класс?


Очень просто: миксовать классы только с разной ответственностью. Если нужно добавить единое скругление углов к компоненту, то этот компонент не должен отвечать за свойство border-radius. Тоже самое с отступами, фоном, позиционированием и так далее. Компонент должен быть либо максимально открыт к изменениям, либо реализовывать всё тоже самое через модификаторы.


Как понять что можно добавить на компонент, а что нет?


Очень просто: сначала добавить его в разметку и посмотреть какие свойства он определяет. Ни одно из этих свойств родительский компонент переопределять не должен, а вместо этого нужно реализовать отдельный модификатор для дочернего компонента.


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


.button
{
  font-size: var(--block-font-size, var(--button--font-size, 14px));
}

.button--big
{
  --button--font-size: 20px;
}

.reply-form
{
  --block-font-size: 16px; /* Применится 16px для button, даже если у кнопки стоит модификатор button--big */
}
В статье уже рассматривались проблемы подобного решения с разбиением на зоны ответственности классов: такой подход сложно контролируется. Как вы защититесь от ситуации, когда вы ушли в отпуск, а когда вернулись, коллеги уже намешали представление с раскладкой в общих классах?
Это уже совсем-совсем другая тема.

Но если вы хотите обсудить как следить за тем чтобы оно всё не перемешалось то здесь множество работающих вариантов, люди ведь как-то выучили БЭМ и не забывают как он работает.
Есть код ревью, есть внутренняя документация, есть обучение внутри команды, можно банально не допускать людей до вёрстки пока они не освоили подходы внутри проекта.
Оно не сразу даётся в первое время, особенно когда хочется всё сделать на каскаде. Но как только привыкаешь к этим паттернам больше вообще не задумываешься где какие свойства прописать.

Я не совсем понял о каких сложностях контроля можно говорить в этом случае. Если где-то опечатка то она сразу проявится в интерфейсе, вы ведь проверяете финальный результат правок в вёрстке? Зависимостей по селекторам и порядку подключения файлов нет, поэтому и тестировать это не нужно совсем.

Каждый компонент получается полностью изолированным от другого. Так что если вы решите поменять цвет ссылок внутри любого списка вам не нужно будет идти в каждый компонент, который реализует какой-то список. Достаточно лишь поменять значение у модификатора ссылки. Список не знает как устроены ссылки, а ссылкам не важно куда они вложены и наоборот. Для меня это самая удобная система на данный момент, потому что сильной связанности между компонентами нет. Исключение это публичный интерфейс компонента, как выше в примере с block-font-size. Такие вещи должны быть унифицированы и использоваться по минимуму. Такой же интерфейс можно использовать для изменения стиля через :hover и другие состояния в случаях когда у элемента уже преднастроено свойство, которое нужно изменить. Например для заливки SVG иконок по наведению на родителя.
люди ведь как-то выучили БЭМ и не забывают как он работает

Дело в том, что вы предлагаете расширенное определение БЭМ, со своими дополнениями. В обычном БЭМ бывают неоднозначные трактовки (делаем отдельный блок или добавляем элемент?), то в вашим дополнением неопределенность усилится. Сложно будет добиться от разных разработчиков единообразного кода. CSS-in-JS снимает с разработчиков задачу именования и группировки блоков, безо всяких сложных конвенций.


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

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


Совмещение двух блоков в любом случае приводит к размытию зон отвественности. В CSS-in-JS можно хотя бы добиться явного порядка стилей, потому что видно, что сonst MenuItem = styled(Link) расширяет стили ссылки, а не наоборот.

CSS-in-JS снимает с разработчиков задачу именования и группировки блоков, безо всяких сложных конвенций.

И лишает нас возможности удобной отладки CSS (например забываем про быстрый поиск CSS по селектору). У каждого подхода есть свои особенности. В моём подходе есть чёткий набор правил и ограничений, который если соблюдать то не возникнет вопроса «а как мне сделать это?». Вы правильно заметили что БЭМ можно трактовать по-разному из-за довольно широких определений. С наличием документированных правил я не вижу никаких проблем в освоении такого подхода, он как раз направлен на то чтобы максимально уменьшить возможность неоднозначной трактовки БЭМ.

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

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

Зато получаем все преимущества статического анализа (я использую styled-components и typescript). Можно искать, где используется стиль не текстовым поиском, а через статический анализ импортов и зависимостей. Я считаю, что это важное улучшение.


И в целом этот тред получается противостоянием "методология и конвенция именований" против "автоматические инструменты". В Javascript вы тоже предпочитаете все объекты называть глобально MyModuleName_MyClassName, а приватные переменные делать через __privateName или все-таки пользоваться ES6-модулями и Typescript? И если вы выбираете Typescript, то почему бы не использовать тот же самый тулинг и для стилевой части?

В Javascript вы тоже предпочитаете все объекты называть глобально MyModuleName_MyClassName, а приватные переменные делать через __privateName или все-таки пользоваться ES6-модулями и Typescript?

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

.menu__item.link.link--menu-item

Вам не кажется, что здесь где-то закралась тавтология? Во что у вас превратится компонент, если его нужно кастомизировать в 100 контекстах? 100 модификаторов для каждого места использования? Вы уверены, что эти все эти 100 модификаторов должны поставляться с самим компонентом и поддерживаться разработчиками этого компонента, а не разработчиками его использующими?

Согласен с вашим замечанием, но очень бы хотелось узнать, что вы предлагаете взамен.
То, что я нашел по ссылке (селекторы типа `mol_date_calendar_day`) очень похоже на БЭМ (точнее БЭЭЭМ, потому что указываются все элементы иерархии).

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

Да, это дальнейшее развитие бэма. Можно назвать фрактальным бэмом. Не так тут только два момента:


  1. Статически не чекается. Ну и ладно, не велика беда. Хотя ничто не мешает такую тулзу написать.
  2. На чанки не бьётся. Кода и так получается мало, так что в чанках просто нет потребности. Например, css всех $mol компонент — это всего 8кб в сжатом виде.
Да, это одна из особенностей этого подхода когда дело касается one-for-all компонентов типа ссылок, кнопок. Так как таких компонентов на всю систему обычно не больше десятка особого дискомфорта это не доставляет. Но даже если же таких компонентов сотни и тысячи я бы всё-равно предпочёл писать именно так, а не опираться на специфичность селектора. Гораздо проще держать в голове контексты одного компонента, чем контексты тысяч компонентов куда он подключается. Плюс в моём подходе я вижу все контексты явно, а в случае если они не в компоненте то я понятия не имею что будет дальше с ним происходить. Отсюда вытекает неизбежный ад с выстраиванием цепочки подключения файлов и повышением специфичности. Чтобы это полностью исключить я и пришёл к такой системе.

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

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

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

Ваша наивная вера в большую компанию меня просто поражает, ребята :-)

похоже скорее на адскил полифил, а то и на деобфускатор.
Боже, язык перевода кошмарен! При всей актуальности темы, проникнуть в суть иногда просто невозможно. Но всё равно спасибо! Хорошо бы хабру иметь технического редактора))
Укажите конкретные замечания, буду рад поправить, чтобы всем стало приятнее читать.
Завтра постараюсь влезть)) Мне в 4 утра вставать.

Очень напоминает "от преимуществах встраивания HTML в PHP" лет так 15 назад… быстро, удобно и гибко контролируемо программистами прямо "на лету"… А потом так же бодро и весело стали повсеместно от этого избавляться.


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

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

Sign up to leave a comment.

Articles