How to make all items the same width but as small as possible?

Viewed 294

Using flex or some alternative, how can I achieve the following?

  • Each item should be displayed side-by-side
  • The width of each item should be as small as possible, but large enough so that each item is of equal width
  • If all the items cannot fit on one row, the items should wrap appropriately

This is what I've tried so far: https://jsfiddle.net/nqyds03m/

.container {
  display: flex;
  width: max-content;
}

.item {
  border: 1px solid gray;
  margin: 0.25rem;
  flex: 1;
  flex-basis: 0;
}
<div class="container">
  <div class="item">
    An item with a lot of text indeed!
  </div>
  <div class="item">
    Short item
  </div>
</div>

The result is close enough, but not perfect. The items should be larger in the above example so that the text on the first item fits on one line, and the second item should grow to match the first.

I would like to avoid JavaScript if possible, but if a little JavaScript is necessary that is OK, as long as it remains performant like pure CSS.

2 Answers

Without wrapping we can easily do this with CSS grid:

.container {
  display: inline-grid;
  grid-auto-flow:column;
  grid-auto-columns:1fr;
}

.item {
  border: 1px solid gray;
  margin: 0.25rem;
}
<div class="container">
  <div class="item">
    An item with a lot of text indeed!
  </div>
  <div class="item">
    Short item
  </div>
</div>

To have wrapping, I think you will need some JS. Here is an idea where I will get the width of items then set a variable with that width.

document.querySelector('.container').style.setProperty("--w",document.querySelector('.item').offsetWidth+"px") 
document.querySelector('.container').style.display="grid";
.container {
  /* I need the below to have the same width for all the items
     then I will override it after getting that width */
  display: inline-block; 
  grid-template-columns:repeat(auto-fit,var(--w));
  grid-gap:0.5rem;
}

.item {
  border: 1px solid gray;
}
<div class="container">
  <div class="item">
    An item with a lot of text indeed!
  </div>
  <div class="item">
    Short item
  </div>
  <div class="item">
    another item
  </div>
</div>

Same idea using flexbox:

document.querySelector('.container').style.setProperty("--w",document.querySelector('.item').offsetWidth+"px") 
document.querySelector('.container').style.display="flex";
.container {
  /* I need the below to have the same width for all the items
     then I will override it after getting that width */
  display: inline-block;
  flex-wrap:wrap;
}

.item {
  width:var(--w);
  border: 1px solid gray;
  margin:0.25rem
}
<div class="container">
  <div class="item">
    An item with a lot of text indeed!
  </div>
  <div class="item">
    Short item
  </div>
  <div class="item">
    another item
  </div>
</div>

Use the column for vertical alignment with the inline-flex.

.container {
  display: inline-flex;
  flex-direction: column;
}
.item {
  flex: 0 1 auto;
  width: 100%;
  border: 1px solid gray;
  margin: 0.25rem;
}
<div class="container">
  <div class="item">
    An item with a lot of text indeed!
  </div>
  <div class="item">
    Short item
  </div>
</div>

Related