5

I'm using the CSS multi-column layout for this layout:

enter image description here

I want the content to use as many columns as possible. It does that in the above image, but when there's only 3 items, it does the following:

enter image description here

I would like the box "3" to be to the right of box "2". Is that possible?

EDIT: looking for a general solution (this is a simplified example, we don't know the heights of the container or elements in advance).

EDIT 2: if there's a better way than using multi-column (perhaps grid?), we'd use that.

Here's the HTML/CSS (or jsfiddle here):

.container {
  column-width: 120px;
  column-gap: 20px;
  padding: 10px;
  width: 600px;
  height: 250px;
  border: 1px solid blue;
}

.item {
  
  background: #2371f3;
  padding: 5px;
  height: 100px;
  width: 100px;
  color: white;
  break-inside: avoid;
  /* Workaround for Firefox bug (https://stackoverflow.com/a/7785711/2223706) */
  overflow: hidden;
  border: 1px solid darkblue;
}

.longer {
  height: 220px; /* Decreasing this to 200px makes #2 and #3 no longer stack. */
}
<div class="container">
  <div class="item longer">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>
Garrett
  • 4,007
  • 2
  • 41
  • 59
  • Basically...no! For that you have to define the number of columns. – Paulie_D Jan 27 '21 at 22:38
  • In addition .. It would be possible with backend programming OR JavaScript to control the column layout based on the number of a specific class or element type etc etc – Zak Jan 27 '21 at 22:41
  • An example of a "work around" with a small amount of jQuery -- Changes the height of `.longer` to force the `float` -- [FIDDLE](https://jsfiddle.net/gnqLu8b3/) – Zak Jan 27 '21 at 22:59
  • @Paulie_D it seems defining the number of columns doesn't help either. In [this](https://jsfiddle.net/56c8f70h/) fiddle, I've modified the above by adding `column-count: 3;`, but it still doesn't want to spread the content out. – Garrett Jan 28 '21 at 00:11
  • @Zak thanks for that example, although in our use-case, we don't want to modify the height of the boxes, and it also relies on knowing the exact heights of the different boxes. – Garrett Jan 28 '21 at 00:13

2 Answers2

2

in chrome you can add this in your stylesheet at the end

.item:nth-child(n+3):last-child {
  background: #000;
  break-before: column;
}

if you have 3 items, the 3th item moves to the right, if a forth comes in then it goes back under 2nd.

if you have 5 items, the 5th item moves to the right, if a sixth comes in then it goes back under 4th.

but I cannot make it work on firefox, I think the column/break compatibility still is not that good on mozilla

Tch
  • 1,055
  • 5
  • 11
  • Thanks for the answer, although this won't work for our use case since it relies on the container and the items inside having specific heights (or more precisely that the heights are such that, exactly 2 element can fit per column) – Garrett Feb 01 '21 at 14:22
  • I would suggest you look at some kind of a grid system instead of `column` which is not very compatible with all browsers as yet, it will be a lot easier to customize to your needs I think – Tch Feb 01 '21 at 15:03
  • We can use `grid` since we don't support IE anymore, but haven't been able to figure it out yet using `grid` either. Edited question to reflect our openness to grid. – Garrett Feb 01 '21 at 17:52
  • would you also be able to provide us as to what the output should look like in various occasions? like if item2 is longer than item1 or if 3 is longer than item2 , if the width of the container or of the items will be standard, what happens if there are 7 items? – Tch Feb 01 '21 at 22:06
  • Sure, I think the best way I have to describe it is, just like multi-column layout, but that it always attempts to use all columns. If there were 7 items, it should look like the first image in my question. – Garrett Feb 02 '21 at 16:22
1

If the number of element is limited you can write some specific CSS to do it

.container {
  column-width: 120px;
  column-gap: 20px;
  padding: 10px;
  width: 600px;
  height: 200px;
  border: 1px solid blue;
}

.item {
  background: #2371f3;
  padding: 5px;
  height: 100px;
  width: 100px;
  color: white;
  display: inline-block;
  vertical-align: top;
  box-sizing:border-box;
  overflow: hidden;
  border: 1px solid darkblue;
}

/* we add some bottom margin to push the next element */
.item:nth-last-child(2):nth-child(even):not(:nth-child(6)),
.item:nth-last-child(3):nth-child(2),
.item:nth-last-child(2):nth-child(3){
  background: red;
  margin-bottom: 5px; /* any value from 1px to 50px can do the job */
}
/**/
.longer {
  height: 200px;
}
<div class="container">
  <div class="item longer">1</div>
  <div class="item">2</div>
</div>

<div class="container">
  <div class="item longer">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>

<div class="container">
  <div class="item longer">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
</div>

<div class="container">
  <div class="item longer">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
</div>

<div class="container">
  <div class="item longer">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
</div>

<div class="container">
  <div class="item longer">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • 1
    Extremely CLEVER – Zak Jan 27 '21 at 23:08
  • That is clever! Although won't work for our use-case because it also relies on the container and the items inside having specific heights (or more precisely, that the heights are such that, exactly 2 elements can fit per column). – Garrett Jan 28 '21 at 00:03
  • @Garrett the solution I provided doesn't consider the height. I used margin-bottom:50px as a radom value, even 1px will do the job. Any value will do the job – Temani Afif Jan 28 '21 at 00:15
  • 1
    @TemaniAfif, sorry should have attached to fiddle to explain what I mean. [Here](https://jsfiddle.net/0za8cnoj/1/), I've only modified one property (updating `.item` to have `height: 60px;`) and you can see that it no longer works. – Garrett Jan 28 '21 at 01:03
  • @Garrett you said *exactly 2 elements can fit per column*. In that fiddle 3 elements can fit per column – Temani Afif Jan 28 '21 at 07:37
  • 1
    @TemaniAfif, I was saying "exactly 2 element can fit per column" in the context of saying that this solution "won't work for our use case because it also relies on the container and the items inside having specific heights (or more precisely that the heights are such that, exactly 2 element can fit per column)". So, it's not our use-case that 2 elements fit per column - we don't know the heights of the elements in advance. But of course, may work for other folks. – Garrett Jan 29 '21 at 16:13