Source of the Problem
Here is the source of the problem:
.flexContainer {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: stretch;
align-content: flex-start; <-- problem
}
Background
The align-content
property controls the cross-axis alignment of flex lines within the flex container. Think of flex lines as the rows or columns (depending on flex-direction
) in which flex items live. Put another way, align-content
distributes the space between and around flex lines, packing them to the top, bottom, center, etc. (see the full list of values).
Because align-content
distributes space between and around flex lines, it can only work on multi-line flex containers. (A single-line extends across the full cross-axis length of the container leaving no free space for align-content
to work.)
Obviously, a multi-line container is a container with more than one line (flex items have wrapped). Technically, however, a multi-line container is simply a container with flex-wrap: wrap
or flex-wrap: wrap-reverse
(regardless of whether flex items have wrapped, or even exist).
Same concept applies to a single-line flex container, which is a container with flex-wrap: nowrap
. The align-content
property has no effect in nowrap
containers, as discussed above.
§ 8.4. Packing Flex Lines: the align-content
property
The align-content
property aligns a flex container’s lines within
the flex container when there is extra space in the cross-axis,
similar to how justify-content
aligns individual items within the
main-axis. Note, this property has no effect on a single-line flex
container.
§ 6. Flex
Lines
Flex items in a flex container are laid out and aligned within flex
lines, hypothetical containers used for grouping and alignment by the
layout algorithm. A flex container can be either single-line or
multi-line, depending on the flex-wrap
property:
A single-line flex container (i.e. one with flex-wrap: nowrap
) lays out all of its children in a single line, even if that would
cause its contents to overflow.
A multi-line flex container (i.e. one with flex-wrap: wrap
or flex-wrap: wrap-reverse
) breaks its flex items across multiple lines, similar to how text is broken onto a new line when it gets too wide to fit on the existing line.
The Discrepancy between Chrome and Firefox / Edge
Looking again at your code:
body {
background-color: teal;
}
.flexContainer {
background-color: blue;
border: 1px solid black;
height: 300px;
}
.flexItem {
background-color: red;
border: 1px solid black;
}
.flexContainer {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: stretch;
align-content: flex-start;
}
.flexItem {
flex: 0 1 0;
}
<div class="flexContainer">
<div class="flexItem">1111111111111111111</div>
<div class="flexItem">2222<br/>2222</div>
<div class="flexItem">3333<br/>3333<br/>3333</div>
<div class="flexItem">4444444444444444444</div>
</div>
Notice three things:
(1) There is no actual wrapping. All four items exist on one line. The flex container has one line.
(2) The flex-wrap
property is set to wrap
(in the flex-flow
shorthand).
(3) The align-content
property is set to flex-start
.
Let's break this down.
Because there is only a single line in the flex container, Chrome is ignoring align-content
. As written in the specification (see above):
The align-content
property has no effect on a single-line flex container.
So this is Chrome's interpretation. If there is an actual single line, then ignore align-content
.
Switch between wrap
and nowrap
in Chrome. There's no difference.
On the other hand, because the container is set to flex-wrap: wrap
, this technically creates a multi-line flex container, as far as Firefox and Edge are concerned. The actual wrapping or existence of flex items is irrelevant.
As written in the specification (see above):
A multi-line flex container (i.e. one with flex-wrap: wrap
or flex-wrap: wrap-reverse
) breaks its flex items across multiple lines...
Switch between wrap
and nowrap
in Firefox and Edge. There's a difference.
So each browser has it's own way of implementing this rendering behavior.
Standards Compliance
In terms of adherence to the specification, I would say that Firefox and Edge are at full compliance. They seem to adhere most closely to the wording in the spec.
However, I wouldn't characterize Chrome's behavior as a "bug". What they've done is more likely an intervention.
An intervention is when a user agent decides to deviate slightly from a standardized behavior in order to provide a greatly enhanced user experience.
Interventions appear to be standard practice at Chrome. Examples:
More Information