So, to wrap elements in a flex div using a row layout all I have to do is this:
div {
display: flex;
flex-direction: row; /* I want to change this to column */
flex-wrap: wrap; /* wrap doesn't seem to work on column, only row */
}
<div>
<p>these</p>
<p>will</p>
<p>wrap</p>
</div>
This works for my rows, but I want to make it work for my columns as well.
I tried just changing flex-direction to column, but it doesn't seem to be working. Does anyone know how to get this functionality?
Block-level elements, by default, take up the full width of their containing block. This, in effect, resolves to width: 100%, which sets a break in the flow of content in the horizontal direction.
So, flex items can wrap by default in a row-direction container.
Nothing in HTML or CSS, however, sets a default height on block-level elements. Heights are content-driven (height: auto).
This means that elements will flow vertically without having any reason to break.
(I guess somewhere along the line of evolution, possibly on the basis of usability studies, it was decided that it would be okay for web applications to expand vertically, but not horizontally.)
That's why flexbox doesn't automatically wrap items in column direction. It requires an author-defined height to serve as a breaking point.
Often times, however, a layout's height is dynamic so a specific height cannot be set. That makes flexbox unusable for wrapping items in column direction. A great alternative is CSS Grid Layout, which doesn't require a height setting on the container:
div {
display: grid;
grid-gap: 10px;
}
p:nth-child(3n + 1) {
grid-row: 1;
background-color: aqua;
}
p:nth-child(3n + 2) {
grid-row: 2;
background-color: orange;
}
p:nth-child(3n + 3) {
grid-row: 3;
background-color: lightgreen;
}
p {
margin: 0;
padding: 10px;
}
<div>
<p>ONE</p>
<p>TWO</p>
<p>THREE</p>
<p>FOUR</p>
<p>FIVE</p>
<p>SIX</p>
<p>SEVEN</p>
<p>EIGHT</p>
<p>NINE</p>
</div>
Browser Support for CSS Grid
Chrome - full support as of March 8, 2017 (version 57)
Firefox - full support as of March 6, 2017 (version 52)
Safari - full support as of March 26, 2017 (version 10.1)
Edge - full support as of October 16, 2017 (version 16)
IE11 - no support for current spec; supports obsolete version
Here's the complete picture: http://caniuse.com/#search=grid
Related
Consider the main axis and cross axis of a flex container:
Source: W3C
To align flex items along the main axis there is one property:
justify-content
To align flex items along the cross axis there are three properties:
align-content
align-items
align-self
In the image above, the main axis is horizontal and the cross axis is vertical. These are the default directions of a flex container.
However, these directions can be easily interchanged with the flex-direction property.
/* main axis is horizontal, cross axis is vertical */
flex-direction: row;
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.)
My point in describing how the axes' work is that there doesn't seem to be anything special about either direction. Main axis, cross axis, they're both equal in terms of importance and flex-direction makes it easy to switch back and forth.
So why does the cross axis get two additional alignment properties?
Why are align-content and align-items consolidated into one property for the main axis?
Why does the main axis not get a justify-self property?
Scenarios where these properties would be useful:
placing a flex item in the corner of the flex container
#box3 { align-self: flex-end; justify-self: flex-end; }
making a group of flex items align-right (justify-content: flex-end) but have the first item align left (justify-self: flex-start)
Consider a header section with a group of nav items and a logo. With justify-self the logo could be aligned left while the nav items stay far right, and the whole thing adjusts smoothly ("flexes") to different screen sizes.
in a row of three flex items, affix the middle item to the center of the container (justify-content: center) and align the adjacent items to the container edges (justify-self: flex-start and justify-self: flex-end).
Note that values space-around and space-between on
justify-content property will not keep the middle item centered about the container if the adjacent items have different widths.
#container {
display: flex;
justify-content: space-between;
background-color: lightyellow;
}
.box {
height: 50px;
width: 75px;
background-color: springgreen;
}
.box1 {
width: 100px;
}
.box3 {
width: 200px;
}
#center {
text-align: center;
margin-bottom: 5px;
}
#center > span {
background-color: aqua;
padding: 2px;
}
<div id="center">
<span>TRUE CENTER</span>
</div>
<div id="container">
<div class="box box1"></div>
<div class="box box2"></div>
<div class="box box3"></div>
</div>
<p>note that the middlebox will only be truly centered if adjacent boxes are equal width</p>
jsFiddle version
As of this writing, there is no mention of justify-self or justify-items in the flexbox spec.
However, in the CSS Box Alignment Module, which is the W3C's unfinished proposal to establish a common set of alignment properties for use across all box models, there is this:
Source: W3C
You'll notice that justify-self and justify-items are being considered... but not for flexbox.
I'll end by reiterating the main question:
Why are there no "justify-items" and "justify-self" properties?
Methods for Aligning Flex Items along the Main Axis
As stated in the question:
To align flex items along the main axis there is one property: justify-content
To align flex items along the cross axis there are three properties: align-content, align-items and align-self.
The question then asks:
Why are there no justify-items and justify-self properties?
One answer may be: Because they're not necessary.
The flexbox specification provides two methods for aligning flex items along the main axis:
The justify-content keyword property, and
auto margins
justify-content
The justify-content property aligns flex items along the main axis of the flex container.
It is applied to the flex container but only affects flex items.
There are five alignment options:
flex-start ~ Flex items are packed toward the start of the line.
flex-end ~ Flex items are packed toward the end of the line.
center ~ Flex items are packed toward the center of the line.
space-between ~ Flex items are evenly spaced, with the first item aligned to one edge of the container and the last item aligned to the opposite edge. The edges used by the first and last items depends on flex-direction and writing mode (ltr or rtl).
space-around ~ Same as space-between except with half-size spaces on both ends.
Auto Margins
With auto margins, flex items can be centered, spaced away or packed into sub-groups.
Unlike justify-content, which is applied to the flex container, auto margins go on flex items.
They work by consuming all free space in the specified direction.
Align group of flex items to the right, but first item to the left
Scenario from the question:
making a group of flex items align-right (justify-content: flex-end)
but have the first item align left (justify-self: flex-start)
Consider a header section with a group of nav items and a logo. With
justify-self the logo could be aligned left while the nav items stay
far right, and the whole thing adjusts smoothly ("flexes") to
different screen sizes.
Other useful scenarios:
Place a flex item in the corner
Scenario from the question:
placing a flex item in a corner .box { align-self: flex-end; justify-self: flex-end; }
Center a flex item vertically and horizontally
margin: auto is an alternative to justify-content: center and align-items: center.
Instead of this code on the flex container:
.container {
justify-content: center;
align-items: center;
}
You can use this on the flex item:
.box56 {
margin: auto;
}
This alternative is useful when centering a flex item that overflows the container.
Center a flex item, and center a second flex item between the first and the edge
A flex container aligns flex items by distributing free space.
Hence, in order to create equal balance, so that a middle item can be centered in the container with a single item alongside, a counterbalance must be introduced.
In the examples below, invisible third flex items (boxes 61 & 68) are introduced to balance out the "real" items (box 63 & 66).
Of course, this method is nothing great in terms of semantics.
Alternatively, you can use a pseudo-element instead of an actual DOM element. Or you can use absolute positioning. All three methods are covered here: Center and bottom-align flex items
NOTE: The examples above will only work – in terms of true centering – when the outermost items are equal height/width. When flex items are different lengths, see next example.
Center a flex item when adjacent items vary in size
Scenario from the question:
in a row of three flex items, affix the middle item to the center of the container (justify-content: center) and align the adjacent
items to the container edges (justify-self: flex-start and
justify-self: flex-end).
Note that values space-around and space-between on justify-content property will not keep the middle item centered in relation to the container if the adjacent items have different widths (see demo).
As noted, unless all flex items are of equal width or height (depending on flex-direction), the middle item cannot be truly centered. This problem makes a strong case for a justify-self property (designed to handle the task, of course).
#container {
display: flex;
justify-content: space-between;
background-color: lightyellow;
}
.box {
height: 50px;
width: 75px;
background-color: springgreen;
}
.box1 {
width: 100px;
}
.box3 {
width: 200px;
}
#center {
text-align: center;
margin-bottom: 5px;
}
#center > span {
background-color: aqua;
padding: 2px;
}
<div id="center">
<span>TRUE CENTER</span>
</div>
<div id="container">
<div class="box box1"></div>
<div class="box box2"></div>
<div class="box box3"></div>
</div>
<p>The middle box will be truly centered only if adjacent boxes are equal width.</p>
Here are two methods for solving this problem:
Solution #1: Absolute Positioning
The flexbox spec allows for absolute positioning of flex items. This allows for the middle item to be perfectly centered regardless of the size of its siblings.
Just keep in mind that, like all absolutely positioned elements, the items are removed from the document flow. This means they don't take up space in the container and can overlap their siblings.
In the examples below, the middle item is centered with absolute positioning and the outer items remain in-flow. But the same layout can be achieved in reverse fashion: Center the middle item with justify-content: center and absolutely position the outer items.
Solution #2: Nested Flex Containers (no absolute positioning)
.container {
display: flex;
}
.box {
flex: 1;
display: flex;
justify-content: center;
}
.box71 > span { margin-right: auto; }
.box73 > span { margin-left: auto; }
/* non-essential */
.box {
align-items: center;
border: 1px solid #ccc;
background-color: lightgreen;
height: 40px;
}
<div class="container">
<div class="box box71"><span>71 short</span></div>
<div class="box box72"><span>72 centered</span></div>
<div class="box box73"><span>73 loooooooooooooooong</span></div>
</div>
Here's how it works:
The top-level div (.container) is a flex container.
Each child div (.box) is now a flex item.
Each .box item is given flex: 1 in order to distribute container space equally.
Now the items are consuming all space in the row and are equal width.
Make each item a (nested) flex container and add justify-content: center.
Now each span element is a centered flex item.
Use flex auto margins to shift the outer spans left and right.
You could also forgo justify-content and use auto margins exclusively.
But justify-content can work here because auto margins always have priority. From the spec:
8.1. Aligning with auto
margins
Prior to alignment via justify-content and align-self, any
positive free space is distributed to auto margins in that dimension.
justify-content: space-same (concept)
Going back to justify-content for a minute, here's an idea for one more option.
space-same ~ A hybrid of space-between and space-around. Flex items are evenly spaced (like space-between), except instead of half-size spaces on both ends (like space-around), there are full-size spaces on both ends.
This layout can be achieved with ::before and ::after pseudo-elements on the flex container.
(credit: #oriol for the code, and #crl for the label)
UPDATE: Browsers have begun implementing space-evenly, which accomplishes the above. See this post for details: Equal space between flex items
PLAYGROUND (includes code for all examples above)
I know this is not an answer, but I'd like to contribute to this matter for what it's worth. It would be great if they could release justify-self for flexbox to make it truly flexible.
It's my belief that when there are multiple items on the axis, the most logical way for justify-self to behave is to align itself to its nearest neighbours (or edge) as demonstrated below.
I truly hope, W3C takes notice of this and will at least consider it. =)
This way you can have an item that is truly centered regardless of the size of the left and right box. When one of the boxes reaches the point of the center box it will simply push it until there is no more space to distribute.
The ease of making awesome layouts are endless, take a look at this "complex" example.
This was asked on the www-style list, and Tab Atkins (spec editor) provided an answer explaining why. I'll elaborate on that a bit here.
To start out, let's initially assume our flex container is single-line (flex-wrap: nowrap). In this case, there's clearly an alignment difference between the main axis and the cross axis -- there are multiple items stacked in the main axis, but only one item stacked in the cross axis. So it makes sense to have a customizeable-per-item "align-self" in the cross axis (since each item is aligned separately, on its own), whereas it doesn't make sense in the main axis (since there, the items are aligned collectively).
For multi-line flexbox, the same logic applies to each "flex line". In a given line, items are aligned individually in the cross axis (since there's only one item per line, in the cross axis), vs. collectively in the main axis.
Here's another way of phrasing it: so, all of the *-self and *-content properties are about how to distribute extra space around things. But the key difference is that the *-self versions are for cases where there's only a single thing in that axis, and the *-content versions are for when there are potentially many things in that axis. The one-thing vs. many-things scenarios are different types of problems, and so they have different types of options available -- for example, the space-around / space-between values make sense for *-content, but not for *-self.
SO: In a flexbox's main axis, there are many things to distribute space around. So a *-content property makes sense there, but not a *-self property.
In contrast, in the cross axis, we have both a *-self and a *-content property. One determines how we'll distribute space around the many flex lines (align-content), whereas the other (align-self) determines how to distribute space around individual flex items in the cross axis, within a given flex line.
(I'm ignoring *-items properties here, since they simply establish defaults for *-self.)
This is due to the one-dimensional nature of flexbox, and that there may be multiple items along the axis, making it impossible to justify a single item. To align items along the main, inline axis in flexbox you use the justify-content property.
Reference: Box alignment in CSS Grid Layout
I know this doesn't use flexbox, but for the simple use-case of three items (one at left, one at center, one at right), this can be accomplished easily using display: grid on the parent, grid-area: 1/1/1/1; on the children, and justify-self for positioning of those children.
<div style="border: 1px solid red; display: grid; width: 100px; height: 25px;">
<div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: left;"></div>
<div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: center;"></div>
<div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: right;"></div>
</div>
I just found my own solution to this problem, or at least my problem.
I was using justify-content: space-around instead of justify-content: space-between;.
This way the end elements will stick to the top and bottom, and you could have custom margins if you wanted.
So I have an issue that appears on Firefox.
Basically I have a container with set width (let's say 300px).
Inside it nested a couple of levels is a component that uses truncation to hide text with max-width. CSS rule would look like this for example:
max-width: calc( ((100vw - 376px) / 12) * 8 + 168px );
Child span uses basic line-clamp + overflow technique for hiding extra content.
What I found out is that this code constrains width of elements of component and truncation works fine on Chrome but it doesn't work as expected in Firefox. I guess that it makes sense since this calculation uses vw for setting max-width but it confuses me why it works on Chrome. Does Firefox somehow differently do calculations?
.wrapper {
width: 300px;
}
.max-width__component {
/* This is probably calculated to be a bigger value than width
of container */
max-width: calc( ((100vw - 376px) / 12) * 8 + 168px);
}
.truncation {
display: -webkit-box;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
<div class="wrapper">
<div class="max-width__component">
<span class="truncation">
Some dummy content that is normally longer and truncated
</span>
</div>
</div>
Thanks in advance.
The problem indeed wasn't with setting max-width
One thing that was missing from my code snippet was another child element that represents icons (https://codepen.io/Skafec/pen/yLbNBJM) but the issue still wasn't reproduced in this codepen.
How I fixed is that I added:
flex-shrink: 0;
on icon wrapper which makes sure that icon always takes the same space and doesn't get pushed outside of the main container.
I would like to display my clients first and last name in 2 different inputs in the center of the client page and give each input a minimum width to avoid extra spacing between the two.
I've tried to use min-width or use the "size" attribute for the inputs but it's causing problems when the first input has too much characters.
<div className="input-client-name">
<input value={this.state.fname}/>
<input value={this.state.lname}/>
</div>
.input-client-name {
display: flex;
}
.input-client-name input {
min-width: 0;
max-width: min-content;
}
I expect the output of: " firstName LastName " without worrying from the characters length of each of the ones.
If you're working with flexbox, it's advised to not play with width since we flexbox for achieving responsive behaviour and setting width (even max and min widths) to a value defeats that purpose.
Since you want input boxes displayed side-by-side, and based on window size - you may want to wrap second input box to next line - add a flex-flow to your parent.
.input-client-name {
display: flex;
flex-flow: row wrap;
}
flex-flow is a combination of flex-direction and flex-wrap properties.
Next, you want to give a min width to your input boxes, you can achieve this by using flex-basis - which works as an initial size for your element.
.input-client-name input {
flex-basis: 40%;
margin: 8px;
}
Note: margin is added as space between two input boxes. You can choose to use justify-content: space-between or justify-content: space-evenly for same purpose.
Additional references:
A demo fiddle for this is availale here.
Want to learn more about flexbox? Read a nice article on it here.
Hope this helps.
input {
text-align: center;
width: auto;
}
In this page on plunker (https://plnkr.co/edit/gMbgxvUqHNDsQVe4P7ny?p=preview) there is a weird problem.
On Chrome on Windows and Android (Canary also) everything works good. I can scroll the two areas (on the left and on the right) and the top and bottom div of the page are on the top and on the bottom of my device screen. I see them anytime (see the picture below).
On iPad or iPhone, iOS, with Safari or Chrome, this is not what I get. And also on Firefox 47.0.1 on Windows.
The page is long and there is just one scroll on the right, like if there is no flexbox on the page, this code is just ignored:
.bigone {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.main {
flex: 1 1 0;
display: flex;
}
.container-fluid {
display: flex;
}
.col-6 {
overflow-y: auto;
}
Quirk example:
You can see on the iPad or iPhone just by a click on this button:
Why this behaviour?
Safari and Firefox bug or Chrome's one?
Why on Chrome everything good on Windows and Android?
And if in the new Safari in the future this will work good, how to do with the older devices with older iOS and firefox?
I will appreciate any answer. Thanks.
It's both a frustrating and mysterious problem.
The source of the problem in these sorts of questions is normally the minimum sizing algorithm on flex items. These rules, which are part of the spec, prevent a flex item from shrinking past the size of its content. Such behavior prevents a scrollbar from rendering because the content cannot overflow a flex item. It simply expands it.
But none of the standard methods to override that behavior (e.g., min-height: 0, overflow: hidden) seem to work in this case.
Here are two suggestions that may get you closer to a solution:
(1) Since you want the entire layout to appear in the viewport (i.e., no vertical scrollbar on the browser window), don't use min-height to size the container. That allows the container to expand. Use a fixed height instead.
Make this adjustment to your code:
.bigone {
display: flex;
/* min-height: 100vh; <-- REMOVE */
height: 100vh; /* <-- NEW */
flex-direction: column;
}
But that, by itself, doesn't solve the problem.
(2) A simple and quick solution to the problem is to set a height on .col-6.
Add this to your code:
.col-6 {
height: 90vh;
}
So it would appear that Edge, FF and the other "non-working" browsers need a defined height on that container.
revised demo
The Michael_B's answer is not enough. 90vh doesn't work with dynamic header, footer and other divs.
I fixed this (temporarily, until Safari fix this) with this on parent div:
min-height: 100vh; height: 100vh;
and
flex: 1; min-height: 0;' on the first children.
But the smell is heavy.
Try:
margin: auto;
in the css for the flex-item - that did the trick for me (seems like the auto does the magic here ...)
Wanted to share that finding, as min-height, overflow-x, etc ... did not work reliably for me neither.
This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Why don't flex items shrink past content size?
(5 answers)
Closed 5 years ago.
In the following questions, I've been able to get all the cases to work out, I'm just looking to debug my mental model. I'm also only concerned with Chrome, if that makes answering easier.
I have an overflow:auto within nested "holy grail-ish" flexbox layouts. The overflow:auto behavior works fine for 2-level and 3-level nesting.
However, once I get to 4-level nesting, it "breaks," requiring me to specify the min-height:0 property (despite my having consistently specified flex-basis:0 via flex:1, which should annul the flex-basis:content/content-sized default). Why is this only happening at 4-level nesting?
Also, the element I need to slap the min-height:0 onto is .orange. Why this element, and why not the other ancestors?
Can anyone explain the above two questions? I have been consulting the spec and am having trouble connecting its rules back to my 4-level-deep example.
Note that this is different from the other questions I've been able to find on SO regarding flexbox and overflow, for instance (see in particular my answers):
overflow: auto in nested flexboxes
Nested flexbox with scrolling area
I have an overflow:auto within nested "holy grail-ish" flexbox layouts. The overflow:auto behavior works fine for 2-level and 3-level nesting.
Your 2-level code does indeed work as intended in Chrome, and IE11. However, it fails in Firefox. Same thing with your 3-level code: Works in Chrome and IE11, but not Firefox.
However, once I get to 4-level nesting, it "breaks," requiring me to specify the min-height:0 property (despite my having consistently specified flex-basis:0 via flex:1, which should annul the flex-basis:content/content-sized
default). Why is this only happening at 4-level nesting?
Once again, your statement is true for Chrome and IE11, but not for Firefox.
Solutions
Let's start with the fixes, so that all demos work in Chrome, Firefox and IE11. (I didn't test in Safari, but that's WebKit like Chrome, so it should be fine with vendor prefixes for any versions prior to 9.)
Also, I'll use compiled code in the answer, as not everybody uses preprocessors.
Revised 2-level (added two lines of code)
.violet {
flex: 1;
background: violet;
display: flex;
flex-direction: column;
min-height: 0; /* new */
min-width: 0; /* new */
}
Revised 3-level (added four lines of code)
.violet {
flex: 1;
background: violet;
display: flex;
flex-direction: column;
min-height: 0; /* new */
min-width: 0; /* new */
}
.orange {
flex: 1;
background: orange;
display: flex;
min-height: 0; /* new */
min-width: 0; /* new */
}
Revised 4-level (added one line of code)
.violet {
flex: 1;
background: violet;
display: flex;
flex-direction: column;
/* For some reason this is not needed */
/* min-height:0; */
min-width: 0; /* new */
}
Breaking Down the Behavior
There's a lot going on with your nesting. I'm not going to debug the code line-by-line, but I'll offer three concepts that may be useful to you.
1. Calculating Percentage Heights
Chrome, Firefox and IE11 can have different interpretations for an element's height.
Here's what it says in the spec:
CSS height property
percentage Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly and this element is not absolutely positioned, the value computes to "auto".
auto The height depends on the values of other properties.
Traditionally, when calculating percentage heights, browsers have interpreted the spec's use of the term "height" to mean the value of the height property.
Based on a reading of the height definition, the interpretation could just as easily be the computed height, but the height property requirement has become the predominant implementation. I've never seen min-height or max-height work on a parent when dealing with percentage heights.
Chrome expects to see the height property when calculating height. If it doesn't, it computes the height to auto. Firefox, however, has a broader interpretation of the spec. It accepts flex heights, as well (as evidenced here and here and here).
It's not clear which browsers are more compliant.
It doesn't help matters that the height property definition hasn't been updated since 1998 (CSS2).
In all three of your demos you're combining percentage heights, pixel heights and flex heights. You may want to keep the differing browser interpretations in mind when troubleshooting your code.
Here are some more details: Working with the CSS height property and percentage values
2. Why doesn't flex item shrink past content size?
3. flex-basis: 0 vs flex-basis: auto
flex: 1 1 auto (or flex: auto, for short), sizes a flex item based on the content size or height properties.
flex: 1 1 0 (or flex: 1, for short), sizes a flex item based on the free space in the flex container.
Each may have a different effect on the behavior of overflow: auto.
More details here: Page-filling flexbox layout with top and side bars not quite working