Этот пост является развернутым ответом на вопросы из этого разговора в Твиттере. Автор оригинала, Сунил Пай, является автором относительно популярной библиотеки glamor и работает разработчиком в Facebook.


Каким образом Javascript оказывается более удобным чем CSS? Как написание CSS внутри JS делает его более поддерживаемым?

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


Итак, самое главное в CSS-in-JS (cij) это CSS-селекторы. Наибольшее преимущество cij состоит в том, что компьютеры могут генерировать эти селекторы автоматически. Конвенции типа OOCSS и т.п. в принципе хороши, но они основываются на вручную написанных селекторах, которым сложно обеспечить уникальность в общем пространстве имен, потому что там всегда есть шанс на пересечение. Если не случится сейчас, то может произойти спустя года три, когда ваша команда разрастется, а обстоятельства поменяются. Эта ситуация усугубляется с использованием сторонних библиотек. Ограничение области действия CSS-селекторов также может достигаться использованием CSS-модулей, которые пользуются популярностью именно за эту возможность.


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


Кроме того, усиленный контроль за CSS-селекторами открывает новые возможности, которые не были легко доступны раньше. Например, мы можем элементарно реализовать извлечение критического CSS, сопоставляя блоки HTML с нужными им стилями, так что мы сможем загрузить на страницу всего 1-2 Кб CSS, который нужен для изначального отображения страницы. Безо всякого рантайма! Фреймворки типа Gatsby и Next активно этим пользуются, чтобы улучшить показатели производительности в проектах на их основе. Они встраивают критический CSS прямо в загружаемый HTML просто потому что он весит настолько мало, что это будет лучше лишнего запроса, блокирующего загрузку страницы. Это значительно сокращает время первоначальной отрисовки страницы. Более того, это также способствует решению проблем размера загружаемого Javascript! Выгода приходит от применения критического CSS, а также использования динамического import(), разделения кода и удалению неиспользуемого кода. (В противовес постоянно растущим легаси файлам стилей, в которые разработчики только добавляют новый код, боясь трогать существующий. Здесь есть немного аналитики на эту тему.)


Аналогичная ситуация с реализацией тем оформления. Знаете ли вы, что CSS-переменные, даже будучи очень интересной штукой, так и не взлетели до тех сценариев использования, для которых они изначально задумывались, а все потому что способы фоллбека для старых браузеров оказались либо очень сложными, либо неполноценными? Это означает, что они обычно используются как глобальные константы, но очень редко как переменные, значение которых определяется в браузере динамически. Наличие рантайма для работы с CSS означает, что вы сможете передавать значения из JS в стили, делая это возможным.


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


В ситуации сложных SPA с кучей компонентов и асинхронной загрузкой ресурсов, таких как скрипты и стили, вы не можете гарантировать точный порядок загрузки стилей, так что либо вам придется создавать какие-то рантайм решения для гарантирования порядка стилей, или просто использовать !important, даже если вы придерживаетесь какой-то CSS-методологии. Например, у вас есть элемент с class=“a b”, но классы a и b определены в разных файлах стилей, то вы не сможете быть уверены в финальном виде блока, если у вас не задан четко порядок следования файлов стилей. Кодовая база Facebook содержит тысячи использований !important, даже несмотря на то, что код писался квалифицированными программистами с использованием принципов SOLID и хорошим взаимодействием с командой дизайнеров.


Здесь часто говорится об обращение с CSS как будто это Javascript – учитывая, что 10 лет назад мы уже решали аналогичные проблемы для JS – библиотеки и модули регистрировали себя в глобальное пространство имен ($ и тому подобные) и нам приходилось быть довольно внимательными с порядком подключение скриптов в HTML. Но мы не застряли там навсегда – сейчас мы используем модули, и системы сборки сшивают их вместе в гарантированно правильном порядке. Это происходит просто и прозрачно для нас.


Наблюдая за реальными проектами, я также заметил, что вы все еще можете использовать традиционные архитектурные подходы (типа OOCSS или SMACSS и т.п.) в мире CSS-in-JS – элементы тех архитектур представляются здесь JS-объектами, вместо блоков селектор+стили. Я придерживаюсь такого подхода и он работает для меня хорошо. Здесь об этом можно почитать больше.


Также я хорошо осведомлен о недостатках CSS-in-JS. В самом деле, именно поэтому здесь нет какой то одной "каноничной" библиотеки, которая представляет CSS-in-JS – это спектр разных решений, от ванильного статического CSS с одной стороны до полностью динамических библиотек, типа styled-components с другой. Препроцессоры типа SASS или LESS могут показаться перпендикулярными этому спектру, потому что они теоретически могут использоваться любой из этих библиотек на усмотрение их авторов. Каждая из этих библиотек имеет свои недостатки – некоторые занимаются извлечением стилей на этапе сборки, чтобы не было расходов в рантайме, некоторые сфокусированы на правильности или удобстве для разработчиков, другие заточены на эффективную реализацию сложных анимаций, и так далее и тому подобное. Это многообразие – естественная реакция на необходимость разных решений для разных рабочих задач, в чересчур быстро развивающийся индустрии. И это происходит не только с библиотеками – разработчики веб-стандартов (ShadowDOM и других) доблестно стараются решить эти проблемы тоже, но их решение также имеет недостатки, наименьший из которых, это то что они пока не везде доступны, что делает это неприемлемым для использования во множестве команд.


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


P.S. Слишком поздно осознал, что забыл отметить галочку "Перевод", поэтому опубликовалось вот так. Ссылка на оригинал.


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

Комментарии (72)


  1. navix
    16.12.2018 12:05
    +3

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

    В Angular вопрос изоляции даже не стоит, там это идет из коробки.


    1. justboris Автор
      16.12.2018 13:31

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


      1. staticlab
        16.12.2018 23:52

        var style = getComputedStyle(document.body);
        console.log(style.getPropertyValue('--color-font-general'));


        1. justboris Автор
          17.12.2018 00:14

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


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


          1. vintage
            17.12.2018 00:29
            +1

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


            1. Gugic
              17.12.2018 23:42

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


              1. vintage
                18.12.2018 00:16

                Переменные наследуются по иерархии элементов.


  1. jakobz
    16.12.2018 13:19
    +2

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

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

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

    Сейчас мы на CSS Modules, и все равно мы на ключевые элементы добавляем :global()-селекторы — чтобы была возможность чуть что подхачить каскадингом.


    1. napa3um
      16.12.2018 13:32
      +1

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


    1. justboris Автор
      16.12.2018 13:52

      Я недавно закончил работать над проектом с использованием 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-файлом.


      1. trickst_r
        16.12.2018 22:58

        Например, material-ui использует JSS, но в своей документации они об этом не пишут

        Пишем.
        material-ui.com/customization/css-in-js/#jss


        1. justboris Автор
          16.12.2018 23:02

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


          For the sake of simplicity, we expose our styling solution to users. You can use it, but you don't have to.


    1. Carduelis
      16.12.2018 14:51

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


  1. JustDont
    16.12.2018 13:47
    +1

    CSS-in-JS дает возможность автоматизировать генерацию уникальных селекторов и идентификаторов.

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

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

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


    1. justboris Автор
      16.12.2018 14:19

      У вас нет каскадности и перекрываемости (кроме той, которую вы предусмотрели заранее в самом коде);

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


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

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


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

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


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

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


      1. JustDont
        16.12.2018 14:35

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

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

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

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

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

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

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

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

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


        1. Carduelis
          16.12.2018 15:00

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

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

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


          1. JustDont
            16.12.2018 15:21

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

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

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

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

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


          1. JustDont
            16.12.2018 19:38

            Они выбрали как основу для своего реакт-приложения библиотеку recompose. Написали проект, он почти что вышел из альфа-версии, а тут создатель recompose такой и пишет: Спасибо всем, но я не буду больше развивать библиотеку, может быть фиксить баги буду, используйте React.Hooks теперь.
            Ничего страшного не произошло, библиотека по-прежнем работает, а те же самые Хуки могут через 10 лет повторить историю миксинов, или React повторит историю jQuery.

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

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

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


          1. alexesDev
            17.12.2018 13:57

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


        1. justboris Автор
          16.12.2018 15:35

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

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


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

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


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

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


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

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


          1. JustDont
            16.12.2018 16:00

            Открыть все стили для переопределения – это не 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 из-за отсутствия статически анализируемых связей часто встречается ситуация «лучше оставим эти стили, хрен его знает где они используются, но пусть будут, от греха подальше».

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


            1. justboris Автор
              16.12.2018 16:18

              Открыть все стили для переопределения – это не API.
              А что же это? ^_^

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


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

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


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

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


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

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


              1. JustDont
                16.12.2018 16:38

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

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

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

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

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

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


                1. justboris Автор
                  16.12.2018 17:36

                  А кто-то другой вас посылает матерными словами и считает не очень умным

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


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

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


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

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



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

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

                  Есть CSS


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

                  И JS


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

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


                  1. vintage
                    16.12.2018 18:08

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


                    1. justboris Автор
                      16.12.2018 18:21

                      Я в курсе об этом, есть еще вот такой пример: philipwalton.github.io/responsive-components

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


                      1. vintage
                        16.12.2018 18:52

                        css-variables элементарно читаются/пишутся через JS и используются в CSS.


                        1. justboris Автор
                          16.12.2018 19:18

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


                          1. vintage
                            16.12.2018 19:21

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


                    1. Alexufo
                      16.12.2018 20:57

                      так как они меняют стили в зависимости от размера окна браузера, а не размера контейнера, в котором находится компонент.

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

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


                      1. vintage
                        17.12.2018 00:02

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

                        И ничего описанного вами там нет. Возможно вы что-то отредактировали случайно?


                  1. JustDont
                    16.12.2018 18:42

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

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


                    1. Alexufo
                      16.12.2018 21:47

                      каждый из которых посвящён отдельной группе медиа квери)


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


                      1. JustDont
                        16.12.2018 22:01

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


                  1. JustDont
                    16.12.2018 18:46

                    В зависимости от реализации выравнивания (либо через float:left/right, либо через flexbox) переопределение может сломаться, и текст с иконкой разъедется на две строки, например.

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

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

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

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

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


                    1. justboris Автор
                      16.12.2018 19:17

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

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


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

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


                      1. vintage
                        16.12.2018 19:30

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


                        1. justboris Автор
                          16.12.2018 21:43

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

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


  1. JustDont
    16.12.2018 15:21

    <коммент был не туда>
    Когда-нибудь я доживу до того дня, когда хабракоммент в последнюю ветку комментариев не будет путаться с новым комментом в корень.


  1. CyberAP
    16.12.2018 18:54

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


    1. justboris Автор
      16.12.2018 19:04

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


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

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


      1. CyberAP
        16.12.2018 19:25

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


        1. dagen
          16.12.2018 22:54
          +1

          Тут более общая проблема: вебпак (по крайней мере 4-й, может в пятом это победят, они ведь грозятся сделать first-class поддержку css) не гарантирует порядок включения css. А если вы победите вебпак или будете использовать свой умный сборщик (опасливо покосился на vintage), то вы всё равно получите это, так как ваши подгружаемые файлы могут подгружаться в любом порядке. Соответственно у вас два селектора с одинаковыми весами, и они будут по-разному работать, в зависимости от того пути, по которому пользователь пришёл к вашему компоненту (путь определяет дозагрузку частей приложения).


          1. CyberAP
            16.12.2018 23:04

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


            1. justboris Автор
              16.12.2018 23:14

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


              1. CyberAP
                16.12.2018 23:23

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


                1. justboris Автор
                  17.12.2018 00:11

                  Вот пример из статьи по ссылке. Есть 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;
                  `;

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


                  1. vintage
                    17.12.2018 00:22

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


                  1. CyberAP
                    17.12.2018 00:33

                    Здесь смешались ответственности селекторов. 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 */
                    }


                    1. justboris Автор
                      17.12.2018 01:00

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


                      1. CyberAP
                        17.12.2018 01:21

                        Это уже совсем-совсем другая тема.

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

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

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


                        1. justboris Автор
                          17.12.2018 02:22

                          люди ведь как-то выучили БЭМ и не забывают как он работает

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


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

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


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


                          1. CyberAP
                            17.12.2018 02:40

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

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

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

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


                            1. justboris Автор
                              17.12.2018 11:21

                              И лишает нас возможности удобной отладки CSS (например забываем про быстрый поиск CSS по селектору)

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


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


                              1. vintage
                                17.12.2018 14:07

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

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


                    1. vintage
                      17.12.2018 01:42

                      .menu__item.link.link--menu-item

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


                      1. justboris Автор
                        17.12.2018 01:45

                        Согласен с вашим замечанием, но очень бы хотелось узнать, что вы предлагаете взамен.


                        1. vintage
                          17.12.2018 01:51

                          1. justboris Автор
                            17.12.2018 02:04

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

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


                            1. vintage
                              17.12.2018 02:13

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


                              1. Статически не чекается. Ну и ладно, не велика беда. Хотя ничто не мешает такую тулзу написать.
                              2. На чанки не бьётся. Кода и так получается мало, так что в чанках просто нет потребности. Например, css всех $mol компонент — это всего 8кб в сжатом виде.


                      1. CyberAP
                        17.12.2018 01:56

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


              1. vintage
                17.12.2018 00:12

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


      1. vintage
        16.12.2018 19:46

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


        1. Goodkat
          16.12.2018 21:32

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


          1. vintage
            17.12.2018 00:45

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


        1. Alexufo
          16.12.2018 21:33

          похоже скорее на адскил полифил, а то и на деобфускатор.


  1. imouseR
    16.12.2018 22:57

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


    1. justboris Автор
      16.12.2018 22:58

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


      1. imouseR
        16.12.2018 23:44

        Завтра постараюсь влезть)) Мне в 4 утра вставать.


  1. mSnus
    17.12.2018 13:44

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


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


    1. justboris Автор
      17.12.2018 13:56

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