Страшная правда о gap
в CSS
Самый базовый юзкейс для флексбокса: расположить в блоке энное количество элементов по какому-то шаблону. Преимущество именно флексбокса в том, что размеры элементов будут автоматически подстраиваться под размер родительского блока (примеру ниже можно менять размер).
Один из самых базовых шаблонов: элементы все одинакового размера и стоят по строчкам.
Для того, чтобы задать отступы между элементами, используется css-свойство gap
. Но он имеет одну страшную особенность, об которую обязательно спотыкается всякий, кто пытается использовать gap
в первый раз.
Вот, казалось бы, логичный код:
.parent {
display: flex; /* отображать по флексу */
flex-wrap: wrap; /* переносить строки */
gap: 0.5em; /* интервал между элементами */
}
.child {
flex-basis: 25%; /* каждый элемент занимает 25% (¼) строки */
height: 2em;
}
Однако он выдаст вот такой результат:
В строке поместилось всего три элемента, а четвёртый уехал на следующую. Почему так вышло? А вот и настало время раскрыть грязный секрет...
Оно всё работает так, что сначала элементу задаётся размер 25%
, а потом к этому размеру прибавляется отступ. Соответственно, при отрисовке получается, что элемент занимает не 25%
, а 25% + 0.5em * 0.75
, где 0.75
это три отступа, которые должны быть между четырьмя элементами. Поскольку второе больше, чем первое, последний элемент переносится на следующую строку, так как в свою он не влезает.
Чтобы компенсировать эти 0.5em * 0.75
, надо написать следующий довольно уродливый код:
.parent {
display: flex;
flex-wrap: wrap;
gap: 0.5em;
}
.child {
flex-basis: calc(25% - 0.5em * 0.75); /* изменение тут */
height: 2em;
}
Если есть задача сделать так, чтобы на разных размерах экрана было разное количество элементов в строке, нужно использовать такую формулу:
flex-basis = (100% / perRow) - gap * (1 - 1 / perRow)
А на самом деле, конечно, промежутки между элементами не должны учитываться в их размере. Я не знаю, зачем такое поведение сделано, но каждый раз писать эту формулу-мантру — бред.
5 октября 2023 Указатель