Grid columns delay resizing on overflow
P粉638343995
P粉638343995 2023-09-06 21:25:59
0
1
594

I have a 2×2 CSS grid that fills the browser viewport using fixed positioning. It looks like this:

-----------------
| |xxxxxxxxxxxxx|
-----------------
|x|             |
|x|             |
|x|             |
|x|             |
-----------------

The top row and left column each fit their content and are sized auto. The bottom row and right column are used to occupy any remaining space and have size 1fr respectively.

The northeast and southwest cells (filled with Xs in the image) are both scrollable Flex parent cells. They contain any number of child elements, and that number may change dynamically. I set the overflow property of each property to auto and style the scrollbar using these rulesets:

.scrollable::-webkit-scrollbar {
  height: 10px;
  width: 10px;
}

.scrollable::-webkit-scrollbar-thumb {
  background: darkgray;
}

.scrollable::-webkit-scrollbar-track {
  background: #666666;
}

When I load the page in Chrome on macOS, the scrollbar overlays the contents of the southwest cell. Then when I resize the browser window, the left column expands to accommodate the scrollbar (which already appears as an overlay) and it moves to the right of the content.

I want the scrollbar to not cover the content at all, and I'd really like to eliminate layout shifting on irrelevant resize events. Do you know how I can achieve these goals?

This codepen is a minimal reproducible example. However, it doesn't look consistent to me. When I reload the page, sometimes the scrollbar is covered and sometimes the column is wide enough for the scrollbar to show up to the right of the content. I'm seeing the wrong coverage and sizing being more consistent on this standalone page.

P粉638343995
P粉638343995

reply all(1)
P粉502608799

To prevent this, the grid needs to update its dimensions and take scrollbars into account. Another question is how to do this using only css. I thought of applying animation for grid-template-columns and it seems to work:

* {
  box-sizing:border-box;
}

#grid {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto 1fr;
  animation: grid 200ms;
}

@keyframes grid {
  to {
    grid-template-columns: auto 2fr;
  }
}

#nw {
  background-color: green;
}

.scrollable {
  display: flex;
}

#ne {
  background-color: red;
  flex-direction: row;
  overflow-x: auto;
}

#sw {
  background-color: yellow;
  flex-direction: column;
  overflow-y: auto;
  scrollbar-color: darkgray #666666;
  scrollbar-width: thick;
}

#se {
  background-color: blue;
}

.box {
  width: 4em;
  height: 4em;
  margin: 5px;
  border-radius: 5px;
  background-color: black;
  flex-shrink: 0;
}

.scrollable::-webkit-scrollbar {
  height: 10px;
  width: 10px;
}

.scrollable::-webkit-scrollbar-thumb {
  background: darkgray;
}

.scrollable::-webkit-scrollbar-track {
  background: #666666;
}
<div id="grid">
  <div id="nw"></div>
  <div id="ne" class="scrollable">
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
  </div>
  <div id="sw" class="scrollable">
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
  </div>
  <div id="se"></div>
</div>

If you want to use JavaScript:

setTimeout(() => grid.style.gridTemplateColumns = 'auto 2fr', 200)
* {
  box-sizing:border-box;
}

#grid {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  display: grid;
  grid-template-rows: auto 1fr;
  grid-template-columns: auto 1fr;
}

#nw {
  background-color: green;
}

.scrollable {
  display: flex;
}

#ne {
  background-color: red;
  flex-direction: row;
  overflow-x: auto;
}

#sw {
  background-color: yellow;
  flex-direction: column;
  overflow-y: auto;
  scrollbar-color: darkgray #666666;
  scrollbar-width: thick;
}

#se {
  background-color: blue;
}

.box {
  width: 4em;
  height: 4em;
  margin: 5px;
  border-radius: 5px;
  background-color: black;
  flex-shrink: 0;
}

.scrollable::-webkit-scrollbar {
  height: 10px;
  width: 10px;
}

.scrollable::-webkit-scrollbar-thumb {
  background: darkgray;
}

.scrollable::-webkit-scrollbar-track {
  background: #666666;
}
<div id="grid">
  <div id="nw"></div>
  <div id="ne" class="scrollable">
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
  </div>
  <div id="sw" class="scrollable">
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
    <div class="box"></div>
  </div>
  <div id="se"></div>
</div>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template