С первых строк кода, каждый человек начинает понимать важность правильной его организации и оптимизации рабочего пространства в целом.

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

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

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

Если говорить о css, то с уверенностью можно сказать — каждый из нас пользуется определенной методологией, осознанно или нет. Даже если человек не использует определенные правила и стандарты, то у него все равно есть свои привычки и постоянно повторяющиеся приемы.

Способы написания кода не обязательно должны быть общепринятыми и стандартизированными, обязательным должно быть другое – они должны быть предсказуемыми.

Список методологий на которые стоит обратить внимание не так велик:

-BEM,
-Smacss,
-OOCSS,
-MCSS,
-Atomic CSS

Atomic CSS – пожалуй является самой необычной и даже в какой то мере пугающей методологией, что к счастью не мешает ей быть очень понятной и предсказуемой.
Что бы обосновать свой выбор я должен откатить немного назад.

Почти Атомарный CSS


Были времена, когда корневой каталог подавляющего количества проектов на стадии создания интерфейса выглядел как три файла и две папки:

>fonts
>img
-index.html
-style.css
-script.js

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

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

Первым решением этой проблеммы были следующие действия:

  • создание файла с названием “re-use.css”,
  • создание в этом файле инструкций, которые в теории могут понадобиться больше чем одному селектору,
  • дописывание разных селекторов к одной и той же инструкции.

Имело это следующий вид:

...
.class { display: inline-block;}
.class { text-transform: uppercase;}
...

и в последствии принимало следующий:

...
.menu-link, .primary-button, .form-button, .footer-link, .social-link
{ display: inline-block;}
...

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



.inline-block { display: inline-block;}
.block {display: block;}
.uppercase {text-transform: uppercase;}


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

<aside class=”sidebar fixed left top w-30 h-100 main-fill”></aside>


С одного взгляда достаточно что бы понять что это боковая колонка, с фиксированным позиционированием, с левой стороны экрана, занимающая 30% его ширины и 100% высоты, залитая главным цветом.

Все что касалось числовых значений, в основном это были внешние и внутренние отступы, я записывал в стандартном формате. Для этого каждому тегу, или группе тегов я добавлял отдельный класс идущий первым, на примере выше это класс “slider”.

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

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

И тогда на помощь пришли две вещи, которые помогли решить все проблеммы – это препроцессор и шаблонизатор.

С их помощью я модифицировал свою методологию и сделал верстку приятной и удобной.

Почти идеальный Css


Начну с препроцессора. Его выбор не принципиален, изначально я пользовался Sass, потом SCSS и в итоге перешел на Stylus, потому что уважаю минимализм, а Stylus был максимально минималистичен (в примерах ниже будет использован scss, по причине его популярности).

Итак, первое что я сделал это написал дополнительные классы которые с помощью директивы @extend выглядели как настоящие атомы:

.flex {
 display: flex;
 flex-wrap: no-wrap;	
}
.flex-jc-center {
 @extend .flex;
 justify-content: center;
}
.flex-ai-center {
 @extend .flex;
 align-items: center;
}

Мне понравилась идея, а директива @extend вызвала сходство с ядром атома, рядом с которым были дополнительные инструкции.

Я решил что идею надо развивать и создал отдельный файл для организмов. Организмами я называл классы включающие в себя несколько директив @extend:

.header {
 @extend .fixed;
 @extend .w-100;
 @extend .main-fill;
 @extend .left;
 @extend .top;
 @extend .flex-ai-center;
 @extend .z-top;
}

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

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

Сначала я детально изучил графические проекты которые мне достаются от дизайнеров и выявил ряд закономерностей:

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

Первым делом нужно было написать функции и миксины для создания нужных классов:


//создаем функцию для пересчета px в em 
@function em($pixels, $context: $browser-context) { 
 @return #{$pixels/$context}em 
};

// создаем массив с размерами для текста 
$text-size: ( 
l: 18, 
m: 16, 
s:  14, 
xs: 12 
);

@mixin emFonts($list, $n) { 
//создаем миксин $list – массив, n – Число на которое требуется уменьшить шрифт для адаптивности.
 @each $status, $size in $list { 
//используя интерполяцию - создаем класс для каждого из размеров 
	&-#{$status} {
 		font-size: em($size - $n); 
//присваиваем нужные числовые значения тексту
  }
 }
}

Теперь мы можем вызвать эту комбинацию из миксина и функции в любом удобном для нас месте:


.txt { 
 @include emFonts($text-size, 0) 
}

И на выходе получим 4 класса для текста разных размеров:

.txt-m {  font-size: 1.125em; }
.txt-s {  font-size: 1em; }

Аналогичным образом создаются и вызываются функции для размеров заголовков, цветов текста и заливки, шрифтов и тд.

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

Шаблонизатор.

Я думаю многие из вас пользуются шаблонизаторами, и скорее всего – это Pug(который раньше назывался Jade).

Для атомарной верстки он необходим благодаря 3 вещам:

  • миксины
  • переменные
  • циклы

Pug полностью избавляет нас от громоздкого из за микроклассов HTML кода, так как мы можем превратить следующий код:

…
<ul class=”menu__list flex-ai-center w-100 relative “>
 <li class=”menu__item m-color m-font txt-s inline-block bold-border”>first</li>
 <li class=”menu__item m-color m-font txt-s inline-block bold-border”>second</li>
 <li class=”menu__item m-color m-font txt-s inline-block bold-border”>third</li>
</ul>

в удобный для редактирования:

-let menuItemClasses =   ‘menu__item m-color m-font txt-s inline-block bold-border’
//создав переменную содержащую все класы мы можем менять их в одном месте
ul
   li(class=`${menuItemCLasses}`) frst
   li(class=`${menuItemCLasses}`) second
   li(class=`${menuItemCLasses}`) third
...
</ul>

или в другом варианте, с помощью цикла:

let menuItems = [‘first’, ‘second’, ‘third’]
ul
    -for(let item of menuItems) {
	li(class=”menu__item m-color m-font txt-s inline-block bold-border”)	
    -}

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

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

Заключение


В заключении хотелось бы сказать следующее:

перед тем как начать пользоваться “почти атомарной методологией”, я долгое время использовал smacss и потом BEM. В итоге от bem я оставил лишь названия для классов требующих описания отступов и размеров, и иерархию хранения файлов и папок. Набор готовых классов и функций, я подключаю к проекту в качестве библиотеки.

Важный момент который хотелось бы отметить – это удобство верстки станиц и отдельных ее секций целиком. Благодаря микроклассам достаточно легко создать “скелет” страницы или секции в шаблонизаторе и только потом перейти к написанию для нее стилей.

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


  1. orion76
    09.12.2018 22:21
    +3

    Т.е. «стиль» жестко привязывается «специальным» классом к элементу страницы?
    инлайн-стили 2.0?


    1. JustDont
      09.12.2018 22:32
      +1

      Ага. Это когда до дрожи в коленках хочется инлайновые стили, но кто-то не даёт.
      Хорошего в этом примерно столько же, сколько в инлайновых стилях, лишенных всех их несомненных плюсов (рантайм-подстановок, например).
      С другой стороны, это голый цсс, в отличии от красочных либ для css-in-js, которые тормозят, будучи переизобретением очень быстрого нативного встроенного в браузер велосипеда на JS.

      Но абсолютно неясно, зачем это всё нужно. Стили компонента страницы никогда не нужно было бездумно и произвольно перекрывать. В подавляющем большинстве случаев всего-то нужно решение для единократного перекрытия (база + тема), всё. Попытки же переехать в инлайн для решения проблемы хаотичного перекрытия звучат как «Мы выстрелили себе в ногу из гранатомёта, и, скажу я вам, это больно! Поэтому далее мы попробовали выстрелить себе в ногу из пистолета, и это намного лучше! Горячо рекомендую!».

      А может лучше вообще не стрелять?


      1. justboris
        10.12.2018 00:35

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


        1. JustDont
          10.12.2018 00:52

          Не хочется устраивать у себя хаос из перекрытий — не надо его устраивать. Вот и всё собссно. Повторы стилей устраняет любой препроцессор или просто css modules; это даже не говоря про то, что далеко не все повторы нужно устранять. Накатывание одного перекрытия для кастомизации компонентов делается через обычную специфичность селекторов, база — это 1 класс, тема — комбинация из двух (база + название темы), которая заведомо специфичнее базы и спокойно её перекрывает.

          А больше ничего и не нужно.


          1. justboris
            10.12.2018 10:59

            Все равно непонятно. Чтобы не устраивать хаос и соблюдать порядок, нужна методология. Какого способа организации классов придерживаетесь вы? CSS Modules?


            1. JustDont
              10.12.2018 14:56

              CSS Modules — спека, а не методология. Что автоматически делает её намного лучше (не надо стоять и следить над соблюдением).
              И когда у нас не еще не было CSS Modules — нам хватало «не перекрывайте ничего и нигде вне css темы» в качестве методологии. Следить за этим было просто, хаоса — не было. Ну, вернее, в темах был заметный хаос, но css тем по определению самый короткоживущий css (нужен под конкретное оформительство конкретных компонентов конкретного продукта и релиза), и поэтому фиг бы с ним.


    1. JohnyScript Автор
      10.12.2018 00:27

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


      1. Tyusha
        10.12.2018 10:43

        Как у вас класс с именем 'top w-30 h-100'
        способствует адаптивности страницы?


      1. bro-dev0
        10.12.2018 11:35

        Инлайновые стили кэшируются браузером вместе с html страницей.


  1. Alexufo
    09.12.2018 23:43

    Чем же вас не устроил bootstrap4 тогда? Скачиваете, убиваете все, кроме инструкций описания скелета и вуаля — у вас тот же подход + стандартизация.

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

    Например, в какой-то момент вам нужно убрать inline-block и поставить block c padding-bottom:0.5em. Тогда у вас будет xs-block плюс xs-padding-bottom. И потом надо будет логотипу или элементу cправа дать тоже паддинг, но с .5em, чтоб они перестали слепаться и тут начинается!

    Вы опять пишите классы xs-padding-right-05em… и когда все это чудо у вас написано в class="" на все брейкпоинты, то с определенного момента вы перестаете понимать, как это взаимодействует.

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


    1. JohnyScript Автор
      10.12.2018 00:18

      На счёт bootstrap тяжело дать однозначный ответ. Слишком он громоздкий и неправильный с моей точки зрения. Эти бесконечные коридоры из вложенных селекторов и тд.
      Я ведь борюсь за порядок и минимализм, не только для удобства, но и для увеличения скорости рендеринга страниц.
      А на счёт создания кучи дополнительных классов для отступов и брейкпоинтов, я ведь написал что для этих целей просто использую классический подход написания стилей. В итоге css файлы состоят только из инструкций с числовыми значениями.
      Моей главной целью было избежать повторений одинаковых инструкций, думаю я ее достиг.


      1. Alexufo
        10.12.2018 00:47

        Мы же говорим про 4-ую версию.Про флексы, сетку и утилиты, а там все довольно складно, вложенность технически обоснвана.


  1. Moskus
    10.12.2018 01:26

    Я, честно говоря, не знаю, какие выступающие органы надо отрывать тем, кто пишет классы типа

    sidebar fixed left top w-30 h-100 main-fill

    Потому что это костыль, который противоречит самой идее CSS — отделению разметки от оформления. Это даже еще хуже чем inline style, потому что
    style="width:30px; height:100px"
    не может значить ничего другого. А вот идиотская ситуация, когда у вас
    .h-100 {height:100px}
    завтра превращается в
    .h-100 {height:200px}
    — более чем возможна.


    1. JohnyScript Автор
      10.12.2018 09:08

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


      1. Moskus
        10.12.2018 09:23
        +1

        Вы не путайтесь в показаниях. Классы типа .h-100 несут на практике всегда одну и ту же функцию — назначение определенного свойства оформления. От того, что вы его переименуете, он не потеряет свою функцию и не перестанет быть использован там, где разработчику была о нужно height:100. Такое вполне допустимо в стилях, который генерирует движок или фреймворк дополнительно к семантической разметке, например — при назначении темы. Но совершенно недопустимо по своей функции в том, что пишется руками.


      1. Moskus
        10.12.2018 09:35

        Для понятности, опишу негативный сценарий.
        1. Вы создаете класс, который назначает ширину 100 пикселей.
        2. Называете его w-100.
        3. Назначаете его множеству элементов.
        4. Переименовываете в abcde в CSS и в HTML.
        Но от того, что он теперь называется abcde, ничего принципиально не меняется в том, как он используется. То есть вы как-бы реализовали переменную, и даже назвали ее так, чтобы название не отражало значение (что вообще ад). Вы можете менять значение этой переменной, редактируя только CSS, но не можете, редактируя только стили, сделать один блок, который был 100, например, 150, а другой оставить 100. Так что делать так можно, только если вы точно уверены, что это всё никогда не будет действительно переделываться.


    1. ArsenAbakarov
      10.12.2018 13:08

      Мог бы, плюсанул бы, сам удивляюсь, зачем это пишут, потом в итоге в верстке wrapper-pull-right уезжает куда-нибудь вниз или вверх по медиа запросу и тп. и тд. А ты сидишь и ломаешь свою голову и ничерта не понимаешь!


  1. Tyusha
    10.12.2018 10:54

    Del


  1. Tyusha
    10.12.2018 10:56

    Вот скажите мне друзья. Где нынче тот принцип разделения содержания и оформления? Открой любой современный сайт, там 20 этажные обёртки дивами. И все это нормальным считают, всё по bem-у сделано. А JS ради оформления?! Это тоже ок? К сожалению, сегодня ответ да.


    Рада ошибаться. С радостью посмотрю на контрпримеры.


    1. aleki
      10.12.2018 12:08

      Как связан BEM с 20-ти этажными обертками?


    1. AxisPod
      10.12.2018 14:02

      Да вот недавно пришлось использовать react-data-grid, я когда увидел, чего он там творит, мне стало не просто плохо, мне стало очень плохо. А он просто для табличек жестко использует абсолютно позиционированные дивы. Для каждой ячейки 3 дива и спан, в котором к моему удивлению лежит ещё один див. Я был в шоке от его скорости работы, её нет, 100 строк оно рендерит несколько секунд. Так что им норм, они не против делать непонятно что, лишь бы не использовать то, что приспособлено для требуемой задачи.


      1. kurumpa
        10.12.2018 17:05

        А он просто для табличек жестко использует абсолютно позиционированные дивы

        А это для того, чтобы 100 000 строк показывать так же быстро, как и 100 (зачем их рисовать, если их все равно никто не видит)


        1. AxisPod
          10.12.2018 17:07

          Это ладно, но зачем 5 dom элементов для каждой ячейки?


    1. Moskus
      10.12.2018 21:51

      Начните с понимания того, что множество людей не понимают: что есть классы, которые должны писаться в соответствии с принципом разделения оформления и разметки, а есть — те, что генерируются автоматически. На вторые — плевать, там может быть вообще что угодно. А что неправильно в смешении разметки и оформления, я объяснил для тех, кто понимает только на примерах, в комментарии выше: habr.com/post/432586/#comment_19476736

      И, к слову, BEM был придуман именно как конвенция для случая автогенерируемых стилей, с чем этот принцип действительно прекрасно справляется. Но потом некоторые, у которых семантическая разметка в голове просто не умещается, сделали из него культ и стали по нему писать вручную. То, что нечто образует статистическую норму (то есть «дофига кто так делает») не значит, что это правильно.


  1. dom1n1k
    11.12.2018 20:32

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