Приводим сетку к продакшен-реди решению, изучаем адаптивность
Базовую версию сетки мы сделали. Напомню, где мы остановились:
iframe: https://jsfiddle.net/y29uhtbL/22/embedded/result,html,css/
- сделали 12 колонок,
- сделали
.row
, - сделали контейнер
.container
, чтобы фиксировать ширину контента
Но есть один нюанс: если мы зададим контейнеру бэкграунд, чтобы проверить как всё отработало, мы заметим один мерзкий баг — у контейнера есть отступы слева и справа.
iframe: https://jsfiddle.net/y29uhtbL/21/embedded/result,html,css/
Отступы есть по очевидной причине: у наших .col-*
-классов есть padding-left
и padding-right
. Но как от них избавиться только в контейнере?
В этом нам помогут отрицательные марджины. Отрицательные марджины — зло и показатель непонимания блочной модели, но любое зло всегда имеет право на реализацию в каких-то пограничных случаях (edge cases).
Мы повесим отрицательные марджины слева и справа на .row
:
.row {
margin-left: -8px;
margin-right: -8px;
}
iframe: https://jsfiddle.net/y29uhtbL/23/embedded/result,html,css/
Всё сразу же стало по красоте. Подчистим наш код, приведём в порядок — получим готовую сетку.
.container {
max-width: 976px;
}
.row {
display: flex;
flex-wrap: wrap;
margin-left: -8px;
margin-right: -8px;
}
.col-1,
.col-2,
.col-3,
.col-4,
.col-5,
.col-6,
.col-7,
.col-8,
.col-9,
.col-10,
.col-11,
.col-12 {
padding-left: 8px;
padding-right: 8px;
box-sizing: border-box;
}
.col-1 {
flex-basis: 8.3333%;
}
.col-2 {
flex-basis: 16.6666%;
}
.col-3 {
flex-basis: 24.9999%;
}
.col-4 {
flex-basis: 33.3333%;
}
.col-5 {
flex-basis: 41.6665%;
}
.col-6 {
flex-basis: 49.9998%;
}
.col-7 {
flex-basis: 58.3331%;
}
.col-8 {
flex-basis: 66.6664%;
}
.col-9 {
flex-basis: 74.9997%;
}
.col-10 {
flex-basis: 83.3333%;
}
.col-11 {
flex-basis: 91.6663%;
}
.col-12 {
flex-basis: 100%;
}
Красиво? Удобно? Да.
Резюмируя: мы не только поняли, что такое модульная сетка, но и научились сами её собирать на флексбоксах, разобрались, зачем нужен .row
и как вместить наш контент в фиксированный контейнер.
Кстати, частый кейс — как сделать бэкграунд во всю ширину, а контент — в контейнере? Я думаю, вы догадались об ответе, но всё-таки.
<style>
header {
background-color: #6041FB;
}
</style>
<header>
<div class="container">
<h1>Курс по вёрстке</h1>
</div>
</header>
Поговорим об адаптивности.
Когда делают сайты и веб-приложения, очень редко делают отдельные мобильные версии (типа mobile.twitter.com), чаще всего делают адаптивную вёрстку.
Что такое адаптивность? Способность приспосабливаться к изменениям. Адаптивная вёрстка? Способная приспосабливаться к изменениям!
Вы спросите: «да к каким изменениям-то?», а я отвечу «ко многим, но давайте разберемся с примитивами».
В ЦСС есть мощная штука медиакверис (media queries). Это условия, при которых выполняется, эээ, код, если ЦСС можно назвать таковым.
Семантика у неё простая:
@media <media-query-list> {
/* css */
}
Где <media-query-list>
это набор правил.
Всё просто: тип устройства. Нет, это не разграничение на айфоны и андроиды, макбуки и синкпады, это
all
— любое устройство,screen
— color computer screens,print
— стили для печати,speech
— скринридеры.
Примеры:
@media print {
body {
font-size: 10pt;
}
}
@media screen {
body {
font-size: 13px;
}
}
@media screen, print {
body {
line-height: 1.2;
}
}
Их очень много, но в основном используют min-width
— определить ширину экрана.
Примеры:
body {
color: orange;
}
@media (min-width: 768px) {
body {
color: red;
}
}
@media (min-width: 992px) {
body {
color: green;
}
}
@media (min-width: 1200px) {
body {
color: blue;
}
}
По-умолчанию (на маленьких устройствах) цвет текста будет оранжевым, при ширине от 768 пикселей — красным, от 992 пикселей — зеленым, а от 1200 — синим.
Как разобраться, какие размеры прописывать? Есть два способа: запомнить самые общие популярные параметры или подсматривать на screensiz.es.
Такие параметры называются брейкпоинтами (breakpoints, точки слома): точки, когда поведение должно поменяться. Но, например, Миша Капанага с этим не согласен и я тоже с ним соглашусь — всегда нужно смотреть на конкретном сайте и исправлять конкретные проблемы, просто популярные брейкпоинты помогают ориентироваться.
Так какие значения-то? Они бьются по размерам:
- xs это экраны до 576 пикселей (смартфоны),
- sm — от 576 до 768 (большие смартфоны и планшеты в вертикальной ориентации),
- md — от 768 до 991 (планшеты в горизонтальной),
- lg — от 991 до 1200 (десктопы),
- xl — от 1200 и выше (большие десктопы).
Есть небольшое уточнение: хоть и фактическая ширина тех же айфонов — 750 пикселей, она делится на два (375 пикселей) и вписываются в xs, потому что там Ретина. Как разобраться? Смотреть на значения pixel ratio
и CSS width
на сайте mydevice.io/devices.
Существует подход mobile first, когда вы учитываете сначала мобильные девайсы и постепенно увеличиваетесь.
Честно говоря, сам термин давно устарел, я бы его назвал low first — сначала мы разбираемся с возможностями слабых (маленьких) устройств, а потом наращиваем мощности.
В нашем примере выше мы сначала объявили body { color: orange; }
, а потом на брейкпоинтах ломали это значение, когда увеличивалась ширина экрана.
Примеры практики:
- на маленьких девайсах мы размеры заголовков ставим в 26 пикселей, а на больших можем разогнаться и поставить 72,
- на маленьких девайсах мы можем блоки разместить друг под другом (
display: block
), а на больших они вместятся рядом — поставимdisplay: inline-block
.
Поэтому всегда пишите код через mobile first: его легче будет дебажить (debug, отладка) и читать, он остаётся предсказуемым — ведь если мы видим чёткую нисходящую картину по размерам, то это легче понять, чем кучу свойств max-width
.
Плохо: тяжело читать.
@media (min-width: 1200px) {
body {
color: blue;
}
}
body {
color: orange;
}
@media (max-width: 992px) {
body {
color: green;
}
}
@media (max-width: 768px) {
body {
color: red;
}
}
Хорошо: правила идут по увеличению экранов.
body {
color: orange;
}
@media (min-width: 768px) {
body {
color: red;
}
}
@media (min-width: 992px) {
body {
color: green;
}
}
@media (min-width: 1200px) {
body {
color: blue;
}
}
Сделайте планшетную и мобильную версии UberEats.
Но дополнительное задание: вернемся к сетке — пора её сделать адаптивной!
Если мы останемся с нашими .col-*
, то у нас будут проблемы: на xs нам нужны элементы, которые идут друг за другом, на md они могут вместиться по 2 на строку, а на lg — вообще по 4 в одну строку. Текущая сетка этого не поддерживает.
Задание: сделать классы .col-[size]-*
, где size
это брейкпоинты.
Примеры использования:
<div class="row">
<div class="col-xs-11 col-md-6 col-lg-3">test</div>
<div class="col-xs-11 col-md-6 col-lg-3">test</div>
</div>
<div class="row">
<div class="col-xs-11 col-sm-4 col-xl-2">test</div>
<div class="col-xs-11 col-sm-4 col-xl-2">test</div>
</div>
Кстати, в первом примере я опустил sm
значение, а во втором — md
. Почему?
Потому что действует тот же принцип mobile first: то, что объявлено ниже, наследуется, пока не встретится брейкпоинт.
Не забывайте задавать вопросы в чате — там обязательно помогут 💪🏻
Помните: нет глупых вопросов, есть лишь страх их задавать.
Подсказка:
.col-xs-7 {
flex-basis: 58.3331%;
}
... @media (min-width: 768px) {
.col-md-3 {
flex-basis: 24.9999%;
}
}
Мы доделали сетку: исправили баг с контейнером и разобрались, когда нужно использовать отрицательные марджины.
Плюс изучили адаптивность через медиакверис и познакомились с принципом mobile first.