Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome: grid container changes height at different rate from content

Below is a simplified (and exaggerated) example of an accordion that uses grid to transition the height of the content.

The transition works, but behaves weirdly in Chrome: the container (.accordion) starts growing quicker than the content, and it takes the content a while to catch up in height, so during the transition there's a gap at the bottom of the container (see screenshot).

In Firefox, everything works as expected.

Using a different transition function (e.g. linear) affects only the transition of the container; the discrepancy remains.

Is this a bug in Chrome, and if so, is there a workaround?

height transition discrepancy in 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>
like image 890
vvye Avatar asked Nov 17 '25 17:11

vvye


1 Answers

Wrap and extract

I would want to avoid animating grid-template-rows when using values of less then 1fr and having the grid-height depend on the content height.
Wrapping with a new div and extracting the button from the grid is one solution that should work.

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

Other solutions might also fit your need. It seems you're implementing a work-around for animating to height: auto. There's other work-arounds with different trade-offs.
IE height: calc-size(auto); landed in chrome-canary which should make a transition from height: 0 to height: auto easier, But adoption for all borwsers is surely going to take some time.

What is happening

Fr units: take a fraction of the available space.
While transitioning from 0fr to 1fr. we'll be at 0.5fr at the halfway mark of the animation.
At that point, our grid-rows will be 0.5fr + min-content for the 2 rows.
The total height of the grid: content height + button height = 100%

Now we've come the crux (and the discrepancy in browser implementation).
What is 0.5fr, or 50% of the available space? The total space is dependent on the child-size, and the child-size depends on total space.

  • Firefox: seems to use the child size (ie 100px), and have that be equal to the total size = 100px
  • Chrome: seems to use the child size (100px), calculate the total (100px) and then scale the children again to the 'available space' (0.5fr, 50px)

Who's correct?
I don't know, but the firefox one makes more sense to me.
(Arguably) Chrome! The specification mentions this at the definition of 'flex-factor':

Note: If the sum of the flex factors is less than 1, they’ll take up only a corresponding fraction of the leftover space, rather than expanding to fill the entire thing.

As a side note; fr units and minmax are mostly useful when there's any other element that is taking up space. If all units are defined as fr, you might as well use percentages.
for example

  • 2 rows: 1fr 1fr = 50% 50%.
  • 2 rows: 0.5fr 1.5fr = 25% 75%
  • 2 rows minmax(200px, 1fr), 1fr = when > 400px 50% 50%, when < 400 200px remainder, this can't be achieved with just percentages.
  • 2 rows minmax(0, 1fr), 1fr = no mater what size 50% 50%

Comparison between chrome and firefox: chrome-firefox-comparison

  .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>
like image 59
Lars Avatar answered Nov 20 '25 05:11

Lars



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!