Reputation: 973
Let's say I have a div
which will contain a set of elements (divs), which may have different heights, but all of them will have the same width.
I've achieved this currently with isotope + masonry, but since some browsers already support CSS3 multi-columns, I was hoping to have a only-CSS solution for these browsers, falling back to Javascript for the rest.
This is the CSS I've been trying:
.div-of-boxes {
-webkit-column-count: 3;
-webkit-column-gap: 10px;
-moz-column-count: 3;
-moz-column-gap: 10px;
column-count: 3;
column-gap: 10px;
}
However, this makes the flow of the elements to be top-down left-right. I'd like instead a left-right top-down flow. This is an example of what I'd like:
1 2 3
4 5 6
7 8 9
But this is what I get:
1 4 7
2 5 8
3 6 9
In Flow multi-column elements left-right before top-down something similar is asked, but I'm not satisfied with the answer, and it won't work with elements of different height. Is this possible at all with CSS columns, or is it a limitation?
Upvotes: 45
Views: 23273
Reputation: 122
There doesn't seem to be a built-in css only way to this. The most straightforward solution is to simply place N containers next to each other (flex, table) and then rearrange the list into the N containers in code by going through the items and pushing the next item into the next column like this:
const N = 3;
const columnsToView = [];
for (let columnIndex = 0; columnIndex < N; columnIndex++) {
columnsToView[columnIndex] = [];
}
for (let itemIndex = 0; itemIndex < itemsToView.length; itemIndex++){
columnsToView[itemIndex % N].push(itemsToView[itemIndex]);
}
Upvotes: 0
Reputation: 86
There's a CSS-only solution using flexbox
, :nth-child()
, and order
as described in this blog post by Tobias Ahlin.
The idea is quite simple. flex-flow: column
with wrap
can do precisely what column-count
does. You'll need two conditions to make it work: 1. The flexbox container needs to have a fixed height and it needs to be taller than your tallest column. 2. Flex children need width, 50% for 2-column layout, 33% for 3-column layout, etc.
.flex-container {
display: flex;
flex-flow: column wrap;
height: 600px; /* You'll need to play with this value to distribute items correctly */
}
.flex-child {
width: 33%; /* Creates 3-column layout */
}
This approach has the same problem as column-count
: the elements are ordered by column, top-down. But since we're using flexbox, now we get access to the order
property.
Using :nth-child()
and order
we can override the default order.
.flex-child:nth-child(3n+1) { order: 1; }
.flex-child:nth-child(3n+2) { order: 2; }
.flex-child:nth-child(3n) { order: 3; }
Items with order: 1
will go in the first column, order: 2
will go in the second column, and order: 3
in the third column.
In (an + b)
formula a
represents a cycle size, n
is a counter (starts at 0), and b
is an offset value. So (3n+1)
selects every third item starting with the first one. (3n+2)
selects every third item but starting with the second item. And (3n)
selects every third item starting with the third
item, since there's nothing at index 0.
In certain layouts, columns might merge. To solve this issue, Tobias inserts pseudo-elements between columns:
/* Force new columns */
.flex-container::before,
.flex-container::after {
content: "";
flex-basis: 100%;
width: 0;
order: 2;
}
I won't explain how this works here, but you can read more about it here.
Here's a CodePen by Tobias for a 3-column layout. If you're working with more than three columns, read how to make adjustments here.
Upvotes: 0
Reputation: 191
Here's a link on solution! Used only flex.
html
- var n = 0;
ul
while n < 40
li= n++
li
css
ul {
list-style: none;
padding: 30px;
background: #28285e;
li {
padding: 20px;
margin: 6px;
background: white;
width: calc(50% - 52px);
height: 100px;
display: inline-block;
border: {
radius: 4px
}
&:nth-child(3n) {
height: 40px;
}
&:nth-child(2n + 1) {
height: 80px;
}
&:nth-child(even) {
float: right;
}
&:nth-child(odd) {
float: left;
}
&:last-child {
clear: both;
float: none;
}
}
}
Upvotes: 0
Reputation: 10625
If your layout is always going to be 3 columns wide, you could try using the nth
selector on your internal divs.
You could do this by clearing your 4th item.
#container {
overflow: hidden;
width: 440px;
}
#container div {
background-color: gray;
width: 110px;
margin: 5px;
float: left;
}
#container div:nth-child(4) {
clear: both;
}
<div id="container">
<div id="widget1">1</div>
<div id="widget2">2</div>
<div id="widget3">3</div>
<div id="widget4">4</div>
<div id="widget5">5</div>
<div id="widget6">6</div>
<div id="widget7">7</div>
<div id="widget7">8</div>
</div>
Upvotes: 7
Reputation: 15
You can use jQuery to rearrange items in columns. In case of 2 cols it would be:
$('.your-columns-container .your-item:nth-child(even)').appendTo('.your-columns-container');
https://jsfiddle.net/hzvp7sgf/
And something more complicated for 3 columns:
$('.your-columns-container .your-item:nth-child(3n - 1)').addClass('container-col2');
$('.your-columns-container .your-item:nth-child(3n)').addClass('container-col3');
$('.container-col2').appendTo('.your-columns-container').removeClass('container-col2');
$('.container-col3').appendTo('.your-columns-container').removeClass('container-col3');
https://jsfiddle.net/d4LeLyu5/
Upvotes: -1
Reputation: 68319
The multi-column specification offers no property to change the distribution of elements among the columns: http://www.w3.org/TR/css3-multicol/. Such a property seems to go against what the module was designed for (recreating how newspaper or magazine articles are laid out).
None of the other pure CSS solutions will allow you to achieve the effect you are looking for.
Upvotes: 29