4

I have n children items in a container grid and each child can have different width.

  1. I want to arrange them in css grid such that each column width is equal.
  2. The width of column would be the maximum of the width among the children.

I would think

.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(max-content, 1fr));
}

will do it but it does not work:

.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(max-content, 1fr));
}
<div class="container">
  <div class="children"> Very long text </div>
  <div class="children"> long text </div>
  <div class="children"> text</div>
  <div class="children"> text</div>
  <div class="children"> text</div>
  <div class="children"> text</div>
</div>

In the case above, if only 2 columns fitted, I would expect the layout to be something below.

Very long text | long text     |
text           | text          |
text.          | text          | 

Similarly, if only 3 columns fitted, I would expect the layout to be something like below.

Very long text | long text     | text         |
text           | text          | text         | 

In both case above, "very long text" has the maximum max-content and it would determine the width of the columns.

What would be the easiest way to achieve this layout ?

  • 1
    If you inspect the `.container` element in your browser, you'll find that the `grid-template-columns` property-value is an invalid value; I can't remember exactly, but I believe that at least one of the values - that you've passed to `minmax()` - *must* be specified as a ab "absolute" length (whether in `em`, `px`, `%`...) but `1fr` can't be used alongside another value such as `max-content` (or `min-content`, `fit-content`...) – David Thomas Apr 15 '23 at 22:35
  • Yeah I noticed it but didn't know why. Your explanation makes sense. Thanks!! Any idea what might work instead ? I am now thinking it might not be possible without constraining the dimension of the largest width element/ or num of element per row as that would be the only way to introduce one absolute length – Suman Nepal Apr 15 '23 at 22:41
  • 2
    At least one value in `minmax()` must be a definite size (*"A size that can be determined without measuring content"*). In your code sample, `max-content` and `1fr` are both content-based sizes. That makes the rule invalid. As long as one value is definite, and the first value is not `fr`, the rule is valid. https://stackoverflow.com/questions/45333922/minmax-fails-invalid-property-value – Michael Benjamin Apr 15 '23 at 22:54
  • Also worth noting, [`mimax()` defaults to the *max* value](https://stackoverflow.com/q/50654400/3597276) – Michael Benjamin Apr 15 '23 at 22:57
  • Isn't this the perfect usecase for `display: flex` ?! – Sebi Apr 16 '23 at 00:59
  • I tried flex as well. Can you share what you are thinking ? In case there are 5 children, the last row will only have one element. I was having very hard time making the width of columns the same using flex when the elements wrap. I want the width of all children to be same and be of the max width among children. – Suman Nepal Apr 16 '23 at 17:11
  • related: https://stackoverflow.com/q/47601564 – djvg May 16 '23 at 12:37
  • Thank you everyone. So yeah turns out you cannot implicitly achieve this with css alone without constraining either the no of columns or width of the column - which means I had to use javascript to measure the max width among the children. After you get the max width of the children, you can set it anyway you like to achieve the desired outcome. One such way is the answer below. Other way is to use repeat for grid-column-template: repeat(x, maxWidth) where x = containerWidth/maxWidth. – Suman Nepal Jun 06 '23 at 03:41

1 Answers1

1

You indicated in the comments you'd be open to using flex, and if you're also open to using a little JavaScript, this should do the trick:

function calcMax()
{
    var container = document.getElementById("_container");
    var maxCell = Math.max(...[...container .children].map(ch=>ch.clientWidth));
    container.style.setProperty("--max-cell", maxCell.toString() + "px");
}
calcMax();
.container {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
}
.children {
    border: 1px solid black;
    min-width: var(--max-cell);      
}
<div id="_container" class="container">
    <div class="children"> Very long text </div>
    <div class="children"> long text </div>
    <div class="children"> text</div>
    <div class="children"> text</div>
    <div class="children"> text</div>
    <div class="children"> text</div>
</div>

Depending on what framework you're using and/or how you're rendering you may need to put a ResizeObserver on each cell to recalculate the max, or just make sure to calculate after each render.