Mysterious behavior in flex-direction: column - css

When I write such code, I know that the text does not break.
.a {
display: flex;
border: 1px solid yellow;
}
.b {
border: 1px solid green;
overflow-wrap: break-word;
}
<div class="a">
<div class="b">texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext</div>
</div>
The cause of this problem is that min-width: auto sets the text width of the flex item tomin-width.Therefore, this problem is solved with min-width: 0.
.a {
display: flex;
border: 1px solid yellow;
}
.b {
border: 1px solid green;
overflow-wrap: break-word;
min-width: 0; /* add this code! */
}
<div class="a">
<div class="b">texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext</div>
</div>
Next I wrote such a code.
However, the min-width of that code did not work as I expected and a long word overflowed. This is a problem that did not occur at flex-direction: row. What is the cause of this?
Why does min-width: 0 not work in flex-direction: column?
.a {
display: flex;
flex-direction: column;
border: 1px solid yellow;
align-items: start;
}
.b {
border: 1px solid green;
overflow-wrap: break-word;
min-width: 0;
}
<div class="a">
<div class="b">texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext</div>
</div>

For flex-direction: row the main-axis is horizontal and the cross-axis is vertical.
For flex-direction: column they switch so the main-axis is vertical and cross-axis is horizontal, you know.
Now let me remind you that
justify-content, flex-grow, flex-shrink and flex-basis properties work on the main-axis
align-items works on the cross-axis
When you set align-items: start you're overriding the default align-items: stretch and your flex-item can take any width which is greater than min-width (as neither width nor max-width are specified).
To achieve the desired behavior it would be enough to remove align-items: start;
min-width: 0 can be also safely removed as it does nothing.
See the snippet below:
.a {
display: flex;
flex-direction: column;
border: 1px solid yellow;
/* align-items: start; let's use default value instead */
}
.b {
border: 1px solid green;
overflow-wrap: break-word;
/* min-width: 0; this does nothing */
}
<div class="a">
<div class="b">texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext</div>
</div>

You just need to give div .b an explicit width, or the element will expand to fit content. Using your code, this is as simple as:
.a {
display: flex;
flex-direction: column;
border: 1px solid yellow;
align-items: start;
}
.b {
border: 1px solid green;
overflow-wrap: break-word;
// min-width: 0;
width: 100%;
}
<div class="a">
<div class="b">texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext</div>
</div>

Related

Text breaking out of flexbox container

I've been working on learning flexbox for layout and have been unable to figure out why text is not wrapping inside the flex-item. The text is breaking out of the container like this:
html,
body {
height: 100%;
}
.main {
max-width: 10em;
margin: 1em auto;
}
.flex-row {
display: flex;
align-items: center;
justify-content: center;
min-height: 12em;
border: 1px solid red;
}
.flex-column {
display: flex;
flex-direction: column;
}
.flex-item {
padding: 5px;
border: 1px solid black;
}
<div class="main">
<div class="flex-row">
<div class="flex-column">
<div class="flex-item">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</div>
<div class="flex-item">
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
</div>
</div>
</div>
</div>
There are no spaces between your text.
The default value of the word-break property is normal, meaning that a continuous line of text has no line breaks.
For these reasons, your text is not wrapping and overflowing the container.
Add word-break: break-all to .flex-item.
html,
body {
height: 100%;
}
.main {
max-width: 10em;
margin: 1em auto;
}
.flex-row {
display: flex;
align-items: center;
justify-content: center;
min-height: 12em;
border: 1px solid red;
}
.flex-column {
display: flex;
flex-direction: column;
}
.flex-item {
padding: 5px;
border: 1px solid black;
word-break: break-all; /* new */
}
<div class="main">
<div class="flex-row">
<div class="flex-column">
<div class="flex-item">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</div>
<div class="flex-item">
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
</div>
</div>
</div>
</div>
From MDN:
word-break
The word-break CSS property specifies whether or not the browser
should insert line breaks wherever the text would otherwise overflow
its content box.
In contrast to overflow-wrap, word-break will create a break at
the exact place where text would otherwise overflow its container
(even if putting an entire word on its own line would negate the need
for a break).
Values
normal
Use the default line break rule.
break-all
To prevent overflow, word breaks should be inserted between any two
characters (excluding Chinese/Japanese/Korean text).
keep-all
Word breaks should not be used for Chinese/Japanese/Korean (CJK) text.
Non-CJK text behavior is the same as for normal.
There's actually another reason – flexbox-specific – why the flex items are overflowing the container. Here's the explanation:
Why doesn't flex item shrink past content size?
To contain the items (without the need for the text to wrap), you could apply min-width: 0, overflow: hidden or overflow: auto to .flex-column.
html,
body {
height: 100%;
}
.main {
max-width: 10em;
margin: 1em auto;
}
.flex-row {
display: flex;
align-items: center;
justify-content: center;
min-height: 12em;
border: 1px solid red;
}
.flex-column {
display: flex;
flex-direction: column;
overflow: hidden; /* new */
/* overflow: auto; */
/* min-width: 0; */
}
.flex-item {
padding: 5px;
border: 1px solid black;
}
<div class="main">
<div class="flex-row">
<div class="flex-column">
<div class="flex-item">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</div>
<div class="flex-item">
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
</div>
</div>
</div>
</div>

Flex auto margins behave differently in Chrome and Safari

Open this page in Chrome and in Safari and we can see the difference.
In Safari the "Maths" keyword is not on the right side as in Chrome.
Also the widths of the item-3 div is different in Chrome and in Safari.
My issue is that why it is different in Safari and what is the fix (I want CSS fix on the item-3).
flex-wrap: wrap is not a acceptable solution.
.main-container {
display: flex;
flex-direction: column;
width: 400px;
height: 300px;
border: 1px solid red;
}
.item-1 {
display: flex;
border: 1px solid blue;
}
.item-2 {
display: flex;
border: 1px solid green;
}
.item-3 {
display: flex;
margin-left: auto!important;
border: 2px solid yellow;
}
<div class="main-container">
<div class="item-1">Physics</div>
<div class="item-2">Chemistry</div>
<div class="item-3">Maths</div>
</div>
The width of .item-3 is different than its siblings because margin-left: auto packs the flex item to the right side. That's normal behavior for flex auto margins.
The reason margin-left doesn't work in Safari is a mystery / bug.
However, for cross-browser support, there is a simple flex alternative to auto margins in this case: align-self: flex-end
.main-container {
display: flex;
flex-direction: column;
width: 400px;
height: 300px;
border: 1px solid red;
}
.item-1 {
display: flex;
border: 1px solid blue;
}
.item-2 {
display: flex;
border: 1px solid green;
}
.item-3 {
display: flex;
align-self: flex-end; /* NEW */
border: 2px solid yellow;
}
<div class="main-container">
<div class="item-1">Physics</div>
<div class="item-2">Chemistry</div>
<div class="item-3"><span>Maths</span></div>
</div>
If you want .item-3 to keep the full width of the container, then use justify-content: flex-end.
.main-container {
display: flex;
flex-direction: column;
width: 400px;
height: 300px;
border: 1px solid red;
}
.item-1 {
display: flex;
border: 1px solid blue;
}
.item-2 {
display: flex;
border: 1px solid green;
}
.item-3 {
display: flex;
justify-content: flex-end; /* NEW */
border: 2px solid yellow;
}
<div class="main-container">
<div class="item-1">Physics</div>
<div class="item-2">Chemistry</div>
<div class="item-3">Maths</div>
</div>
How align-self: flex-end works
With align-self: flex-end you're shifting .item-3 along the cross axis all the way to the right.
This works because the flex container (.main-container) has flex-direction: column, which makes the main axis vertical and cross axis horizontal.
How justify-content: flex-end works
With justify-content: flex-end you're shifting the children of .item-3 along the main axis all the way to the right.
This works because .item-3 is a flex container with flex-direction: row (by default), which makes the main axis horizontal and cross axis vertical.
Then, as per the specification, text in a flex container that is not explicitly wrapped by an element, is considered an anonymous flex item. This allows justify-content to work.
4. Flex Items
Each in-flow child of a flex container becomes a flex item, and each
contiguous run of text that is directly contained inside a flex
container is wrapped in an anonymous flex item.
Why text-align: right doesn't work
text-align: right won't work because flex items (including anonymous ones) are considered block-level elements. The text-align property applies only to inline-level content.
More information
Learn more about flex alignment along the main axis here:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
Learn more about flex alignment along the cross axis here:
How does flex-wrap work with align-self, align-items and align-content?

issue with flexbox columns

I have a flex grid with equal columns, but in some of them i have some padding. It appears that this breaks the columns width.
I tried to add the padding to an inner wrapper, but this won't work for me as its percent based.
.grid{
width: 100%;
display: flex;
flex-direction: row;
}
.column {
flex: 1 1 100%;
display: block;
height: 200px;
background-color: #e5e5e5;
border: 1px solid #999999;
&.padd{
padding: 0 5%;
}
}
https://jsfiddle.net/heyapo/8qntbj3c/
Any ideas?
Quite simply flex-grow or flex-basis do not equal width.
Detailed explanation here: by Michael_B.
Padding will add to the dimensions of the element receiving it and the other elements will resolve their sizes accordingly.
If you want to use width...use width (and box-sizing).
.grid {
width: 100%;
display: flex;
flex-direction: row;
}
.column {
width: calc(100% / 3);
display: block;
height: 200px;
background-color: #e5e5e5;
border: 1px solid #999999;
}
padd {
padding: 0 20px;
}
<div class="grid">
<div class="column"></div>
<div class="column"></div>
<div class="column padd"></div>
</div>

Flexbox child collapsed after aligning

Can't figure out how to keep the child items same height on both sides after aligning their content to the middle.
My aim is to create a layout as seen in picture:
<div class="halves">
<div class="half">
<div class="half-inner is-right">H1</div>
</div>
<div class="half">
<div class="half-inner is-left">H2
<br> asdfs df <br>a sdfadsf sdfa dadsf df asdf afdf sadf asdf </div>
</div>
.halves{
display: flex;
border: 5px solid red;
.half{
flex: 1;
border: 10px solid yellow;
/* align-items: center; */
display: flex;
.half-inner{
max-width: 100px;
&.is-right{
margin-left: auto;
background: pink;
}
&.is-left{
background: green;
}
}
}
}
My current code here: http://codepen.io/zsitro/pen/YqpLba
In my example uncommenting /* align-items: center; */ you can see the child item collapses.
I appreciate any guidance. ty
align-items: center forces the div into the center of a flex container, and in the event of no specific declarations of width/height/flex-basis/whatnot, it makes the div as big as its content, preserving the whitespace. If you want the div to stretch, you will need the the align-items value to be stretch so it takes up the entire height of the parent container.
Additionally, if you want the .half-inner divs to be equal in width: flex: 1 (or flex-grow: 1) is a child property, so the declaration you currently have only applies to the .half divs, not the .half-inner divs. Since the parent .half div is a flex container, you can just add flex:1 under the .half-inner CSS and you should be good to go.
.halves{
display: flex;
border: 5px solid red;
.half{
flex: 1;
border: 10px solid yellow;
align-items: stretch;
display: flex;
.half-inner{
max-width: 100px;
flex: 1;
&.is-right{
margin-left: auto;
background: pink;
}
&.is-left{
background: green;
}
}
}
}

Flex box container width doesn't grow [duplicate]

This question already has answers here:
When flexbox items wrap in column mode, container does not grow its width
(9 answers)
Closed 6 years ago.
When using flex box in default row direction, the container height grows to contain all the flex items, even if it is absolutely positioned.
#container {
position: absolute;
display: flex;
flex-wrap: wrap;
}
#container > div {
flex: 0 0 200px;
height: 200px;
}
See http://codepen.io/tamlyn/pen/dPjLoN/?editors=110
However if the flex direction is changed to column, the container collapses to the width of a single flex item, even if the items wrap onto the next column.
#container {
position: absolute;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
#container > div {
flex: 0 0 200px;
width: 200px;
}
See http://codepen.io/tamlyn/pen/rarbeN?editors=110
How can I make the container contain all flex items in column mode?
I've actually found a CSS-only solution to this but it isn't the most perfect thing in the world. Here it is: http://codepen.io/anon/pen/vEPBKK
The trick here is to create a visibility: collapsed container. In flex, visibility: collapsed objects take themselves out of the normal flex flow but retain their dimensions for the purpose of layout. This widens the flex container to the desired width but leaves the flex items unaffected. There are a few caveats, however:
This requires a bit of fiddling. As you can see, the magic <div> is a set width but it uses :nth-child to determine how many boxes are before it. If your actual design breaks at more or less than 3 rows, you'll have to adjust this and you'll most certainly have to adjust the width of the object.
Because of a rendering bug, this does not work in IE. Luckily, IE's incorrect implementation does exactly what you wanted in the first place without any changes so all you have to do is give IE it's own stylesheet with some conditional statements and shoot the div.magic some good old display: none.
HTML
<div id="container">
<div class="fb"></div>
<div class="fb"></div>
<div class="fb"></div>
<div class="fb"></div>
<div class="fb"></div>
<div class="fb"></div>
<div class="fb"></div>
<div class="magic"></div>
</div>
CSS
#container {
position: absolute;
display: flex;
flex-direction: column;
flex-wrap: wrap;
border: 1px solid #f00;
height: 650px;
padding: 1px;
}
#container div.fb {
border: 1px solid #555;
flex: 0 0 200px;
background-color: #ccc;
width: 200px;
margin: 1px;
height: 200px;
}
#container > div.magic {
height: 0;
margin: 0;
padding: 0;
visibility: collapsed;
}
#container > div.magic:nth-child(5),
#container > div.magic:nth-child(6),
#container > div.magic:nth-child(7) {
width: 408px;
}
#container > div.magic:nth-child(8),
#container > div.magic:nth-child(9),
#container > div.magic:nth-child(10) {
width: 612px;
}
#container > div.magic:nth-child(11),
#container > div.magic:nth-child(12),
#container > div.magic:nth-child(13) {
width: 816px;
}
I think this is the CSS you're looking for:
#container {
display: flex;
flex-flow: row wrap;
border: 1px solid #f00;
padding: 1px;
}
#container > * {
border: 1px solid #555;
background-color: #ccc;
height: 200px;
width: 200px;
margin: 1px;
}
The "Container" will always the the width of it's container, in this case the page, but now the boxes will adjust within it properly.
Let me know if I misunderstood your question.
Update
I've been playing with what you're asking for for several days now, and it really seems like it's not possible to do what you're asking... at least not in the direction that you're asking.
The container wants to be the maximum width possible. Unless you force the container to be the exact width, at which point it wont be the full width, but it wont flex with the flexing content either.
.flex-container {
padding: 0;
margin: 0;
list-style: none;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
justify-content: space-around;
border: 1px solid #f00;
}
.flex-item {
background-color: #ccc;
padding: 5px;
width: 200px;
height: 150px;
line-height: 150px;
color: white;
font-weight: bold;
font-size: 3em;
text-align: center;
border: 1px solid #555;
}
<div id="container" class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
<div class="flex-item">7</div>
</div>
The first try I do not understand what you mean
as reference material you can see this tutorial
https://css-tricks.com/snippets/css/a-guide-to-flexbox/

Resources