219

I don't think this is part of the flexbox standard yet, but is there maybe a trick to suggest or force wrapping after a certain element? I'd like to respond to different page sizes and wrap a list differently without extra markup, so that rather than having (for example) orphaned menu items on the next line, I break in the middle of the menu.

Here's the starting html:

<ul>
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <li>Four</li>
    <li>Five</li>
</ul>

And css:

ul {
    display: flex;
    flex-wrap: wrap;
}

I'd love something like the following:

/* inside media query targeting width */
li:nth-child(2n) {
    flex-break: after;
}

See the jsfiddle for a more complete setup: http://jsfiddle.net/theazureshadow/ww8DR/

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
theazureshadow
  • 9,499
  • 5
  • 33
  • 48
  • For wrapping based on viewport dimensions there are *media queries*, for wrapping based on content quantity, such as sibling count, there are [***quantity queries***](http://stackoverflow.com/a/33333193/3597276). – Michael Benjamin Nov 08 '15 at 12:37

5 Answers5

193

You can accomplish this by setting this on the container:

ul {
    display: flex;
    flex-wrap: wrap;
}

And on the child you set this:

li:nth-child(2n) {
    flex-basis: 100%;
}

ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
}

li:nth-child(4n) {
  flex-basis: 100%;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>

This causes the child to make up 100% of the container width before any other calculation. Since the container is set to break in case there is not enough space it does so before and after this child. So you could use an empty div element to force the wrap between the element before and after it.

musicformellons
  • 12,283
  • 4
  • 51
  • 86
luksak
  • 3,502
  • 2
  • 25
  • 28
  • 4
    Thanks! For example, if you want to have 4 items per row, you just do: `li { flex-basis: 25% }` – fabio.sang Oct 20 '16 at 08:24
  • 19
    Setting a basis of 100% or 100% / elements per row isn't a great solution because it requires you to set a height on the container or it'll expand. – Lucent Jun 16 '17 at 17:09
  • 1
    @Lucent, `min-height` would suffice though right? Just thinking `min-height: 1px` might mitigate this concern for a lot of use cases. – Ynot Nov 15 '18 at 19:56
  • 3
    Also using this solution stretches element which otherwise won't be taking 100% – llamerr Mar 01 '21 at 12:58
81

=========================

Here's an article with your full list of options: https://tobiasahlin.com/blog/flexbox-break-to-new-row/

EDIT: This is really easy to do with Grid now: https://codepen.io/anon/pen/mGONxv?editors=1100

=========================

I don't think you can break after a specific item. The best you can probably do is change the flex-basis at your breakpoints. So:

ul {
  flex-flow: row wrap;
  display: flex;
}

li {
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: 50%;
}

@media (min-width: 40em;){
li {
  flex-basis: 30%;
}

Here's a sample: http://cdpn.io/ndCzD

============================================

EDIT: You CAN break after a specific element! Heydon Pickering unleashed some css wizardry in an A List Apart article: http://alistapart.com/article/quantity-queries-for-css

EDIT 2: Please have a look at this answer: Line break in multi-line flexbox

@luksak also provides a great answer

2507rkt3
  • 21,311
  • 1
  • 18
  • 15
  • That's quite a good idea! I've added it to the jsfiddle. Playing around with it, I think I prefer a non-percentage-based approach, since percentage-based prevents further reflow as you shrink the container more, though you could certainly add more specific breakpoints as it shrinks (when it should go to 33%, etc). – theazureshadow Oct 24 '13 at 21:58
  • works great in chrome desktop. so sad it doesn't in android webviews for android <4.4 :( – Guillaume Gendre Jan 14 '14 at 11:12
  • does not work in Safari 7.0.3 either. – wprater May 30 '14 at 21:48
  • yes - you just need to have the proper prefixes for the css – 2507rkt3 Jun 11 '14 at 13:55
  • And most of all have a fallback when flexbox is not supported. – Didier Ghys Mar 18 '15 at 22:34
  • 29
    I don't see how the alistapart article explains how to break on a specific item. I can see how it talks about *selecting* the item, but not breaking the wrap. – Ben Davis Nov 08 '15 at 21:57
  • True. It's about implementing different styling depending on the number of elements existing in the markup, not the number of elements that are being displayed on one row or something. – certainlyakey Jun 20 '16 at 08:12
  • I like how you comeback to the post, update when new info becomes available. Kudo's and one-up – James Walker Jan 31 '20 at 03:08
  • @2507rkt3 Could it be done for `column-wise` direction. More specifically [this question](https://stackoverflow.com/q/64801733/8655856) – Dost Arora Nov 12 '20 at 11:37
36

There is part of the spec that sure sounds like this... right in the "flex layout algorithm" and "main sizing" sections:

Otherwise, starting from the first uncollected item, collect consecutive items one by one until the first time that the next collected item would not fit into the flex container’s inner main size, or until a forced break is encountered. If the very first uncollected item wouldn’t fit, collect just it into the line. A break is forced wherever the CSS2.1 page-break-before/page-break-after [CSS21] or the CSS3 break-before/break-after [CSS3-BREAK] properties specify a fragmentation break.

From http://www.w3.org/TR/css-flexbox-1/#main-sizing

It sure sounds like (aside from the fact that page-breaks ought to be for printing), when laying out a potentially multi-line flex layout (which I take from another portion of the spec is one without flex-wrap: nowrap) a page-break-after: always or break-after: always should cause a break, or wrap to the next line.

.flex-container {
  display: flex;
  flex-flow: row wrap;
}

.child {
  flex-grow: 1;
}

.child.break-here {
  page-break-after: always;
  break-after: always;
}

However, I have tried this and it hasn't been implemented that way in...

  • Safari (up to 7)
  • Chrome (up to 43 dev)
  • Opera (up to 28 dev & 12.16)
  • IE (up to 11)

It does work the way it sounds (to me, at least) like in:

  • Firefox (28+)

Sample at http://codepen.io/morewry/pen/JoVmVj.

I didn't find any other requests in the bug tracker, so I reported it at https://code.google.com/p/chromium/issues/detail?id=473481.

But the topic took to the mailing list and, regardless of how it sounds, that's not what apparently they meant to imply, except I guess for pagination. So there's no way to wrap before or after a particular box in flex layout without nesting successive flex layouts inside flex children or fiddling with specific widths (e.g. flex-basis: 100%).

This is deeply annoying, of course, since working with the Firefox implementation confirms my suspicion that the functionality is incredibly useful. Aside from the improved vertical alignment, the lack obviates a good deal of the utility of flex layout in numerous scenarios. Having to add additional wrapping tags with nested flex layouts to control the point at which a row wraps increases the complexity of both the HTML and CSS and, sadly, frequently renders order useless. Similarly, forcing the width of an item to 100% reduces the "responsive" potential of the flex layout or requires a lot of highly specific queries or count selectors (e.g. the techniques that may accomplish the general result you need that are mentioned in the other answers).

At least floats had clear. Something may get added at some point or another for this, one hopes.

morewry
  • 4,320
  • 3
  • 35
  • 35
  • 1
    That sounds pretty hacky. As I understand it, `page-break-after` is for when you're printing, and `break-after` is for "page, column or region break behavior", not line breaks. – Ajedi32 Apr 05 '15 at 03:31
  • 6
    Take it up with the spec authors; as I mentioned, it is straight from the official specification for Flexbox. It's not a suggestion I am making about a "cool trick". Incidentally, wrapping a flex row is not, strictly speaking "an inline line break", nor did I say it was. The phrase "wrap to the next line" is simply one of several casual ways of expressing "it won't be next to the other boxes anymore". – morewry Apr 06 '15 at 23:29
  • Damn! This was looking so promising :( – Lyrical Nov 10 '17 at 16:28
  • If we had `break-after: row` this would be perfect. However, the smallest thing we currently have is `break-after: region` which is supported by about 0% of the browsers and `break-after: column` which too heavy already. Think about case where you have flex and multiple columns. Breaking the column is not the same thing as breaking the row. – Mikko Rantalainen Aug 25 '21 at 08:56
14

Setting a min-width on child elements will also create a breakpoint. For example breaking every 3 elements,

flex-grow: 1;
min-width: 33%; 

If there are 4 elements, this will have the 4th element wrap taking the full 100%. If there are 5 elements, the 4th and 5th elements will wrap and take each 50%.

Make sure to have parent element with,

flex-wrap: wrap
David Ortiz
  • 1,377
  • 1
  • 9
  • 7
3

The only thing that appears to work is to set flex-wrap: wrap; on the container and them somehow make the child you want to break out after to fill the full width, so width: 100%; should work.

If, however, you can't stretch the element to 100% (for example, if it's an <img>), you can apply a margin to it, like width: 50px; margin-right: calc(100% - 50px).

fiatjaf
  • 11,479
  • 5
  • 56
  • 72