Search code examples
csscss-grid

Multiple CSS grids with shared auto-sized column widths


I have multiple divs on a page each configured for display: grid and grid-template-columns: auto auto auto. I would like each grid to share the same column widths, except using auto-fit behavior rather than hard coding pixel widths or using 1fr 1fr 1fr.

In other words I would like to achieve this:

Grids with shared column layout but placed/styled independently

where each column grows to he maximum content width measured across both grids (note the green lines are just to illustrate shared width layouts), instead of this:

Auto-fitted columns are totally independent between the two grids

where each respective grid's column widths are based only on their own child cells.

What I'm looking for is the equivalent of SharedSizeGroup in WPF Grid, for those who are familiar, or a workaround. Basically I would like both grids to be treated as one for purposes of auto-fitted columns but still be separate divs that can be placed and styled independently.

A CSS-only solution would be ideal, though I'm fairly sure none exists. I have no problem using Javascript, but even a Javascript solution eludes me short of abandoning grid completely and reinventing it.

Either way I need something reasonably scalable (i.e. I don't want to have to set any pixel widths by hand and don't want an ad-hoc solution that would only work for specific layout scenarios).

Is this possible?


Solution

  • Ensure all the items are in the same grid. Have the content be inside the grid but expanded across all the grid column tracks.

    <div style="display: grid; grid-template-columns: repeat(3, auto);">
      <div>Auto</div>
      <div>Auto</div>
      <div>Auto</div>
      <div>AAAAAAAAAAAAAAAAAAAAAA</div>
      <div>BB</div>
      <div>CCCCCCCCC</div>
      <div>AAAAA</div>
      <div>BBBBBBBBBBBBBBBBB</div>
      <div>CCCCCCCCCCCCC</div>
      <div>AAA</div>
      <div>BBBBBBB</div>
      <div>CCCCCCCCCCCCCCCCCC</div>
    
      <div style="grid-column: 1 / -1; padding: 2em; text-align: center">Other content</div>
    
      <div>Auto</div>
      <div>Auto</div>
      <div>Auto</div>
      <div>AAAA</div>
      <div>BBBBBBB</div>
      <div>CCCCCCCCC</div>
      <div>AAAAAAAAA</div>
      <div>BB</div>
      <div>CCCCCCCCC</div>
      <div>AAAAAAAAAAAA</div>
      <div>BBBBBBB</div>
      <div>CCCCC</div>
    </div>

    Edit in response to comment

    You would need to "sync" the grid column tracks with JavaScript. Here, I use the first three elements of the first row of the first table to detect the grid column track widths, and then pass these as the grid-template-columns value on the second grid.

    document.querySelector('.js-grid-to').style.gridTemplateColumns =
      [...document.querySelector('.js-grid-from').children]
        .slice(0, 3)
        .map((element) => `${element.getBoundingClientRect().width}px`)
        .join(' ');
    <div class="js-grid-from" style="display: grid; grid-template-columns: repeat(3, auto);">
      <div>Auto</div>
      <div>Auto</div>
      <div>Auto</div>
      <div>AAAAAAAAAAAAAAAAAAAAAA</div>
      <div>BB</div>
      <div>CCCCCCCCC</div>
      <div>AAAAA</div>
      <div>BBBBBBBBBBBBBBBBB</div>
      <div>CCCCCCCCCCCCC</div>
      <div>AAA</div>
      <div>BBBBBBB</div>
      <div>CCCCCCCCCCCCCCCCCC</div>
    </div>
    
    <div style="padding: 2em; text-align: center">Other content</div>
    
    <div class="js-grid-to" style="display: grid">
      <div>Auto</div>
      <div>Auto</div>
      <div>Auto</div>
      <div>AAAA</div>
      <div>BBBBBBB</div>
      <div>CCCCCCCCC</div>
      <div>AAAAAAAAA</div>
      <div>BB</div>
      <div>CCCCCCCCC</div>
      <div>AAAAAAAAAAAA</div>
      <div>BBBBBBB</div>
      <div>CCCCC</div>
    </div>