495

I'm using a flex box to display 8 items that will dynamically resize with my page. How do I force it to split the items into two rows? (4 per row)?

Here is a relevant snip:

(Or if you prefer jsfiddle - http://jsfiddle.net/vivmaha/oq6prk1p/2/)

.parent-wrapper {
  height: 100%;
  width: 100%;
  border: 1px solid black;
}
.parent {
  display: flex;
  font-size: 0;
  flex-wrap: wrap;
  margin: -10px 0 0 -10px;
}
.child {
  display: inline-block;
  background: blue;
  margin: 10px 0 0 10px;
  flex-grow: 1;
  height: 100px;
}
<body>
  <div class="parent-wrapper">
    <div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>
  </div>
</body>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
V Maharajh
  • 9,013
  • 5
  • 30
  • 31
  • 39
    [Update] This question was based on a poor unresponsive design. If you find yourself using one of the answers below, be careful. In a good design, you'd have more items on wider screens, and fewer on smaller screens. Forcing 4 items for all screen sizes will only look appealing on a narrow range of screen widths. – V Maharajh Feb 02 '18 at 16:27
  • 6
    I don't agree with the "in a good design" statement at all. What if I'm making a calendar widget and I want it to always have 7 days per row? What if I'm building a Sudoku board and it always needs to be 9x9? There are plenty of valid reasons why someone might want to hard-code the number of items per row, and that doesn't always make it bad design. – OOPS Studio Apr 03 '23 at 21:31

10 Answers10

702

You've got flex-wrap: wrap on the container. That's good, because it overrides the default value, which is nowrap (source). This is the reason items don't wrap to form a grid in some cases.

In this case, the main problem is flex-grow: 1 on the flex items.

The flex-grow property doesn't actually size flex items. Its task is to distribute free space in the container (source). So no matter how small the screen size, each item will receive a proportional part of the free space on the line.

More specifically, there are eight flex items in your container. With flex-grow: 1, each one receives 1/8 of the free space on the line. Since there's no content in your items, they can shrink to zero width and will never wrap.

The solution is to define a width on the items. Try this:

.parent {
  display: flex;
  flex-wrap: wrap;
}

.child {
  flex: 1 0 21%; /* explanation below */
  margin: 5px;
  height: 100px;
  background-color: blue;
}
<div class="parent">
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
</div>

With flex-grow: 1 defined in the flex shorthand, there's no need for flex-basis to be 25%, which would actually result in three items per row due to the margins.

Since flex-grow will consume free space on the row, flex-basis only needs to be large enough to enforce a wrap. In this case, with flex-basis: 21%, there's plenty of space for the margins, but never enough space for a fifth item.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 4
    I like this because it worked for me, but “plenty of space” makes me feel a little uneasy. Is there some tiny window or situation where this “estimation” might fail me? – Jackson May 01 '18 at 21:07
  • 1
    What sort of situation? In most layouts there are extreme cases that can create problems. Such cases normally sail through cost-benefit analyses because they never, or almost never, occur. For instance, in the solution above, if you put in very large margins, the layout may break. If that's an issue, then it should be posted in the question. @Jackson – Michael Benjamin May 02 '18 at 00:36
  • 4
    “if you put in very large margins, the layout may break” That’s an example of a scenario I’d like to avoid. I don’t care about practicality; entertain my adoration for perfection. Is there any way to be more exact? – Jackson May 02 '18 at 16:01
  • 81
    You can also use `flex: 1 0 calc(25% - 10px);` – MarkG Jul 19 '18 at 18:51
  • This kind of an approach is more typically handled by padding and negative margins on the parent, which will allow you to actually use the full 25% `flex-basis`. This was the yesteryear implementation in most grid libraries. – Leland Sep 27 '18 at 18:42
  • 2
    Great answer! A small improvement I use is `margin: 2%;` instead of a fixed pixel number in order to prevent the boxes from jumping to a new line on small devices/resolutions. the general formula is `(100 - (4 * box-width-percent)) / 8`% for different box widths – thomaspsk Feb 18 '19 at 17:27
  • 8
    In case anyone forgets, the flex property here is shorthand for flex-grow: 1; flex-shrink: 0; flex-basis: 21%; – MrAn3 Sep 11 '20 at 15:34
  • Another way I like to deal with wrapping and dynamic margins that arent negative is to use the + selector and then use nth-child for where I want to wrap. Something like: .child+.child { margin-left: 2% } then .child:nth-child(3n +1) { margin-left: 0%; } or something like that – Jared Rice Mar 19 '21 at 18:40
  • You can check this approach also https://stackoverflow.com/a/45038018/3448527 – dippas Jul 16 '21 at 17:38
  • Every time I use flex for something cool like this I am so grateful we're not back in the dark days of web development – Max Apr 02 '22 at 20:59
137

Add a width to the .child elements. I personally would use percentages on the margin-left if you want to have it always 4 per row.

DEMO

.child {
    display: inline-block;
    background: blue;
    margin: 10px 0 0 2%;
    flex-grow: 1;
    height: 100px;
    width: calc(100% * (1/4) - 10px - 1px);
}
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
dowomenfart
  • 2,803
  • 2
  • 15
  • 17
  • Good idea. I used this idea with minor edits. http://jsfiddle.net/vivmaha/oq6prk1p/6/ – V Maharajh Apr 09 '15 at 20:46
  • 1
    Ah. This actually doesn't solve my problem. See here for an example: http://jsfiddle.net/vivmaha/oq6prk1p/7/. I do not have the liberty of using percentages for my margin. They must be a fixed width. This means that the magic 23% that we chose won't work since it doesn't take the fixed margin into account. – V Maharajh Apr 09 '15 at 21:29
  • 4
    Yes, calc solves it! 'calc(100% * (1/4) - 10px - 1px)'. See http://jsfiddle.net/vivmaha/oq6prk1p/9/ – V Maharajh Apr 09 '15 at 23:36
  • 35
    Then what's the use of flex in this, still? – twicejr Nov 29 '16 at 21:41
  • What about responsive design? We don't want to put a fixed width on child – candlejack Dec 26 '17 at 04:32
  • how can i do this if i want two elements per row ? – Youssef Boudaya Dec 15 '20 at 13:14
68

Here is another apporach.

You can accomplish it in this way too:

.parent{
  display: flex;
  flex-wrap: wrap;
}

.child{
  width: 25%;
  box-sizing: border-box;
}

Sample: https://codepen.io/capynet/pen/WOPBBm

And a more complete sample: https://codepen.io/capynet/pen/JyYaba

Capy
  • 5,167
  • 2
  • 20
  • 21
44

I would do it like this using negative margins and calc for the gutters:

.parent {
  display: flex;
  flex-wrap: wrap;
  margin-top: -10px;
  margin-left: -10px;
}

.child {
  width: calc(25% - 10px);
  margin-left: 10px;
  margin-top: 10px;
}

Demo: https://jsfiddle.net/9j2rvom4/


Alternative CSS Grid Method:

.parent {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

Demo: https://jsfiddle.net/jc2utfs3/

shanomurphy
  • 666
  • 6
  • 9
36

For more detail you can follow this Link

.parent{ 
  display: flex; 
  flex-wrap: wrap; 
}

.parent .child{ 
  flex: 1 1 25%;
  /*Start Run Code Snippet output CSS*/
  padding: 5px; 
  box-sizing: border-box;
  text-align: center;
  border: 1px solid #000;
  /*End Run Code Snippet output CSS*/
}
<div class="parent">
  <div class="child">1</div>
  <div class="child">2</div>
  <div class="child">3</div>
  <div class="child">4</div>
  <div class="child">5</div>
  <div class="child">6</div>
  <div class="child">7</div>
  <div class="child">8</div>
</div>
timthedev07
  • 454
  • 1
  • 6
  • 17
Muddasir Abbas
  • 1,699
  • 1
  • 20
  • 37
4

I believe this example is more barebones and easier to understand then @dowomenfart.

.child {
    display: inline-block;
    margin: 0 1em;
    flex-grow: 1;
    width: calc(25% - 2em);
}

This accomplishes the same width calculations while cutting straight to the meat. The math is way easier and em is the new standard due to its scalability and mobile-friendliness.

Joseph Cho
  • 4,033
  • 4
  • 26
  • 33
3

.parent-wrapper {
 height: 100%;
 width: 100%;
 border: 1px solid black;
}
 .parent {
 display: flex;
 font-size: 0;
 flex-wrap: wrap;
 margin-right: -10px;
 margin-bottom: -10px;
}
 .child {
 background: blue;
 height: 100px;
 flex-grow: 1;
 flex-shrink: 0;
 flex-basis: calc(25% - 10px);
}
 .child:nth-child(even) {
 margin: 0 10px 10px 10px;
 background-color: lime;
}
 .child:nth-child(odd) {
 background-color: orange; 
}
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
 <style type="text/css">

 </style>
</head>
<body>
  <div class="parent-wrapper">
    <div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>
  </div>
</body>
</html>

;)

  • 1
    If you can please add some context about why this answers the OP question rather than just posting code. – d219 Mar 31 '18 at 19:51
  • if you add `justify-content: space-evenly;` to the prent, then they align nicely and you don't have to do the `calc` on the child. Thanks for the example, though! – Mattijs Jun 14 '18 at 09:15
2

Flex wrap + negative margin

Why flex vs. display: inline-block?

Why negative margin?

Either you use SCSS or CSS-in-JS for the edge cases (i.e. first element in column), or you set a default margin and get rid of the outer margin later.

Implementation

https://codepen.io/zurfyx/pen/BaBWpja

<div class="outerContainer">
    <div class="container">
        <div class="elementContainer">
            <div class="element">
            </div>
        </div>
        ...
    </div>
</div>
:root {
  --columns: 2;
  --betweenColumns: 20px; /* This value is doubled when no margin collapsing */
}

.outerContainer {
    overflow: hidden; /* Hide the negative margin */
}

.container {
    background-color: grey;
    display: flex;
    flex-wrap: wrap;
    margin: calc(-1 * var(--betweenColumns));
}

.elementContainer {
    display: flex; /* To prevent margin collapsing */
    width: calc(1/var(--columns) * 100% - 2 * var(--betweenColumns));
    margin: var(--betweenColumns);
}

.element {
    display: flex;
    border: 1px solid red;
    background-color: yellow;
    width: 100%;
    height: 42px;
}
zurfyx
  • 31,043
  • 20
  • 111
  • 145
1

you can try this

.parent-wrapper {
    height:100%;
    width:100%;
    border: 1px solid black;
}
.parent {
    display: grid;
    font-size: 0;
    grid-template-columns: 25% 25% 25% 25%;
}
.child {
    background:blue;
    flex-grow: 1;
    height:100px;
    margin: 10px;
    margin-bottom: 0;
}

.child:last-child {
    margin-bottom: 10px;
}
<body>
    <div class="parent-wrapper">
        <div class="parent">
            <div class="child"></div>
            <div class="child"></div>
            <div class="child"></div>
            <div class="child"></div>
            <div class="child"></div>
            <div class="child"></div>
            <div class="child"></div>
            <div class="child"></div>
        </div>
    </div>
</body>

https://jsfiddle.net/samet19/gdntwLhb/

-14

Here's another way without using calc().

// 4 PER ROW
// 100 divided by 4 is 25. Let's use 21% for width, and the remainder 4% for left & right margins...
.child {
  margin: 0 2% 0 2%;
  width: 21%;
}

// 3 PER ROW
// 100 divided by 3 is 33.3333... Let's use 30% for width, and remaining 3.3333% for sides (hint: 3.3333 / 2 = 1.66666)
.child {
  margin: 0 1.66666% 0 1.66666%;
  width: 30%;
}

// and so on!

That's all there is to it. You can get fancy with the dimensions to get a more aesthetic sizes but this is the idea.

Jef
  • 320
  • 5
  • 14
wle8300.com
  • 2,588
  • 1
  • 23
  • 29
  • 6
    I haven't tested this, but the CSS syntax is wrong (CSS values are not quoted, and declarations should end in a semi-colon) so it definitely won't work in its current form. – Nick F Nov 08 '16 at 12:54