Flexbox and Wrap Property

How does flex-wrap work with align-self, align-items and align-content?

Short Answer

Although the flex-wrap property seems pretty basic – it controls whether flex items can wrap – it actually has a wide-ranging impact on the entire flexbox layout.

The flex-wrap property determines the type of flex container you will use.

  • flex-wrap: nowrap creates a single-line flex container
  • flex-wrap: wrap and wrap-reverse create a multi-line flex container

The align-items and align-self properties work in both single- and multi-line containers. However, they can only have an effect when there's free space in the cross axis of the flex line.

The align-content property works only in multi-line containers. It is ignored in single-line containers.



Explanation

The flexbox specification provides four keyword properties for aligning flex items:

  • align-items
  • align-self
  • align-content
  • justify-content

To understand the functions of these properties it's important to first understand the structure of a flex container.



Part 1: Understanding the Main Axis and Cross Axis of a Flex Container

The X and Y Axes

A flex container works in two directions: x-axis (horizontal) and y-axis (vertical).

x-axis and the y-axis

                                                                                                                Source: Wikipedia

The child elements of a flex container – known as "flex items" – can be aligned in either direction. (Ignore the z axis in the image above. It doesn't apply here.)

This is flex alignment at its most fundamental level.

The Main and Cross Axes

Overlaying the x and y axes are, in flex layout, the main and cross axes.

By default, the main axis is horizontal (x-axis), and the cross axis is vertical (y-axis). That's the initial setting, as defined by the flexbox specification.

flex main axis and cross axis

                                                                                                                Source: W3C

However, unlike the x and y axes, which are fixed, the main and cross axes can switch directions.

The flex-direction Property

In the image above, the main axis is horizontal and the cross axis is vertical. As mentioned earlier, that's an initial setting of a flex container.

However, these directions can be easily switched with the flex-direction property. This property controls the direction of the main axis; it determines whether flex items align vertically or horizontally.

From the spec:

5.1. Flex Flow Direction: the flex-direction
property

The flex-direction property specifies how flex items are placed in
the flex container, by setting the direction of the flex container’s
main axis. This determines the direction in which flex items are laid
out.

There are four values for the flex-direction property:

/* main axis is horizontal, cross axis is vertical */
flex-direction: row; /* default */
flex-direction: row-reverse;

/* main axis is vertical, cross axis is horizontal */
flex-direction: column;
flex-direction: column-reverse;

The cross axis is always perpendicular to the main axis.



Part 2: Flex Lines

Within the container, flex items exist in a line, known as a "flex line".

A flex line is a row or column, depending on flex-direction.

A container can have one or more lines, depending on flex-wrap.

Single-Line Flex Container

flex-wrap: nowrap establishes a single-line flex container, in which flex items are forced to stay in a single line (even if they overflow the container).

a single-line flex container (one column)

The image above has one flex line.

flex-container {
display: flex;
flex-direction: column;
flex-wrap: nowrap; /* <-- allows single-line flex container */
width: 250px;
height: 250px;
background-color: silver;
}
flex-item {
flex: 0 0 50px;
width: 50px;
margin: 5px;
background-color: lightgreen;
}
<flex-container>
<flex-item></flex-item>
<flex-item></flex-item>
<flex-item></flex-item>
<flex-item></flex-item>
<flex-item></flex-item>
</flex-container>

flexbox and wrap property

You have quite a few things not quite right here. First, you're mixing old properties with new properties (display: -webkit-box is from the 2009 draft, but -webkit-flex-flow is from the standard draft).

Second, none of the 2009 Flexbox implementations support box-lines: multiple, which is required for enabling wrapping. Sadly, nearly all mobile devices support only the 2009 draft. Firefox versions that support the modern specification currently do not support wrapping either (flex-flow and flex-wrap are supported properties, but the values pertaining to wrapping are not supported).

Third, you've got justify-content: space-around, but its 2009 counterpart is set to box-pack: center. Center is center in all drafts.

http://cssdeck.com/labs/ccamtvl5

.flex-container {
display: -ms-flexbox;
display: -webkit-flex;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-ms-flex-line-pack: end;
-webkit-align-content: flex-end;
align-content: flex-end;
-ms-flex-pack: distribute;
-webkit-justify-content: space-around;
justify-content: space-around;
height: 100%;
}
@supports (flex-wrap: wrap) { /* hide from incomplete Firefox versions */
.flex-container {
display: flex;
}
}

Update: Wrapping now works in Firefox as of version 28, but only when using the modern properties (not the old prefixed ones like display: -moz-box).

How to specify when element should wrap with flexbox?

You could use min-width on the blocks. This means they will fully stretch, but when the screen size limits them to being 200px in this example, that breakpoint will lead them to wrap, and their width will never go below 200px.

Another option is to just apply flex-wrap: wrap; on that specific breakpoint you want with a media-query.

For further control, you could also look into flex-basis: https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis

EDIT: Responsive image

Genereally it's good to include this line of code on most images: max-width: 100%; height: auto; as this will make images auto-responsive. max-width: 100%; forces the image to never overflow from its container, and height: auto; adjusts the images height so its aspect ratio is correct. Try dragging the screen size and you will see its effect :)

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

.block1,
.block2 {
min-width: 200px;
}

.block2 img {
max-width: 100%;
height: auto;
}
<div class='flex-row'>

<div class="block1">

<h2>Some title</h2>
<p>Some text</p>
</div>

<div class="block2">

<img src="http://via.placeholder.com/350x350" />

</div>

</div>

Flexbox: how to wrap a flex item once the width of another flex item is 0?

You can approximate this by using a big flex-shrink on the first container. This will give more priority to the first container for the shrink effect.

.wrapper {
display: flex;
justify-content: space-between;
border: 1px solid red;
max-width: 600px;
}

.flex-wrapper {
display: flex;
min-width: 0;
flex-shrink:99999;
}

.header {
overflow: hidden;
display: inline-block;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 24px;
}

.actions {
display: flex;
flex-wrap: wrap;
column-gap:10px; /* you can use gap with flexbox*/
}
<div class="wrapper">
<div class="flex-wrapper">
<div class="header">
Lorem ipsum dolar sit amet constructeur
</div>
</div>
<div class="actions">
<button>
button1
</button>
<button>
button2
</button>
<button>
button3
</button>
<button>
button4
</button>
</div>
</div>

CSS: How can I ensure flex items wrap to the next line--after the first item--at a certain screen width?

Use the media query to apply flex-wrap:wrap on the flex container and flex:0 0 100% on the first child.

This way you don't need additional HTML markup, and no need to change anything on your code but the media query.

@media (max-width: 800px) {
.cart-cb{
flex-wrap:wrap;
}
.cart-cb div{
flex: 0 0 100%;
text-align:right;
}
}

https://jsfiddle.net/378b4yLy/

Better way to set distance between flexbox items

  • Flexbox doesn't have collapsing margins.
  • Flexbox doesn't have anything akin to border-spacing for tables (edit: CSS property gap fulfills this role in newer browsers, Can I use)

Therefore achieving what you are asking for is a bit more difficult.

In my experience, the "cleanest" way that doesn't use :first-child/:last-child and works without any modification on flex-wrap:wrap is to set padding:5px on the container and margin:5px on the children. That will produce a 10px gap between each child and between each child and their parent.

Demo

.upper {
margin: 30px;
display: flex;
flex-direction: row;
width: 300px;
height: 80px;
border: 1px red solid;

padding: 5px; /* this */
}

.upper > div {
flex: 1 1 auto;
border: 1px red solid;
text-align: center;

margin: 5px; /* and that, will result in a 10px gap */
}

.upper.mc /* multicol test */ {
flex-direction: column;
flex-wrap: wrap;
width: 200px;
height: 200px;
}
<div class="upper">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>

<div class="upper mc">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>

First-child and second in Flexbox

Following way you can achieve above layout using flexbox

First you need to create one parent div which have 3 children

<div class="row">
<div class="child child1">80%</div>
<div class="child child2">20%</div>
<div class="w-100">full Row</div>
</div>

Then we are going to provide css to layout our elements, so we will give flex and flex-wrap propertied to parent div.row, when we set flex-wrap property to wrap it will place child div to new row when there is no space available which child exactly required

Here is the css that will place our elements

 .row {
display: flex;
flex-wrap: wrap;
}
.child1 {
flex: 0 0 80%;
}
.child2 {
flex: 0 0 20%;
}
.w-100 {
flex: 0 0 100%;
background: yellow;
}

Here we are using css flex property to define width of the child element, here is the overview of flex property

CodeSandbox



Related Topics



Leave a reply



Submit