Chrome: контейнер сетки меняет высоту с разной скоростью относительно содержимого

Ниже приведен упрощенный (и преувеличенный) пример аккордеона, который использует сетку для изменения высоты содержимого.

Переход работает, но в Chrome ведет себя странно: контейнер (.accordion) начинает расти быстрее, чем содержимое, и содержимому требуется некоторое время, чтобы наверстать упущенное по высоте, поэтому во время перехода в нижней части контейнера появляется пробел (см. скриншот).

В Firefox все работает как положено.

Использование другой функции перехода (например, linear) влияет только на переход контейнера; несоответствие остается.

Является ли это ошибкой в ​​Chrome, и если да, то есть ли обходной путь?

.accordion {
    display: grid;
    grid-template-rows: minmax(0, 0fr) min-content;
    transition: grid-template-rows 3000ms;
    border: 1px solid;
    padding: 1rem;
}
    
.accordion.open {
    grid-template-rows: minmax(0, 1fr) min-content;
}
    
.content {
    overflow: hidden;
}
<div class = "accordion">
    <div class = "content">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores aut deserunt eaque incidunt labore laudantium minus nam omnis placeat quas quo, reprehenderit rerum soluta veritatis! Accusamus aliquam atque autem consequatur cumque, deserunt doloremque dolorum eaque eligendi esse est eum excepturi fugit hic impedit incidunt minus odit quae, ut voluptas.
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores aut deserunt eaque incidunt labore laudantium minus nam omnis placeat quas quo, reprehenderit rerum soluta veritatis! Accusamus aliquam atque autem consequatur cumque, deserunt doloremque dolorum eaque eligendi esse est eum excepturi fugit hic impedit incidunt minus odit quae, ut voluptas.
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores aut deserunt eaque incidunt labore laudantium minus nam omnis placeat quas quo, reprehenderit rerum soluta veritatis! Accusamus aliquam atque autem consequatur cumque, deserunt doloremque dolorum eaque eligendi esse est eum excepturi fugit hic impedit incidunt minus odit quae, ut voluptas.
    </div>
    <button onclick = "this.parentElement.classList.toggle('open');">toggle</button>
</div>

Связано, если не дублировать - stackoverflow.com/questions/43911880/…

Paulie_D 14.08.2024 15:06
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
CSS: FlexBox
CSS: FlexBox
Ранее разработчики использовали макеты с помощью Position и Float. После появления flexbox сценарий полностью изменился.
4
1
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Завернуть и извлечь

Я бы хотел избежать анимации grid-template-rows при использовании значений меньше 1fr и когда высота сетки зависит от высоты контента.
Обертывание новым элементом div и извлечение кнопки из сетки — одно из решений, которое должно сработать.

.accordion {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 3000ms;
  overflow: hidden; 
  align-items: flex-start;
  /* stretch is causing strange behavior, flex-start forces the element to have predictable height*/
}

.content {
  overflow: hidden;
}

.accordion.open {
  grid-template-rows: 1fr;
}

.wrapper {
  border: 1px solid;
  padding: 1rem;
}

button {
  width: 100%
}
<div class = "wrapper">
  <div class = "accordion">
    <div class = "content">
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores aut deserunt eaque incidunt labore laudantium minus nam omnis placeat quas quo, reprehenderit rerum soluta veritatis! Accusamus aliquam atque autem consequatur cumque, deserunt
      doloremque dolorum eaque eligendi esse est eum excepturi fugit hic impedit incidunt minus odit quae, ut voluptas. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores aut deserunt eaque incidunt labore laudantium minus nam
      omnis placeat quas quo, reprehenderit rerum soluta veritatis! Accusamus aliquam atque autem consequatur cumque, deserunt doloremque dolorum eaque eligendi esse est eum excepturi fugit hic impedit incidunt minus odit quae, ut voluptas. Lorem ipsum
      dolor sit amet, consectetur adipisicing elit. Aperiam asperiores aut deserunt eaque incidunt labore laudantium minus nam omnis placeat quas quo, reprehenderit rerum soluta veritatis! Accusamus aliquam atque autem consequatur cumque, deserunt doloremque
      dolorum eaque eligendi esse est eum excepturi fugit hic impedit incidunt minus odit quae, ut voluptas.
    </div>

  </div>
  <button onclick = "this.parentElement.children[0].classList.toggle('open');">toggle</button>
</div>

Другие решения также могут соответствовать вашим потребностям. Кажется, вы реализуете обходной путь для анимации height: auto. Есть и другие обходные пути с другими компромиссами.
IE height: calc-size(auto); перешел на chrome-canary, что должно облегчить переход с height: 0 на height: auto. Но внедрение для всех браузеров, безусловно, займет некоторое время.

Что происходит

Единицы Fr: займите часть доступного пространства.
При переходе с 0fr на 1fr. мы будем на 0.5fr на середине анимации.
В этот момент наши строки сетки будут 0.5fr + min-content для двух строк.
Общая высота сетки: высота контента + высота кнопки = 100%

Теперь мы подошли к самой сути (и несоответствию в реализации браузера).
Что такое 0,5фр или 50% доступного места? Общее пространство зависит от дочернего размера, а дочерний размер зависит от общего пространства.

  • Firefox: кажется, использует дочерний размер (т. е. 100px), и он равен общему размеру = 100px
  • Chrome: кажется, использует дочерний размер (100px), подсчитывает общую сумму (100px), а затем снова масштабирует дочерние элементы до «доступного пространства» (0.5fr, 50px)

Кто прав?
Не знаю, но мне больше подходит Firefox.
(Спорно) Хром! В спецификации это упоминается в определении «гибкого фактора»:

Примечание. Если сумма коэффициентов гибкости меньше 1, они займут только соответствующую часть оставшегося пространства, а не расширятся, чтобы заполнить все пространство.

В качестве примечания; fr единицы и minmax в основном полезны, когда есть какой-либо другой элемент, занимающий место. Если все единицы определены как fr, вы также можете использовать проценты.
например

  • 2 ряда: 1fr 1fr = 50% 50%.
  • 2 ряда: 0.5fr 1.5fr = 25% 75%
  • 2 строки minmax(200px, 1fr), 1fr = когда > 400 пикселей 50% 50%, когда < 400 200px remainder, этого невозможно добиться с помощью одних процентов.
  • 2 ряда minmax(0, 1fr), 1fr = неважно какой размер 50% 50%

Сравнение Chrome и Firefox:

  .accordion {
  width: 150px;
  display: grid;
  grid-template-rows: .5fr min-content;
  border: 1px solid;
  padding: 1rem;
  overflow: hidden;
}

.content {
  overflow: hidden;
}

.align-start {
  align-items: flex-start;
}

.example {
  margin: 50px;
  padding: 10px;
  background: linen;
<div class = "example">Example: .5fr
  <div class = "accordion">
    <div class = "content">
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores aut deserunt eaque incidunt labore laudantium minus nam omnis placeat quas quo, reprehenderit rerum soluta veritatis! Accusamus aliquam atque autem consequatur cumque, deserunt
      doloremque dolorum eaque eligendi esse est eum excepturi fugit hic impedit incidunt minus odit quae, ut voluptas.
    </div>
    <button onclick = "this.parentElement.classList.toggle('open');">toggle</button>
  </div>
</div>

<div class = "example">
  Example: .5fr with 'align-items: flex-start'
  <div class = "accordion align-start">
    <div class = "content">
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores aut deserunt eaque incidunt labore laudantium minus nam omnis placeat quas quo, reprehenderit rerum soluta veritatis! Accusamus aliquam atque autem consequatur cumque, deserunt
      doloremque dolorum eaque eligendi esse est eum excepturi fugit hic impedit incidunt minus odit quae, ut voluptas.
    </div>
    <button onclick = "this.parentElement.classList.toggle('open');">toggle</button>
  </div>
</div>


<div class = "example">
  Example: .5fr with 'align-items: flex-start' moved button out of grid
  <div class = "accordion align-start">
    <div class = "content">
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores aut deserunt eaque incidunt labore laudantium minus nam omnis placeat quas quo, reprehenderit rerum soluta veritatis! Accusamus aliquam atque autem consequatur cumque, deserunt
      doloremque dolorum eaque eligendi esse est eum excepturi fugit hic impedit incidunt minus odit quae, ut voluptas.
    </div>

  </div>
  <button onclick = "this.parentElement.classList.toggle('open');">toggle</button>
</div>

Ларс, блестящее объяснение! Спасибо

Zach Jensz 18.08.2024 14:14

Спасибо за ответ! Я думаю, что объяснение имеет смысл, и решение сработало. Однако мне пришлось использовать minmax(0, 0fr) и minmax(0, 1fr) вместо 0fr и 1fr, чтобы заставить его работать.

vvye 19.08.2024 14:15

Оказывается, Chrome (более) корректен в соответствии с актуальной спецификацией W3 (редакторский проект, 13 августа 2024 г.). Я обновил ответ. В качестве примечания: minmax будет иметь какой-либо эффект только в том случае, если есть строка, отличная от fr. minmax(0,0fr) — это просто 0, а minmax(0,1fr) будет равняться 1fr, если других строк нет. Я бы не особо беспокоился по этому поводу, если бы у вас это работало, это просто меня немного удивило.

Lars 19.08.2024 14:59

Другие вопросы по теме