How to Create a Row of Elements of Equal Width Inside an Inline Container? Possibly Using Flexbox

How to create a row of elements of equal width inside an inline container? Possibly using flexbox

I was able to accomplish this by using display: inline-grid on the parent element and then adding the property grid-template-columns: 1fr 1fr 1fr to the parent as well (1fr per column needed).

div.inline {

display: inline-grid;

grid-template-columns: 1fr 1fr;

}

div.cell {

border: 1px dotted grey;

text-align: center;

}
content

<div class='inline'>

<div class='cell'>lorem ipsum lorem ipsum</div>

<div class='cell'>lorem</div>

</div>

content

Make flex items have equal width in a row

Flexbox method

In order to make the text items (.section-child) equal width, you need to use flex: 1 1 0, which you have done. This is the same as saying flex: 1.

However, this by itself doesn't achieve the goal for two reasons:

  1. The parent of .section-child, a flex container, but also a flex item in a larger container, is limited to the width of its content, by default. So it won't expand and the text can overflow the container. You need to apply flex: 1 to .section, as well.

  2. A flex item cannot be smaller than the size of its content, by default. The initial setting is min-width: auto. So flex: 1 cannot work to equally distribute container space, because a flex item cannot shrink past the longest item. You need to override this behavior with min-width: 0.

.top-level {

display: flex;

flex-flow: row wrap;

}

.section {

display: flex;

flex-flow: row nowrap;

border: 1px solid;

margin-right: 12px;

margin-top: 12px;

flex: 1;

min-width: 0;

}

.section-child {

display: flex;

flex-flow: column nowrap;

align-items: center;

flex: 1;

min-width: 0;

}

.child-title {

white-space: nowrap;

}

.vertical-separator {

width: 1px;

background-color: rgba(0, 0, 0, 0.3);

margin: 8px;

}
<div class="top-level">

<section class="section">

<div class="section-child">

<h4 class="child-title">Title</h4>

<!--A lot more content here-->

</div>

<div class="vertical-separator"></div>

<div class="section-child">

<h4 class="child-title">Longer title</h4>

<!--A lot more content here-->

</div>

<div class="vertical-separator"></div>

<div class="section-child">

<h4 class="child-title">Much much longer title</h4>

<!--A lot more content here-->

</div>

</section>

<section class="section">

<div class="section-child">

<h4 class="child-title">Title</h4>

<!--A lot more content here-->

</div>

<div class="vertical-separator"></div>

<div class="section-child">

<h4 class="child-title">Longer title</h4>

<!--A lot more content here-->

</div>

<div class="vertical-separator"></div>

<div class="section-child">

<h4 class="child-title">Much much longer title</h4>

<!--A lot more content here-->

</div>

</section>

<section class="section">

<div class="section-child">

<h4 class="child-title">Title</h4>

<!--A lot more content here-->

</div>

<div class="vertical-separator"></div>

<div class="section-child">

<h4 class="child-title">Longer title</h4>

<!--A lot more content here-->

</div>

<div class="vertical-separator"></div>

<div class="section-child">

<h4 class="child-title">Much much longer title</h4>

<!--A lot more content here-->

</div>

</section>

</div>

Flexbox not giving equal width to elements

There is an important bit that is not mentioned in the article to which you linked and that is flex-basis. By default flex-basis is auto.

From the spec:

If the specified flex-basis is auto, the used flex basis is the value of the flex item’s main size property. (This can itself be the keyword auto, which sizes the flex item based on its contents.)

Each flex item has a flex-basis which is sort of like its initial size. Then from there, any remaining free space is distributed proportionally (based on flex-grow) among the items. With auto, that basis is the contents size (or defined size with width, etc.). As a result, items with bigger text within are being given more space overall in your example.

If you want your elements to be completely even, you can set flex-basis: 0. This will set the flex basis to 0 and then any remaining space (which will be all space since all basises are 0) will be proportionally distributed based on flex-grow.

li {
flex-grow: 1;
flex-basis: 0;
/* ... */
}

This diagram from the spec does a pretty good job of illustrating the point.

And here is a working example with your fiddle.

How to display 3 items per row in flexbox?

Flex container:

  • You probably want to use display: flex not inline-flex.
  • Add flex-wrap: wrap to allow wrapping onto multiple lines.
  • Remove width: 33% if you wish it to take entire space avaiable.

For 3 items per row, add on the flex items:

  • flex-basis: 33.333333%
  • You can also use the flex's shorthand like the following: flex: 0 0 33.333333% => which also means flex-basis: 33.333333%.

.serv ul {

display: flex;

flex-wrap: wrap;

padding-left: 0;

}

.serv ul li {

list-style: none;

flex: 0 0 33.333333%;

}
<div class="serv">

<ul>

<li>1</li>

<li>2</li>

<li>3</li>

<li>4</li>

<li>5</li>

<li>6</li>

</ul>

</div>

Equal width flex items even after they wrap

Currently, flexbox offers no clean solution for aligning flexible items in the last row or column. It's beyond the scope of the current spec.

Here's more information and various solutions people have used to get around the problem:

  • Targeting flex items on the last row
  • Is it possible for flex items to align tightly to the items above them?

However, last-row alignment is not a problem with another CSS3 technology, Grid Layout. In fact, it's very simple with this method (and requires no changes to the HTML):

.container {

display: grid;

grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));

grid-auto-rows: 20px;

grid-gap: 5px;

}

.item {

background: yellow;

text-align: center;

border: 1px solid red;

}
<div class="container">

<div class="item">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 class="item">8</div>

<div class="item">9</div>

<div class="item">10</div>

</div>

Arrange 2 items per row using flexbox

You can give flex: 50% to children divs without touching .item

.item {
width: 100%
}

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

.container > div {
flex: 50%; /* or - flex: 0 50% - or - flex-basis: 50% - */
/*demo*/
box-shadow: 0 0 0 1px black;
margin-bottom: 10px;
}
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>

Equal height rows in a flex container

The answer is NO.

The reason is provided in the flexbox specification:

6. Flex Lines

In a multi-line flex container, the cross size of each line is the minimum size necessary to contain the flex items on the line.

In other words, when there are multiple lines in a row-based flex container, the height of each line (the "cross size") is the minimum height necessary to contain the flex items on the line.

Equal height rows, however, are possible in CSS Grid Layout:

  • Equal height rows in CSS Grid Layout

Otherwise, consider a JavaScript alternative.

Possible to use CSS Flexbox to stretch elements on every row while maintaining consistent widths?

You can achieve this using CSS-grid:

.container {

display: grid;

grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));

}

.container>div {

height: 100px;

border: 1px #fff solid;

text-align: center;

font-size: 2em;

background: #66f;

}
<div class="container">

<div>1</div>

<div>2</div>

<div>3</div>

<div>4</div>

<div>5</div>

</div>

How to keep wrapped flex-items the same width as the elements on the previous row?

TL;DR

This is not something I'd call a solution per se, but it's a rather elegant workaround that only uses media queries, and more importantly no JavaScript!

Mixin (SCSS):

@mixin flex-wrap-fix($flex-basis, $max-viewport-width: 2000px) {
flex-grow: 1;
flex-basis: $flex-basis;
max-width: 100%;

$multiplier: 1;
$current-width: 0px;

@while $current-width < $max-viewport-width {
$current-width: $current-width + $flex-basis;
$multiplier: $multiplier + 1;

@media(min-width: $flex-basis * $multiplier) {
max-width: percentage(1/$multiplier);
}
}
}

Usage:

Apply the mixin to your flex item:

.flex-item {
@include flex-wrap-fix(100px)
}

Update:

The above mixin should do the trick, as long as you your flex container width matches your viewport size, as is the case in OP's example. Media queries won't help you otherwise, because they're always based on the viewport width. However, you could use the css-element-queries library and its element queries instead of browser media queries. Here's a mixin that you can apply to the flex container:

@mixin flex-container-wrap-items($flex-basis, $max-expected-width: 2000px) {
display: flex;
flex-wrap: wrap;

> * {
max-width: 100%;
flex-grow: 1;
flex-basis: $flex-basis;
}

$multiplier: 1;
$current-width: 0px;

@while $current-width < $max-expected-width {
$current-width: $current-width + $flex-basis;
$multiplier: $multiplier + 1;

&[min-width~="#{$flex-basis * $multiplier}"] > * {
max-width: percentage(1/$multiplier);
}
}
}

Explanation:

Let's say, as per the OP's example, we want each item to have a maximum width of 100px, so we know that for a browser width of 100px we can fit one item per row, and so on:

| Viewport Width | Max Item Count Per Row | Item Width (min-max) |
|----------------|------------------------|----------------------|
| <= 100 | 1 | 0px - 100px |
| <= 200 | 2 | 50px - 100px |
| <= 300 | 3 | 50px - 100px |
| <= 400 | 4 | 50px - 100px |
| <= 500 | 5 | 50px - 100px |
| <= 600 | 6 | 50px - 100px |

We can write media queries to create the following rules:

| Viewport Width | Max Item Count Per Row | Item Max Width | Calculation |
|------------------------------------------------------------------------|
| <= 100px | 1 | 100% | (100/1) |
| <= 200px | 2 | 50% | (100/2) |
| <= 300px | 3 | 33.33333% | (100/3) |
| <= 400px | 4 | 25% | (100/4) |
| <= 500px | 5 | 20% | (100/5) |
| <= 600px | 6 | 16.66666% | (100/6) |

Like this:

li {
flex: 1 0 0
max-width: 100%;
}

@media(min-width: 200px) {
li { max-width: 50%; }
}

@media(min-width: 300px) {
li { max-width: 33.33333%; }
}

@media(min-width: 400px) {
li { max-width: 25%; }
}

@media(min-width: 500px) {
li { max-width: 20%; }
}

@media(min-width: 600px) {
li { max-width: 16.66666%; }
}

Of course, that's repetitive, but most likely you're using some sort of preprocessor, which can take care of the repetitiveness for you. That's precisely what the mixin in the above TL;DR section does.

All we have to do now is to specify 100px as our flex-basis, and optionally the maximum browser window width (defaults to 2000px) to create the media queries for:

@include flex-wrap-fix(100px)

Example

Finally, a forked version of the original CodePen example with the desired output, using the above mixin:

http://codepen.io/anon/pen/aNVzoJ

demo of the solution



Related Topics



Leave a reply



Submit