简体   繁体   中英

CSS columns with left-right flow

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?

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.

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>

JS Fiddle

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;
        }
    }
}

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 .

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/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM