CODEGURU

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

Допустим, у нас классический случай: сайдбар и область с основным контентом. Как мы раньше верстали такую конструкцию? Задавали им ширину и ставили рядом с помощью 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;
}

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

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