DevGang
Авторизоваться

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.

На момент написания этой статьи все основные браузеры поддерживают эту функцию, но всегда сначала проверяйте совместимость, если вы хотите использовать эту функцию в рабочем коде!

Источник:

#CSS
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться