FRONTEND BLOG

Респонсивная раскладка без медиа-запросов

Допустим, у нас классический случай: сайдбар и область с основным контентом. Как мы раньше верстали такую конструкцию? Задавали им ширину и ставили рядом с помощью float. А потом на необходимом размере убирали float:

@media (max-width: 20rem) {  .sidebar, .main-content {    width: 100%;    float: none;  }}

А теперь сделаем то же самое на флексах и избавимся от медиа-запроса. Для начала откажемся от размеров и примем, что ширина сайдбара должна быть не менее 300px, а ширина блока с основным контентом — не менее 60% родительского элемента:

.section { /* родительский блок */  display: flex;  flex-wrap: wrap;}.main-content {  min-width: 60%;}.sidebar {  flex-basis: 300px;}

Теперь нам нужно быть уверенными, что сайдбар и основной контент получат необходимую ширину, а если поставить их друг под друга, то займут всю доступную ширину. Поэтому для сайдбара мы пропишем flex-grow: 1;, а для основного контента — flex-grow: 9999;. Откуда 9999? Всё очень просто. Если мы напишем основному контенту flex-grow: 1;, то в итоге его ширина будет 60% от родителя, а остальное место займёт сайдбар, у которого тоже flex-grow: 1;. Но нам же нужно, чтобы ширина сайдабара была только 300px. И здесь полезно вспомнить как вообще работает flex-grow. Он делит между элементами, для которых он указан, свободное место, оставшееся после определения размеров и размещения всех остальных элементов внутри флекс-контейнера. Допустим, у нас остаётся свободными 100px. Для одного элемента мы указываем flex-grow: 1;, а для другого flex-grow: 3. Это означает, что первый элемент получит 1/4 от 100px (25px), а второй — 3/4(75px). Теперь понятнее, да? Когда мы указываем для основного контента flex-grow: 9999;, то сайдбар со своим flex-grow: 1; получает всего лишь 1/10000, что браузер округляет до 0. И так мы получаем необходимые размеры.

Полный код примера:

.section {  display: flex;  flex-wrap: wrap;}.main-content {  min-width: 60%;  flex-grow: 9999;}.sidebar {  flex-basis: 300px;  flex-grow: 1;}

А что делать, если нужно, чтобы между сайдбаром и основным контентом был отступ? Очень просто: добавить margin сайдбару и основному контенту и компенсировать его у родителя:

.section {  margin: -0.5rem;  display: flex;  flex-wrap: wrap;}.main-content {  margin: 0.5rem;  min-width: 60%;  flex-grow: 9999;}.sidebar {  margin: 0.5rem;  flex-basis: 300px;  flex-grow: 1;}

И ещё одно а что. А что, если нужно сделать респонсивную сетку для множества элементов, типа каталога? Тут во всей красе раскрывается grid. Достаточно всего пары строк кода:

.grid {  display: grid;  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));  grid-gap: 1rem;}

Вот так просто. Никаких лишних телодвижений, никаких заморочек с медиа-запросами. Просто работает.

Кстати, эти примеры отлично отвечают на вопрос «Что лучше использовать, гриды или флексы?». Он в корне неверен. Не нужно выбирать что-то одно. Гриды не заменяют флексы. Их прекрасно можно использовать совместно. Можно общую раскладку сделать по вышеуказанному методу на флексах, а внутри блока с основным контентом для сетки использовать гриды. Выбирайте инструменты исходя из задачи.