2

I'm having a hard time understanding the logic behind the column gap in a multi-column layout. I have the following HTML/CSS in this Fiddle:

<div class="flex-container">
  <div class="flex-item">1</div>
  <div class="flex-item">2</div>
</div>
.flex-container {
  height: 500px;
  width: 300px;
  border: 1px solid blue;
  columns: 120px;
  padding: 10px;
}

.flex-item {
  background: OliveDrab;
  padding: 5px;
  width: 100px;
  height: 100px;
  line-height: 100px;
  color: white;
  text-align: center;
  break-inside: avoid-column;
}

You will notice that if you change the width of the container from 300px to 400px, the gap between the columns actually shrinks.

enter image description here

Why is it doing this? Is it possible to left-align the columns so they don't move around? Fixed gap between CSS columns may suggest that's not possible.

Garrett
  • 4,007
  • 2
  • 41
  • 59

2 Answers2

3

If you don't specify a column-count (the second parameter to columns) then the system will work out the number of columns possible (i.e. it takes auto as the column-count parameter).

You have specified an 'ideal' column width of 120px and the actual items have a width less than that. Therefore the system reckons you can get 3 columns into the container of width 400px and lays out the first two accordingly.

Here's some info from https://developer.mozilla.org/en-US/docs/Web/CSS/column-width

The column-width CSS property sets the ideal column width in a multi-column layout. The container will have as many columns as can fit without any of them having a width less than the column-width value. If the width of the container is narrower than the specified value, the single column's width will be smaller than the declared column width.

If you want to make sure there are just two columns then give the second parameter:

columns: 120px 2;

.flex-container {
  height: 500px;
  width: 400px;
  border: 1px solid blue;
  columns: 120px 2;
  padding: 10px;
}

.flex-item {
  background: OliveDrab;
  padding: 5px;
  width: 100px;
  height: 100px;
  line-height: 100px;
  color: white;
  text-align: center;
  break-inside: avoid-column;
}
<div class="flex-container">
  <div class="flex-item">1</div>
  <div class="flex-item">2</div>
</div>
A Haworth
  • 30,908
  • 4
  • 11
  • 14
  • the trick is that the column-width:120px isn't respected. It's only a min boundary used. The final width is bigger – Temani Afif Jan 06 '21 at 16:05
  • @TemaniAfif - yes, thanks, though I'm not sure exactly of the definition of 'ideal' or 'minimum boundary'- it's described in MDN documentation as 'ideal' - perhaps that's the same as a min boundary? I've added the link and quote in case of help to people. – A Haworth Jan 06 '21 at 16:13
  • Thanks! That explains why the observed behavior. In terms of specifying the number of columns, I can't do that because I want it to depend on the width, but I guess having fixed width columns and fixed gap, but flexible number of columns [is impossible](https://stackoverflow.com/questions/9105384/fixed-gap-between-css-columns)? – Garrett Jan 06 '21 at 16:48
  • 1
    @Garrett added a solution to my answer if intrested – Temani Afif Jan 06 '21 at 19:21
2

The column layout is a bit tricky. If you read the specification related to column-width you can find:

describes the optimal column width. The actual column width may be wider (to fill the available space), or narrower (only if the available space is smaller than the specified column width). ref

Remove the width from the elements and resize the container to notice this:

.flex-container {
  width: 400px;
  border: 1px solid blue;
  columns: 120px;
  padding: 10px;
  overflow:hidden;
  resize:horizontal;
}

.flex-item {
  background: OliveDrab;
  padding: 5px;
  height: 100px;
  line-height: 100px;
  color: white;
  text-align: center;
  break-inside: avoid-column;
}
<div class="flex-container">
  <div class="flex-item">1</div>
  <div class="flex-item">2</div>
</div>

You will notice that the gap is indeed fixed but the width of columns is changing.

You can find more details around the algorithm here: https://drafts.csswg.org/css-multicol-1/#pseudo-algorithm


A solution is to consider the use of CSS grid having fixed column width. The trick is to define the width of the grid column to be equal to the gap+width of column and you make you container fill all the columns (its width will be a multiplier of gap+width of column)

Resize the screen to see the result:

.container {
  display:grid;
  grid-template-columns:repeat(auto-fit,140px); /* 120 + 20 */
  overflow: hidden;
  resize: horizontal;
  border: 1px solid blue;

}

.flex-container {
  grid-column:1/-1;
  column-width: 120px;
  column-gap: 20px;
  padding: 10px;
}

.flex-item {
  background: OliveDrab;
  padding: 5px;
  height: 100px;
  line-height: 100px;
  color: white;
  text-align: center;
  break-inside: avoid-column;
}
<div class="container">
  <div class="flex-container">
    <div class="flex-item">1</div>
    <div class="flex-item">2</div>
    <div class="flex-item">3</div>
    <div class="flex-item">4</div>
    <div class="flex-item">5</div>
    <div class="flex-item">6</div>
    <div class="flex-item">7</div>
    <div class="flex-item">8</div>
    <div class="flex-item">9</div>
    <div class="flex-item">10</div>
  </div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Awesome! I had to add a `overflow: hidden` to the items as workaround for a Firefox bug (detailed [here](https://stackoverflow.com/a/7785711/2223706)). – Garrett Jan 07 '21 at 00:29