Материал предназначен для дизайнеров и Frontend-разработчиков. Дизайнеры поймут, как минимизировать количество работы для верстальщиков, и тем самым получить их одобрение. Верстальщики научатся экономить свои ресурсы, силы и мозги, чтоб потратить их на более полезные задачи, чем расчёт непонятных сеток.

С чего все началось

В 2018 мы перешли на реактивные фреймворки. Наш выбор пал в пользу Vue. Мы используем его в наших проектах чаще всего. Нам понравилась экономия времени и сил за счёт компонентного подхода (HTML, CSS, JS в одном файле). Далее мы решили автоматизировать всё, что только можно автоматизировать.

Раньше, когда компания работала на субподряд, к нам приходили макеты от разных веб-студий (мы застали ещё времена макетов в Photoshop). Сетки в этих в макетах были просто ужасны. Например 12 колонок на десктопе, 10 на каких-то промежуточных разрешениях, и 2 колонки на мобильном. Отступы между колонками могли быть абсолютно разными. Всё это сводило нас с ума, потому что каждое новое разрешение — это как вёрстка нового макета. Никакой экономии, никакой выгоды, постоянно нужно доказывать, что это действительно много работы, но нас никто не собирался слушать, потому что макеты и бюджеты уже согласованы.

Как было раньше

Как работает сейчас

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

Например, не понятно, на каких разрешениях дизайнер рисует макет 1440 px и на каких разрешениях переходить на макет 768 px. На 1439 px планшетный макет выглядит плохо. Кроме этого есть и другие базовые разрешения, такие, как 1366 px, 1280 px, 1024 px и т.п. Мы пытаемся делать как-то по своему. В итоге получается цепочка итераций переделок и переработок.

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

Резиновая верстка — это когда мы перекладываем работу по адаптации макета под доступную ширину браузера, на сам браузер. Достигается это различными CSS-свойствами и единицами измерения: vw, %. При этом макет очень и очень редко масштабируется.

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

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

  • Адаптивная (фиксированная)

  • Масштабируемая

  • Резиновая (называется так потому что тянется, она жидкая, но при этом возвращается в исходное состояние)

    Примеры сеток

    Вот образец, как обычно рисуются сетки. На 1920px 12 колонок:

    На 1440px — 10 колонок, на 768px — 6 колонок, на 320px 2 колонки

    Для нас это плохо. Мы решили уйти от этого.

    Мы рисуем десятиколоночную сетку. Её легче считать на вёрстке

    Далее сжимаем ширину

    Мы видим, что масштабируется только ширина колонок, но не отступы колонок (gutter) и margin по краям. Это не позволяет нам нормально использовать сетку, если просто раскопировать первоначальный вариант и уменьшать ширину макета.

    Для максимального масштабирования нам нужно, чтобы менялись и gutter и margin, поэтому мы переходим к ручному масштабированию. Для этого мы используем 10 колонок, margin 40px и gutter 30px.

    Рассчитаем размеры в процентах. Берём за основу макет 1920px.

    margin 40px займёт:       40 / 1920 = 0,020833333333 = 2,083333%

    gutter 30px займёт:         30 / 1920 = 0,015625 = 1.5625%

    Ширина колонок 157px: 157 / 1920 = 0,08177083333 = 8,177083%

    Для проверки можем сложить все размеры:

    10 колонок + 9 gutter + 2 margin

    (157 * 10) + (30 * 9) + (40 * 2) = 1920px

    Итак, у нас есть процентные размеры:

    • колонка 8,177083%

    • отступ с краю 2,083333%

    • отступы между колонками 1.5625%

    Рассчитаем размеры на макете 1440px:

    • ширина колонки: 1440 * 8,177083% = 117,75px

    • margin: 1440 * 2,083333% = 29,99999px

    • padding: 1440 * 1.5625% = 22,5px

    сетка на 1440px
    сетка на 1440px

    Таким же образом можно рассчитать размеры на все ширины макетов

    сетка на 1024px и 768px
    сетка на 1024px и 768px
    сетка на 320px
    сетка на 320px

    Как мы видим, наша сетка сохранилась. Она просто уменьшилась относительно ширины макета, ширины канваса.

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

    Код для резиновой верстки

    Перейдём к практике. Мы используем препроцессор scss и функцию percentage для расчета процентов, чтоб сократить код. Напишем в HTML и CSS следующее: https://codepen.io/danilabr/pen/yLpbxPr

    HTML:

    <div class="is-grid"></div>

    CSS:

    $grid_color: #00f;
    $grid_margin: percentage(40 / 1920); // 40 / 1920 * 100%;
    $grid_width: percentage(157 / (1920 - 40 * 2));
    $grid_gutter: percentage(30 / (1920 - 40 * 2));
    
    body {
       position: relative;
       padding: 50px 0;
       min-height: 100vh;
    
       &.is-grid::after {
           content: '';
           position: absolute;
           z-index: 1000;
           top: 0;
           bottom: 0;
           opacity: 0.15;
           left: $grid_margin;
           right: $grid_margin;
           background: repeating-linear-gradient(90deg,
                   $grid_color 0,
                   $grid_color $grid_width,
                   transparent $grid_width,
                   transparent $grid_width + $grid_gutter);
           pointer-events: none;
       }
    }
    

    результат:

Эти стили дают возможность сделать так, чтоб по нажатию на определённую клавишу на body добавился класс .is-grid и отобразилась данная сетка. Это позволяет не тратить время на pixelperfect, и в то же время в процессе вёрстки следить, чтобы блоки располагались правильно по сетке.

Ширину колонки $grid_width и отступ между колонками $grid_gutter будем считать не относительно общей ширины 1920px, а за минусом отступов слева и справа $grid_margin:

$grid_width: percentage(157 / (1920 - 40 * 2));
$grid_gutter: percentage(30 / (1920 - 40 * 2));

В стилях у сетки отрезаем слева и справа margin:

left: $grid_margin;
right: $grid_margin;

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

background: repeating-linear-gradient(90deg,
               $grid_color 0,
               $grid_color $grid_width,
               transparent $grid_width,
               transparent $grid_width + $grid_gutter);

Далее добавим обёртку .wrapper, и положим в него элемент .column-item https://codepen.io/danilabr/pen/LYeyXba

HTML:

<body class="is-grid">
    <div class="wrapper">
        <p class="column-item">123</p>
    </div>
</body>

CSS:

.wrapper {
    margin: 0 $grid_margin;
}

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

Добавим декоративные стили для .column-item:

.column-item {
   height: 50px;
   background: grey;
}

Сделаем ширину .column-item равной пяти колонкам. Это можно сделать несколькими способами:

1. Просто измерить ширину 5ти колонок с отступами в макете. Либо сложить ширину колонок руками:

5 колонок * 157px + 4 отступа * 30px = 905px.

(не забываем, что 1920px минус 2 отступа справа и слева по 30px = 1840px).

width: percentage(905 / 1840);

2. То же самое на чистом CSS:

width: calc(905 / 1840 * 100%);

3. Можно сосчитать 905 / 1840 на калькуляторе (так лучше не писать):

width: calc(0,4918478261 * 100%);

4. Либо, если использовать наши переменные:

width: $grid_width * 5 + $grid_gutter * 4;

Результат всех этих вариантов будет одинаковый:

Подключаем mixin mq, или ошибка брейкпоинтов через переменные

Часто Frontend-разработчики используют в качестве брейкпоинтов глобальные переменные в препроцессоре. Например, основные разрешения: 1920px, 1440px, 1024px, 768px и т.д. Но это загоняет разработчика в очень узкие рамки. Бывает, что возникают ситуации, когда у нас есть промежуточное разрешение: например, 905px. На нём часто не влезает текст, например, слишком длинное слово.

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

Мы хотим себе оставить свободу использовать разные значения брейк поинтов. Для этого мы используем миксин mq(), который выглядит следующим образом:

@mixin mq($from, $to: false) {
   @if $to {
       @media (min-width: #{$from}px) and (max-width: #{$to}px) {
           @content;
       }
   } @else {
       @media (max-width: #{$from}px) {
           @content;
       }
   }
}

Миксин принимает 2 параметра. Второй — опциональный. Если передаётся только один параметр, то используется подход desktop first, если 2, то mobile first.

Добавим к предыдущему примеру mixin mq и брейкпоинт 768px.

.column-item {
	…
   	@include mq(767) {
       width: calc(#{$grid_width} * 4 + #{$grid_gutter} * 3 + 5px);
   	}
}

При ширине экрана менее 767px ширина .column-item станет равна 4м колонкам + 5px.

Слайдер с динамической высотой

https://codepen.io/danilabr/pen/MWroJKv

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

i {
   display: block;
   padding: percentage(9 / 16) 0 0;
   background: none no-repeat 50% 50%;
   background-size: cover;
}
Разрешение экрана более 1280px
Разрешение экрана более 1280px
Разрешение экрана менее 1280px
Разрешение экрана менее 1280px
Разрешение экрана менее 768px
Разрешение экрана менее 768px

Два блока в резиновой сетке

Продемонстрируем три варианта вёрстки для размещения двух блоков в сетке. Результат будет одинаковый:

Разрешение экрана более 1024px
Разрешение экрана более 1024px
Разрешение экрана менее 1024px
Разрешение экрана менее 1024px

1. Первый способ с помощью display: flex; https://codepen.io/danilabr/pen/LYeLWzN

При разрешении менее 768px padding у блоков сделаем резиновым

с помощью padding: percentage(20 / (320 — 7 * 2));

2. Второй способ использует display: grid; https://codepen.io/danilabr/pen/QWagmxg

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

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

3. В третьем способе мы полностью отказываемся от media queries. Современный frontend позволяет делать и такое. https://codepen.io/danilabr/pen/wvpejWr

Для этого в html нам пришлось добавить обёртки над тэгом <p>. Основная логика заключена в следующей строке:
flex: max(482px, (100% / 2 — #{percentage(30 / 1840)}));

Здесь используется flex-basis и нативная функция css max. На разрешениях, на которых размер колонок меньше 482px будет использоваться второй параметр функции (100% / 2 — #{percentage(30 / 1840)}).

Растягиваются колонки на всю ширину за счёт flex-basis, переносятся на следующую строку за счёт flex-wrap. В данном случае мы все расчёты переносим на сторону браузера.

Итог

В заключение, хочется написать список основных постулатов, которые позволят делать резиновую вёрстку быстро, качественно и надёжно:

  • Как можно больше использовать проценты.

  • Как можно больше использовать формулы автоматического рассчёта размеров.

  • Как можно больше использовать коэффициенты.

  • Как можно больше использовать grid.

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

  • Для корректного отображения всех изображений использовать cover или contain.

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


  1. ElKornacio
    07.04.2022 13:28
    +10

    Мы рисуем десятиколоночную сетку. Её легче считать на вёрстке

    12 делится на 2, 3, 4, 6. 10 делится на 2, 5. Это главная причина, почему используется 12 колонок. Дизайнер хочет 3 колонки - он делает 3 колонки, а не 5 (слишком мелко) и не 2 (слишком крупно).

    5 колонок * 157px + 4 отступа * 30px = 905px.

    (не забываем, что 1920px минус 2 отступа справа и слева по 30px = 1840px).

    width: percentage(905 / 1840);

    Я правда хочу верить, что это шутка. Вместо условного "col-md-4" бутстрап-стайл мне предлагается верстать с калькулятором в руках? Или это какая-то разовая акция?

    И ещё, я, вероятно, чего-то не знаю про SCSS/SASS, но:

    width: * 5 + " class="formula inline">grid_gutter 4;

    Это очень странный стиль, который я раньше не видел. Чем это лучше конструкций аля:

    @include col(4);

    или подобных им? чище же и понятнее в 100 раз.

    В общем, сорри за негатив, но я не понял в чём суть вашего решения.

    Звучит так "мы не смогли заставить дизайнеров рисовать норм макеты, поэтому придумали собственную грид-систему, которую дизайнеры, почему-то, использовать будут, хотя она отличается от best-practise по грид-системам".


    1. igor_yakovlev Автор
      07.04.2022 13:55
      -1

      Спасибо за ваши комментарии и интерес к теме!

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

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


      1. linuxoid
        07.04.2022 19:26

        Простите, вы пишете в личном блоге, из-под аккаунта с личным именем. Почему "мы"? Вы - особа королевской крови или вас там много? :)

        /сноб=офф


        1. igor_yakovlev Автор
          07.04.2022 19:28
          -1

          В нашей компании все королевской крови :)


    1. gBACTAKAHA
      07.04.2022 18:18
      -1

      Верстать с калькулятором? Сложные макеты делали? Когда верстка вообще по golden ratio? Калькулятор обязателен. Бутстрап? Тянуть кучу всякой фигни ненужной когда весь лайаут пишется в 100 строк и так как нужно тебе.


  1. monochromer
    07.04.2022 14:39
    +2

    Проверьте сниппеты кода, явно какая-то дичь:


    1. igor_yakovlev Автор
      07.04.2022 15:23
      -1

      спасибо, что заметили наши опечатки!
      мы все проверили и исправили