CSS-трюк: переход height с 0 на auto
Если вы возились с CSS достаточно долго, скорее всего, вы хотя бы один раз пытались перейти от height: 0
к auto
, но это не работает! К счастью, сегодня действительно есть решение этой проблемы: под капотом используется CSS Grid, и это очень просто и работает безупречно!
Начнем с практического примера. Я построил этот простой аккордеон:
HTML для него довольно прост:
<div class="accordion">
<div class="accordion-title">Hover me!</div>
<div class="accordion-body">
<div>
<p>Lorem ipsum ...</p>
</div>
</div>
</div>
Если вы наведете указатель мыши на аккордеон, вы заметите, что появляется раскрывающийся список. Это круто, но что, если мы хотим, чтобы это появлялось с красивым плавным переходом?
На самом деле я пытался сделать это в предыдущем коде, добавив небольшой переход к свойству height
:
.accordion-body {
height: 0;
transition: 500ms height ease;
}
.accordion:hover .accordion-body {
height: auto;
}
К сожалению, это не работает: переход от height: 0
к height: auto
, как я говорил ранее, с помощью CSS невозможен.
Как это решить?
Что ж, первым решением может быть установка height
для свойства фиксированного числа вместо auto
.
Это сработало бы, но это не такой уж хороший подход: чтобы вычислить это фиксированное число, нам пришлось бы прибегнуть к JavaScript, чтобы вычислить, насколько наша .accordion-body
высота на самом деле. Это не совсем то, к чему мы стремились!
Можем ли мы добиться этого эффекта, но с помощью решения, использующего только CSS?
На самом деле да! Почему бы нам просто не использовать max-height
вместо этого?
.accordion-body {
max-height: 0;
transition: 500ms max-height ease;
}
.accordion:hover .accordion-body {
max-height: 200px;
}
Вот результат:
Поскольку мы определяем фиксированное значение для max-height
, браузер теперь может правильно выполнить переход.
Единственная проблема заключается в том, что, поскольку мы определяем фиксированное значение для max-height
, теперь содержимое потенциально может переполниться:
Если вы уверены, что ваш контент всегда будет таким, что никогда не достигнет определенной высоты, тогда вполне можно использовать этот метод! Просто используйте подходящее значение для max-height
, и все готово.
Однако имейте в виду, что чем выше значениеmax-height
, тем страннее становится переход (попробуйте добавить max-height: 1000px
в предыдущий код и посмотрите, как все изменится!).
Можем ли мы сделать лучше? Можем ли мы вообще избежать каких-либо фиксированныхheight
/max-height
?
CSS Grid приходит на помощь! На самом деле мы можем использовать изящный трюк, который по сути заключается в создании CSS-сетки из одного элемента сетки.
Все, что нам действительно нужно сделать, это взять grid-template-rows
и сделать переход от 0fr
к 1fr
: таким образом, наш элемент сетки перейдет от 0 к своей «естественной» высоте. Это так просто:
.accordion-body {
display: grid;
grid-template-rows: 0fr;
transition: 250ms grid-template-rows ease;
}
.accordion:hover .accordion-body {
grid-template-rows: 1fr;
}
.accordion-body > div {
overflow: hidden;
}
Это кажется намного чище. Никаких фиксированных высот, никаких причудливых вещей, просто наш аккордеон работает как положено. Замечательный!
Единственное предостережение в этом решении заключается в том, что вам действительно нужно установить overflow: hidden
для .accordion-body
внутреннего устройства div
, чтобы это работало. На мой взгляд, этот небольшой дополнительный CSS того стоит.
Этот трюк работает только из-за возможности анимации grid-template-rows
(и, в более общем плане, дорожек сетки).
Это довольно новая функция для некоторых браузеров: если вы посетите эту страницу, вы заметите, что анимация сеточных дорожек — это то, что, например, появилось в Chrome только начиная с версии 107.
На момент написания этой статьи все основные браузеры поддерживают эту функцию, но всегда сначала проверяйте совместимость, если вы хотите использовать эту функцию в рабочем коде!