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

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

Материал предназначен для дизайнеров и 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:

    : #00f;
    " class="formula inline">grid_margin: percentage(40 / 1920); // 40 / 1920  100%;
    : percentage(157 / (1920 - 40 * 2));
    " class="formula inline">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: ;
           right: " class="formula inline">grid_margin;
           background: repeating-linear-gradient(90deg,
                    0,
                   " class="formula inline">grid_color ,
                   transparent " class="formula inline">grid_width,
                   transparent  + " class="formula inline">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: " class="formula inline">grid_margin;
right: ;

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

background: repeating-linear-gradient(90deg,
               " class="formula inline">grid_color 0,
                " class="formula inline">grid_width,
               transparent ,
               transparent " class="formula inline">grid_width + );

Далее добавим обёртку .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 " class="formula inline">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:  * 5 + " class="formula inline">grid_gutter  4;

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

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

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

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

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

@include@content@mixin mq(, " class="formula inline">to: false) {
   @if  {
       @media (min-width: #{" class="formula inline">from}px) and (max-width: #{}px) {
           @content;
       }
   } @else {
       @media (max-width: #{" class="formula inline">from}px) {
           @include@content;
       }
   }
}

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

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

.column-item {
  …
     @include mq(767) {
       width: calc(#{} * 4 + #{" class="formula inline">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.

Источник: https://habr.com/ru/post/659477/


Интересные статьи

Интересные статьи

Привет! Меня зовут Саша Шутай, я тимлид в AGIMA. В прошлой статье я рассказывал, что делать, если на проекте Bitrix сожительствует с Vue.js и поисковые боты не видят контента сайта. А в этой помогу ра...
Heredes — библиотека для разработчиков Heredes — библиотека для облегчения решения ряда конкретных задач, связанных с прямым обменом данных в сети без использования ipv6. Из встроенных возможностей ...
Решения для больших компаний обычно должны выдерживать высокие нагрузки. Когда в штате много десятков тысяч человек, и значительная доля из них ежедневно пользуются ...
В 1С Битрикс есть специальные сущности под названием “Информационные блоки, сокращенно (инфоблоки)“, я думаю каждый с ними знаком, но не каждый понимает, что это такое и для чего они нужны
Это советы по улучшению UX ваших проектов БЕЗ многочасовых сессий по изучению пользовательского поведения, бумажного прототипирования или любых других модных словечек. (Серьёзно, поищите «диза...