Респонсивная раскладка без медиа-запросов
Допустим, у нас классический случай: сайдбар и область с основным контентом. Как мы раньше верстали такую конструкцию? Задавали им ширину и ставили рядом с помощью 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;
}
Вот так просто. Никаких лишних телодвижений, никаких заморочек с медиа-запросами. Просто работает.
Кстати, эти примеры отлично отвечают на вопрос «Что лучше использовать, гриды или флексы?». Он в корне неверен. Не нужно выбирать что-то одно. Гриды не заменяют флексы. Их прекрасно можно использовать совместно. Можно общую раскладку сделать по вышеуказанному методу на флексах, а внутри блока с основным контентом для сетки использовать гриды. Выбирайте инструменты исходя из задачи.