За обновлениями можно следить в telegram-канале https://t.me/quasiart

Наверняка каждый опытный верстальщик сталкивался с вопросом: как анимировать изменение высоты блока с 0 до auto и наоборот. Это частая задача при разработке аккордеонов и других разворачивающихся при взаимодействии элементов.

В этой статье я рассмотрю три решения и приложу пример рабочего аккордеона, плавно меняющего высоту при наведении.

Демо

Наведи на меня

Первый абзац

Второй абзац

Третий абзац

Четвёртый абзац

Пятый абзац

Разметка

Начнём с HTML. Код для демонстрации следующий:

<div class="accordion">
  <div class="accordion-title">Наведи на меня</div>
  <div class="accordion-body">
    <div>
      <p>Текст внутри аккордеона</p>
    </div>
  </div>
</div>

Попытка №1 (тщетная)

Наверняка каждый пробовал просто добавить transition для свойства height:

.accordion-body {
  height: 0;
  transition: 500ms height ease;
}

.accordion:hover .accordion-body {
  height: auto;
}

К сожалению, CSS не позволяет анимировать автоматически вычисляемую высоту, так как браузер в данном случае не знает точной высоты, до которой нужно увеличить элемент. Подробнее можно почитать в спецификации: https://drafts.csswg.org/web-animations-1/#the-animationeffect-interface («that simply means that an auto value is replaced by zero»)

Попытка №2 (не идеальная)

А что, если анимировать max-height?

.accordion-body {
  max-height: 0;
  transition: 500ms max-height ease;
}

.accordion:hover .accordion-body {
  max-height: 200px;
}

Так как браузер знает конкретное значение свойства (max-height), то он сможет его анимировать.

Но есть проблема: контент может не уместиться в указанную высоту. Если этот нюанс не доставит неудобств, то это вполне приемлемый вариант анимирования высоты блока.

Попытка №3 (успешная)

Мы можем использовать изящный трюк, который заключается в создании грида с одним элементом сетки. Этот трюк работает только из-за анимируемости строк грида.

.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;
}

Нюанс: необходимо для div внутри .accordion-body установить overflow: hidden, чтобы сработало.

Учтите, что анимирование свойства grid-template-rows поддерживается не всеми браузерами: