"Разработчик – это человек, который переводит мысли заказчика на язык машины"
@mikita_du

Идея статьи появилась год назад, думал назвать «Вёрстка в 2021», но как-то затянулось…
Весной 2021 года Microsoft объявила, что с 15 июня 2022 года прекращается поддержка IE11 (да, не для всех версий Win 10, но всё же), а значит, к выходу статьи уже останется менее полугода до знаменательного события, когда не придётся верстать под IE.

Для меня же это значит, что можно будет по полной использовать новые стандарты браузеров, в частности – css-variables, grid layout.

1.     Введение

С чего начинается вёрстка?
Начинается всё с дизайна. А конкретнее вот этих цифр – 16, 32, 24 (магическая последовательность).

Не многие знают, но эти цифры называют ритмом в дизайне.
Это кратность. В данном случае - кратность отступов 8-ке.
Если взять 8px как основу, то 16, 24 и 32 – это 8*2, 8*3 и 8*4 соответственно.

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

Программисты получают дизайны в Figma (как, например, я - скриншоты выше), где, собственно, и могут заметить эти магические числа.
Пользуясь нехитрой логикой, ленивые программисты (а я надеюсь читатель ленивый, а-то какой-то неправильный получается программист) запишут эти значения в переменные и будут использовать далее.
Например, это можно записать как offset-1 = 8*1, offset-2 = 8*2 и т.д (в стиле material-ui).

Однако не всё так прекрасно в этом дизайне:

Дизайн той же страницы. Везде восьмёрки, а тут, видите ли, девятка.

Ну и что с ней сделать?

Нужно идти к дизайнеру…

Приходим, спрашиваем – «Что тут по отступу? Ты ошибся и тут 8? Как и везде писать?».
И я просто уверен, что он, не задумываясь, ответит – «Да, везде же 8».

И правильно, вы ведь пришли к нему, подумав, а он вам верит. Аргументацию вы привели логичную (везде восьмёрки), всё вроде супер, конечно, 8.

Только есть одно «НО»…
Дизайнер не пишет (цифрами, текстом) отступы между компонентами, секциями и прочими элементами на странице. Он просто двигает картиночки по сетке (в лучшем случае), а то и просто до автовыравнивания элемента.

В примере выше и вы, и дизайнер смотрели только в определённое место в дизайне – на отступы. А информация о том, какой контекст был у дизайнера в момент рисования макета, потерялась в разговоре.

А контекст следующий.
Ширина блока на странице = 343px (как видно на первых скриншотах).
(343 – 9) / 2 = 167 (как вы понимаете – ширина колонки).
Получается, всё там правильно. Просто контекст не тот. Конкретно, этот отступ брался не из понимания ритма страницы, а банально из способности вместить контент в страницу. Чётное число там не может подойти.

Итак, возвращаемся к нашему коду.

Допустим, мы всё-таки выяснили, откуда взялось это число, но как тогда быть с этим счастьем разработчику?

Создавать новую переменную отступа? – Так она не кратна 8-ке.

То есть делать новую группу отступов, кратную 9-ке? – Звучит не очень, громоздко и непонятно.

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

Ай, поставлю как есть... (это прямо не шутка, лень – страшная штука, не недооценивайте её).

И получается такое счастье:

И как это читать? Где тут записана логика всех мыслей, что у нас были в момент написания?

Получается, мы никуда не записываем придуманную дизайнером логику. Мы просто копируем то, что дизайнер наделал в графическом редакторе.
Аналогично и наш дизайнер – никуда не пишет логику отступов. Например, что между заголовком и формой отступ 32px, а между элементами формы в 2 раза меньше – 16px.
Всё забывается сразу, как придумано.

Это же ужасно!
Получается, мы теряем важные части кода – ещё на этапе создания дизайна.

Так я встал перед вопросом – как же исправить вышеизложенное?
Как сохранить контекст, а главное – кто должен это делать и где?

2.       Идея

Думал очень долго, а потом наткнулся на интересную идею.
А что, если ввести специальные переменные, которые будут сохранять логику подсчёта?

Что, если вместо копирования 9px нам нужно было на основании общей ширины контейнера (343px) найти отступ, предполагая, что колонки будут равны (167 из дизайна).

Т.е, по сути, записать уравнение (343 – x) / 2 = 167.
Или x = 343 - 167*2.
В результате мы бы получили, что отступ равен 9px.

Вроде уравнение с числами читаемости не прибавило.
А давайте заменим числа в нём на переменные:
$betweenColumnOffset = $screenWidth - $columnWidth * 2

О, другое дело. Так понятна зависимость.

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

3. Media queries

Код на рисунке выше выглядит несколько сумбурно. Тут, конечно, есть вопросы с разделением кода, можно вынести в отдельные файлы переменные и т.д., но давайте двинемся дальше.
Что, если у нас приложение не только для мобильных телефонов? Допустим, мы делаем версию и под планшеты, и под разные экраны компьютера (от FullHD, до Ultra Wide).
Здесь придётся добавлять media queries. И код станет ещё более завален переменными.

Данную проблему мы решим с помощью css-variables:

С учётом того, что колонки у нас занимают всю доступную ширину экрана (100%), можно убрать переопределение --betweenColumnOffset и заменить фрагмент на следующий:

Так мы получаем автоматически генерируемые отступы на основании ширины колонок из дизайна. Логику можно достаточно просто инвертировать, и считать ширину колонок на основании отступа между ними и ширины экрана.
Имеется в виду --columnWidth: calc(100% - var(--betweenColumnOffset).
Где --betweenColumnOffset переопределяется в media-queries.

Можно применить такой подход на все элементы в проекте.

У вас будут динамичные отступы между заголовками и элементами.

Между элементами формы.

Отступы внутри контейнеров (карточки, либо формы логина).

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

А главное – поддержка и написание будет занимать куда меньше времени и всё будет ровным, потому что вы не будете делать pixel perfect, а будете переводить мысли заказчика в код.

Я сделал уже 4-5 проекта применяя данный подход.
На одном за две недели даже пришлось применить три разных дизайна. Частично меняя логику переменных, конечно, но всё-таки скорость великолепная.
Работает отлично, единственное – это не получается завернуть в библиотеку, потому как если стандартизировать, то получится что-то узко применимое только к определённому дизайну, в стиле bootstrap или material ui.

Поэтому я сделал 3 репозитория, в которых попытался отобразить варианты того, как можно применять css-variables + scss, либо css-variables + styled-components для сохранения логики заказчика и дизайнера.

1)      scss – https://github.com/DrBoria/cra-scss

2)      styled-components – https://github.com/DrBoria/cra-styled

3)      styled-components + куча компонентов – https://github.com/DrBoria/cra-components-library (собственно, это и есть попытка сделать стандарт, но ничего не выходит из-за того, что основная идея – подстраиваться под заказчика, проект, дизайнера, а не плодить очередную библиотеку)

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

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


  1. technic93
    18.12.2021 13:01
    +2

    А flex контейнер не может сам рассчитать девятку если правильно задать правило распределения элементов и число колонок?


    1. mikita_du Автор
      18.12.2021 13:03

      Мне более читаемым/явным показался grid.

      По этому использую его для сложных шаблонов, а для простого выравнивания по центру, сторонам - flex.

      В остальном - флекс без проблем, но нужно объединять в контейнеры будет каждую строку, либо проставлять на детях flex-grow 1/2. А через grid можно всё в одном месте задать.


  1. thisuserhatephp
    18.12.2021 13:21

    Стиль именования переменных правильный, но классы то зачем с заглавной писать ?)


    1. mikita_du Автор
      18.12.2021 13:21

      Думаю привычка от styled-components)


  1. tempick
    18.12.2021 14:27
    +1

    Весной 2021 года Microsoft объявила, что с 15 июня 2022 года прекращается поддержка IE11 (да, не для всех версий Win 10, но всё же), а значит, к выходу статьи уже останется менее полугода до знаменательного события, когда не придётся верстать под IE
    Ну то, что поддержку прекратят — еще не означает, что браузер тут же исчезнет со всех компьютеров)


    1. mikita_du Автор
      18.12.2021 14:34

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

      А новых проектов под него вообще не будет делаться.


      1. tempick
        18.12.2021 15:42

        Разумеется. Под него и сейчас далеко не всегда имеет смысл верстать


  1. dom1n1k
    18.12.2021 14:58
    +10

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

    1. Браузеры давно и прекрасно работают с дробными размерами. Нет никакой проблемы сделать стандартный межколонник 8px, а лишний пиксель раскидать половинками в колонки.

    2. Величина 343px — это ширина стандартного айфона (375) минус два стандартных марджина по 16. То есть это ширина контентного контейнера, а не экрана — нельзя эту величину использовать в медиа-запросе.

    3. Но 375 это лишь один из популярных экранов, а есть и другие — и к слову сказать, большинство четные. А главное, множество телефонов на Андроиде имеет экран 360, в который ваша верстка просто не влезет. (Кстати, именно поэтому лично я предпочитаю рисовать мобильные макеты под 360, а не 375).

    4. Зачем в коде конкретная ширина экрана и колонок?! Там вообще не должно быть переменных типа $columnWidth — там нужно работать либо свойством flex, либо единицей 1fr в гридах.

    5. Дискретные ширины экрана — это дичь уже несколько лет как. Это получается устаревшая адаптивная (несколько фиксиарованных размеров), а не отзывчивая (тянется непрерывно) верстка.


    1. mikita_du Автор
      18.12.2021 21:31

      По первым 3м пунктам думаю нет смысла отвечать. Они никак не противоречат статье. Странно, что вам показалось, что я спорю хоть с чем-то из этого.

      А по поводу последних двух.

      Это шикарно, если можно сделать всё динамично - это ещё лучше передаст мысли заказчика.

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

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

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


      1. dom1n1k
        18.12.2021 22:39
        +1

        По первым 3м пунктам думаю нет смысла отвечать. Они никак не противоречат статье.
        А код им противоречит. Код ведь является частью статьи?
        Желание отразить в коде логику дизайнера — несомненно благое. Посыл правильный, а вот его реализация — нет. Потому что в итоговом коде неправильно примерно всё. Где-то посередине рассуждения пошли не в ту сторону.


        1. mikita_du Автор
          18.12.2021 22:48

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

          Возможно вы предложили вариант отразить лучше. Статья об этом. Я предложил один вариант, вы ещё более понятный по вашему мнению.

          Великолепно, значит мы вместе охватывает сразу кучу вариантов написания.

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

          Если он мыслит в brakepoint, то нельзя делать по другому. Тк именно так думает заказчик. Даже если кому-то кажется, что так логичнее.

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

          З. Ы. Я не говорю про сохранение логики дизайна, я говорю про сохранение логики заказчика. Это разное. Дизайн - лишь очередной инструмент в переводе мыслей заказчика в код. Просто более наглядный, чем слова заказчика.


  1. gBACTAKAHA
    18.12.2021 17:07
    +3

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

    Но в итоге руководитель (он верстал на таблицах раньше, про флекс не в курсе даже) решил что препроцессоры и jade нам как верстальщикам не нужно, нам надо в один файл на чистом CSS заполнять и все. (Типо мы кучу времени тратим на придумывание структуры и.т. д). А я еще про Tailwindcss заикался, а меня отправили блоки в layout на floatах делать, рассмеявшись на совещании .... Был уволен)

    За статью однозначно плюс. Лет пять назад был бы благодарен вам)


    1. ChiDa
      19.12.2021 00:20
      +2

      Ничего плохого во float нет, многие элементы до сих пор на них делаются. Tailwindcss - вообще редкостный отстой. Я бы за него тоже уволил. Вообще странная ситуация. На выходе вы можете отдавать в деплой что угодно. Один файл css или один сжатый. Это настраивается в таск менеджере или сборщике. Как вы верстаете сами это ваше личное дело, на выходе этого не втдно и странно в это посвящать руководство на совещании.


      1. gBACTAKAHA
        20.12.2021 11:44

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


  1. Kvass
    18.12.2021 19:32

    Без БЭМ не кошерно как то выглядит


  1. stainlouder
    18.12.2021 19:32

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


  1. uyrij
    18.12.2021 20:41
    +1

    Это точно 22? Похоже на 17 или ранее ????

    Я думал будет про вебпак/ролап/модули

    И ещё в рамках статьи препроцессор излишне... для всех примеров выше Достаточно somevalue:var(--)


  1. ninJo
    19.12.2021 00:29

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


  1. monochromer
    19.12.2021 17:47

    "Вёрстка в 2022". Код вставляется картинками, которые на экранах с высокой плотностью пикселей почти невозможно разглядеть.


  1. ec5tasy
    19.12.2021 18:19

    У меня вся верстка на работе сводится к ant design + styled components)