Написать пост

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила 

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

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

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

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

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

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  1
Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  2

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

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

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

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

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

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

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

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

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

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  3

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

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  4

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

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

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  5

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

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  6

Мы видим, что масштабируется только ширина колонок, но не отступы колонок (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
Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  7

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

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  8
Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  9

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

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

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

Перейдём к практике. Мы используем препроцессор 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;
   }
}
		

результат:

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  10

Эти стили дают возможность сделать так, чтоб по нажатию на определённую клавишу на 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;
		

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

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  11

Подключаем 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.

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  12

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

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

			i {
   display: block;
   padding: percentage(9 / 16) 0 0;
   background: none no-repeat 50% 50%;
   background-size: cover;
}
		
Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  13
Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  14
Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  15

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

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

Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  16
Резиновая верстка: универсальная сетка под все брейкпоинты, примеры и правила  17

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 нам пришлось добавить обёртки над тэгом

. Основная логика заключена в следующей строке:
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.
Следите за новыми постами
Следите за новыми постами по любимым темам
12К открытий12К показов