Getting CSS columns to bunch on the left instead of spreading out

Viewed 109

How do I get CSS columns to not spread out but instead bunch on the left

What I get

enter image description here

What I want

enter image description here

Example

body {
  background-color: #c3dbff;
}
.cols {
  columns: 250px;  /* want however many 250px columns will fit */
}
.thing {
  display: inline-block;
  width: 240px;
  background: red;
  margin-bottom: 10px;
  break-inside: avoid-column;
  
  
  /* below just to make it clear the order of children in the columns */
  color: white;
  display: inline-grid;
  place-content: center;
  font-weight: bold;
  font-family: sans-serif;
  font-size: 50pt;
}
<div class="cols">
  <div class="thing" style="height: 200px;">1</div>
  <div class="thing" style="height: 200px;">2</div>
  <div class="thing" style="height: 290px;">3</div>
  <div class="thing" style="height: 280px;">4</div>
  <div class="thing" style="height: 200px;">5</div>
  <div class="thing" style="height: 230px;">6</div>
  <div class="thing" style="height: 260px;">7</div>
  <div class="thing" style="height: 210px;">8</div>
  <div class="thing" style="height: 280px;">9</div>
  <div class="thing" style="height: 230px;">10</div>
  <div class="thing" style="height: 260px;">11</div>
  <div class="thing" style="height: 210px;">12</div>
  <div class="thing" style="height: 200px;">13</div>
  <div class="thing" style="height: 270px;">14</div>
  <div class="thing" style="height: 220px;">15</div>
  <div class="thing" style="height: 260px;">16</div>
  <div class="thing" style="height: 250px;">17</div>
  <div class="thing" style="height: 290px;">18</div>
</div>

CSS only.

Things I tried,

  • setting column-width: 250px. ❌

  • setting the outer container to display: inline-block;

  • setting the outer container to margin: 0 auto 0 0

  • setting column-gap: 10px

  • setting display: flex; flex-direction: column; flex-wrap: wrap

    This doesn't work because in order to wrap I'd have to give the flex box a height, otherwise it has no idea it needs to wrap. That's different that columns which will figure out height after figuring out how many columns.

One thing that makes it hard to find an answer is most results about columns are not about the css columns property but about columns in tables, or grids, or flexbox

PS: No, I'm not trying to do a masonry layout out. I want the items to go down the first column, then flow into the second (vs masonry where they flow to the right first and then fill in the shortest column. not looking for that).

3 Answers

It seems your items has fixed sizes so you can use CSS grid to fix this. The trick is to create as many columns with fixed width as possible and span all of them using grid-column: 1/-1

body {
  background-color: #c3dbff;
}


.wrapper {
  display:grid;
  grid-template-columns:repeat(auto-fit,250px); /* same as column width */
  gap:10px; /* same as column gap */
}

.cols {
  columns: 250px;
  column-gap: 10px;
  grid-column:1/-1; /* take all the columns of the grid*/
}

.thing {
  display: inline-block;
  width: 100%; /* use 100% and rely on the gap */
  background: red;
  margin-bottom: 10px;
  break-inside: avoid-column;
  color: white;
  display: inline-grid;
  place-content: center;
  font-weight: bold;
  font-family: sans-serif;
  font-size: 50pt;
}
<div class="wrapper">
  <div class="cols">
    <div class="thing" style="height: 200px;">1</div>
    <div class="thing" style="height: 200px;">2</div>
    <div class="thing" style="height: 290px;">3</div>
    <div class="thing" style="height: 280px;">4</div>
    <div class="thing" style="height: 200px;">5</div>
    <div class="thing" style="height: 230px;">6</div>
    <div class="thing" style="height: 260px;">7</div>
    <div class="thing" style="height: 210px;">8</div>
    <div class="thing" style="height: 280px;">9</div>
    <div class="thing" style="height: 230px;">10</div>
    <div class="thing" style="height: 260px;">11</div>
    <div class="thing" style="height: 210px;">12</div>
    <div class="thing" style="height: 200px;">13</div>
    <div class="thing" style="height: 270px;">14</div>
    <div class="thing" style="height: 220px;">15</div>
    <div class="thing" style="height: 260px;">16</div>
    <div class="thing" style="height: 250px;">17</div>
    <div class="thing" style="height: 290px;">18</div>
  </div>
</div>

Update:

Actually this solution doesn't work. The problem is just because the column size is N and the outer size is N * 3 does not mean the browser will chose to make 3 columns. For example, if there are only 2 items it will make 2 columns because why make 3? But when it makes 2 it ends up distributing the space. So this isn't a solution AFAICT.

Previous answer:

I did think of one poor solution. If container queries worked then I could make

<div id="outer">
  <div id="inner">
    <div></div>
    <div></div>
    <div></div>
  </div>
</div>

And then do queries on outer to force inner to only be multiples of the size I want the columns.

Since I don't have container queries, then I can use media queries. It kind of sucks because I can't use calc and it only works if the out container can be fit to the page.

body {
  background-color: #c3dbff;
  margin: 0;
}
.cols {
  columns: 250px;  /* want however many 250px columns will fit */
  column-gap: 0px;
}
.thing {
  display: inline-block;
  width: 240px;
  background: red;
  margin-bottom: 10px;
  break-inside: avoid-column;
  
  /* below just to make it clear the order of children in the columns */
  color: white;
  display: inline-grid;
  place-content: center;
  font-weight: bold;
  font-family: sans-serif;
  font-size: 50pt;
}

@media (max-width: 2249px) { .cols { width: 2000px; } }
@media (max-width: 1999px) { .cols { width: 1750px; } }
@media (max-width: 1749px) { .cols { width: 1500px; } }
@media (max-width: 1499px) { .cols { width: 1250px; } }
@media (max-width: 1249px) { .cols { width: 1000px; } }
@media (max-width: 999px) { .cols { width: 750px;   } }
@media (max-width: 749px) { .cols { width: 500px;   } }
@media (max-width: 499px) { .cols { width: 250px;  margin-right: 10px; } }
<div class="cols">
  <div class="thing" style="height: 200px;">1</div>
  <div class="thing" style="height: 200px;">2</div>
  <div class="thing" style="height: 290px;">3</div>
  <div class="thing" style="height: 280px;">4</div>
  <div class="thing" style="height: 200px;">5</div>
  <div class="thing" style="height: 230px;">6</div>
  <div class="thing" style="height: 260px;">7</div>
  <div class="thing" style="height: 210px;">8</div>
  <div class="thing" style="height: 280px;">9</div>
  <div class="thing" style="height: 230px;">10</div>
  <div class="thing" style="height: 260px;">11</div>
  <div class="thing" style="height: 210px;">12</div>
  <div class="thing" style="height: 200px;">13</div>
  <div class="thing" style="height: 270px;">14</div>
  <div class="thing" style="height: 220px;">15</div>
  <div class="thing" style="height: 260px;">16</div>
  <div class="thing" style="height: 250px;">17</div>
  <div class="thing" style="height: 290px;">18</div>
</div>

Apparently, at least in Chrome, when the column goes to a single column the margin-bottom setting is ignored.

try using display flex. set up justify-content to flex-start, align items to the centre and flex-wrap to wrap. and give a justifiable width and avoid using inline styles.

Related