Flex-box ignores wrapped children's margin (margin collapse) - css

Given the following HTML:
<div class="outer">
<div>
<div class="inner">A</div>
</div>
</div>
<div class="outer">
<div class="inner">B</div>
</div>
and the following CSS (prefix free):
.outer {
display: box;
box-orient: vertical;
height: 100px;
width: 100px;
background: red;
margin: 10px;
}
.inner {
height: 50px;
margin-top: 10px;
background: green;
}
Here is a CodePen.
A is wrapped in a <div> so it's margin gets ignored.
Q: How can I achieve B's behavior for A (margin) with the flex box model?
Note: The div wrappers can go multiple levels deep
Targeting: latest Chrome/Safari/iOS
Thank you very much for your help!
Edit: Thanks to #JoséCabo I came up with this:
.outer {
display: flex;
flex-direction: column;
height: 100px;
width: 100px;
background: red;
margin: 10px;
}
.inner {
height: 50px;
margin-top: 10px;
background: green;
}
CodePen
Chrome:
Safari:
Unfortunately it doesn't work in Safari as mentioned by #cimmanon, so I still need some help.

What you're looking at actually has nothing to do with Flexbox, but what's called margin collapse
.outer div {
border: 1px solid;
}
The addition of the border has prevented the margin from collapsing. Rather than relying on margins, I would recommend placing a padding on the parent container:
.outer {
padding-top: 10px;
}
Example:
.wrapper {
background: #eef;
border: 1px solid darkgray;
}
.container {
display: flex;
flex-wrap: wrap;
margin: -1em;
}
.item {
flex-grow: 1;
margin: 1em;
border: 1px solid black;
padding: 1em;
min-width: 6em;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div class="wrapper">
<div class='container'>
<div class='item'>item</div>
<div class='item'>item</div>
<div class='item'>item</div>
<div class='item'>item</div>
<div class='item'>item</div>
<div class='item'>item</div>
</div>
</div>
</body>
</html>
Now, to cover all of your prefixes, you need something like this:
.outer {
display: -moz-box;
display: -webkit-flexbox;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-moz-box-orient: vertical;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
height: 100px;
width: 100px;
background: red;
margin: 10px;
}

Finally I came up with the right solution (for my specific problem).
.outer {
display: flex;
flex-direction: column;
height: 100px;
width: 100px;
background: red;
margin: 10px;
}
.inner {
height: 50px;
margin-top: 10px;
background: green;
display: inline-block;
width: 100%;
}
CodePen
I'm using display: inline-block on .inner to disable margin collapsing and then compensate for the lost width with width: 100%.
All the credit goes to cimmanon for pointing me in the right "margin collapse" direction

Related

CSS white-space: nowrap; not respecting max-width [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 4 months ago.
CSS white-space: nowrap; not respecting max-width
Reproduce:
Run the below code
White-space is causing this issue where it increase the width of the right container and igroring the max-width of parent container
Current result: Width of right excees the max- width: 1680px;
Expected Result : Width should not exceed max-width: 1680px;
<!DOCTYPE html>
<html>
<head>
<title>test application</title>
<style>
body {
background-color: red;
}
div{
box-sizing: border-box;
}
.container {
align-items: stretch;
max-width: 1680px;
margin-left: auto;
margin-right: auto;
display: flex;
justify-content: flex-start;
}
.container .left {
background-color: blue;
display: flex;
width: 18em;
padding: 3em 2em 3em 2em;
position: relative;
color: white;
flex-direction: column;
margin-right: 2em;
min-height: calc(100vh - 150px);
flex-grow: 0;
flex-shrink: 0;
}
.container .right {
background-color: green;
width: 100%;
padding: 0em 3em 3em 3em;
flex: 1
}
.b2 {
width: auto;
white-space: nowrap;
overflow: hidden;
}
.abc {
display: inline-flex;
/* width: 1640px; */
overflow: hidden;
}
</style>
</head>
<body>
<div class="container">
<div class="left">left </div>
<div class="right">
<div class="b2">
<div class="abc">
rightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightright
</div>
<div class="abc">
rightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightright
</div>
</div>
</div>
</div>
</body>
</html>
The white-spacing relies on white-spaces to break the text apart. Since you don't have any, the text will not break onto the new line.
There are multiple ways to deal with this.
For example you could set overflow-wrap: anywhere and word-wrap: normal to the .abc selector. But this will also break whole-words apart ignoring standard syllable-based word wrapping.
You could also cut out the excess by forcefully setting overflow: hidden, white-space: nowrap together with a max-width and maybe text-overflow: ellipsis. But this will actually hide the information.
Caveat: The overflow-wrap: anywhere is unfortunately not supported by Safari.
It depends on what you want to achieve.
Example with 'overflow-wrap: anywhere'
<!DOCTYPE html>
<html>
<head>
<title>test application</title>
<style>
body {
background-color: red;
}
div {
box-sizing: border-box;
}
.container {
align-items: stretch;
max-width: 1680px;
margin-left: auto;
margin-right: auto;
display: flex;
justify-content: flex-start;
}
.container .left {
background-color: blue;
display: flex;
width: 18em;
padding: 3em 2em 3em 2em;
position: relative;
color: white;
flex-direction: column;
margin-right: 2em;
min-height: calc(100vh - 150px);
flex-grow: 0;
flex-shrink: 0;
}
.container .right {
background-color: green;
width: 100%;
padding: 0em 3em 3em 3em;
flex: 1
}
.b2 {
width: auto;
white-space: nowrap;
overflow: hidden;
}
.abc {
display: inline-flex;
overflow-wrap: anywhere;
white-space: normal;
overflow: hidden;
}
</style>
</head>
<body>
<div class="container">
<div class="left">left </div>
<div class="right">
<div class="b2">
<div class="abc">
rightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightright
</div>
<div class="abc">
rightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightright
</div>
</div>
</div>
</div>
</body>
</html>
Example with 'text-overflow: ellipsis'
<!DOCTYPE html>
<html>
<head>
<title>test application</title>
<style>
body {
background-color: red;
}
div {
box-sizing: border-box;
}
.container {
align-items: stretch;
max-width: 1680px;
margin-left: auto;
margin-right: auto;
display: flex;
justify-content: flex-start;
}
.container .left {
background-color: blue;
display: flex;
width: 18em;
padding: 3em 2em 3em 2em;
position: relative;
color: white;
flex-direction: column;
margin-right: 2em;
min-height: calc(100vh - 150px);
flex-grow: 0;
flex-shrink: 0;
}
.container .right {
background-color: green;
width: 100%;
padding: 0em 3em 3em 3em;
flex: 1
}
.b2 {
width: auto;
white-space: nowrap;
overflow: hidden;
}
.abc {
display: block;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
max-width: 100ch;
/* 100 characters max */
max-width: 1000px;
/* 1000px max */
}
</style>
</head>
<body>
<div class="container">
<div class="left">left </div>
<div class="right">
<div class="b2">
<div class="abc">
rightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightright
</div>
<div class="abc">
rightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightrightright
</div>
</div>
</div>
</div>
</body>
</html>

How to have a fluid flex layout

I am trying to make a fluid flex field where if there is no enough space then it should drop to next line. As you can see in this example if you decrease the size of the field it doesnt drop to next line because I am using flex.
.container {
width: 80%;
border: 2px solid #ddd;
padding: 20px;
display: flex;
overflow: hidden;
}
.container .panel {
flex: none;
}
.container .panel-info {
display: flex;
align-items: center;
}
.container .panel-info .dot {
background-color: #ccc;
width: 4px;
height: 4px;
border-radius: 50%;
margin: 0 8px;
}
<div class="container">
<div class="panel">Some Long Info</div>
<div class="panel-info">
<div class="dot"></div>
<div class="info">Information</div>
</div>
</div>
Use flex-wrap: wrap.
More information on MDN about the flex-wrap property

How create proper flexbox to make one column inside of content scrollable and another one static?

I want to create a layout where we have a header (responsive, with any height), footer (responsive, with any height), and content that fills the rest of space. Content should have two columns - first(right) that fits the content and second(left) that is very long and should have overflow with y-axis scrolling.
Detailed snipped with HTML and CSS attached.
I have problem with making them work inside of flexible height. I know how to make it work when I have only two columns, but with a responsive footer and header, I have problems.
I also have a code snippet inside of codepen
Thanks in advance for any help :)
html,
body {
height: 100%;
width: 100%;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
}
.column {
background-color: white;
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
color: black;
border: 5px purple solid;
}
.column-with-overflow {
overflow: auto;
max-height: 100%;
flex-grow: 1;
}
.column-with-overflow-content {
height: 1000px;
background-color: blue;
display: flex;
}
.columns {
display: flex;
flex-direction: row;
background-color: yellow;
width: 100%;
max-height: 100%;
}
.content {
background-color: blue;
flex-grow: 1;
}
.box {
text-align: center;
color: white;
display: flex;
justify-content: center;
}
.header {
background-color: green;
height: 60px; // assume that It's not known - any height
}
.footer {
background-color: red;
height: 60px; // assume that It's not known - any height
}
<div class="container">
<div class="box header">Header</div>
<div class="box content">
<div class="columns">
<div class='column column-with-overflow'>
<div class='column-with-overflow-content'>
box 1
</div>
</div>
<div class='column'>box 2</div>
</div>
</div>
<div class="box footer">Footer</div>
</div>
Set a fixed height to your .box.content div element.
And use min-height in .column-with-overflow-content insted of height
html,
body {
height: 100%;
width: 100%;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
}
.column {
background-color: white;
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
color: black;
border: 5px purple solid;
}
.column-with-overflow {
overflow: auto;
max-height: 100%;
flex-grow: 1;
}
.column-with-overflow-content {
min-height: 1000px; /* use min-height */
background-color: blue;
display: flex;
}
.columns {
display: flex;
flex-direction: row;
background-color: yellow;
width: 100%;
max-height: 100%;
}
.content {
background-color: blue;
flex-grow: 1;
}
.box.content { height: 100px; } /* set height to columns container */
.box {
text-align: center;
color: white;
display: flex;
justify-content: center;
}
.header {
background-color: green;
height: 60px; // assume that It's not known - any height
}
.footer {
background-color: red;
height: 60px; // assume that It's not known - any height
}
<div class="container">
<div class="box header">Header</div>
<div class="box content">
<div class="columns">
<div class='column column-with-overflow'>
<div class='column-with-overflow-content'>
box 1
</div>
</div>
<div class='column'>box 2</div>
</div>
</div>
<div class="box footer">Footer</div>
</div>

Flexbox item is not aligned when it line-breaks because of too much text

Here is small codepen example of problem.
https://codepen.io/artyor/pen/OJMrXMX
<div class="wrap">
<a>Row One</a>
<a>Row Two</a>
<a>Problematic Row</a>
<a>Row Four</a>
<a>Row Five</a>
</div>
<style>
body{
margin: 0;
background: gray;
display: flex;
justify-content: center;
align-items: center;
}
.wrap{
width: 200px;
height: auto;
background: silver;
font-size: 30px;
/* problem*/
display: flex;
flex-direction: column;
align-items: center;
}
.wrap > a{
border: 1px solid red;
}
</style>
Once the text in tag is too long, it line-breaks, which is normal and what I want.
But when that happens it puts only that item out of the flow, it's not centered anymore, and even if I somehow make it centered, it still takes full width of container(.wrap).
How do I make it act like other tags?
Does this provide an answer for you?
body{
margin: 0;
background: gray;
display: flex;
justify-content: center;
align-items: center;
}
.wrap{
width: 150px;
max-width: 150px;
height: auto;
background: silver;
font-size: 30px;
/* problem*/
display: flex;
flex-direction: column;
align-items: center;
}
.wrap > a{
width: 150px;
border: 1px solid red;
text-align:center;
}
<div class="wrap">
<a>Row One</a>
<a>Row Two</a>
<a>Problematic Row</a>
<a>Row Four</a>
<a>Row Five</a>
</div>
I just inserted these properties in .wrap class:
max-width: 150px to set the maximum value achievable for the elements width;
text-align: center to make the text aligned at the center horizontally.
Also I changed the values of .wrap > a width to 150px, to make the example the most clear possible.

How to make equal space between boxes in one row via CSS

I have a requirement that there are 4 boxes in one row.
the boxes have fixed width and height
but the width of the row will change by screen size.
the first box should be aligned to the left border of the row
last box aligned to right border.
Also the space between any two boxes should be equal.
Is there a pure CSS way to make that happen? Here is the jsfiddle code.
HTML:
<div class="row">
<div class ="col">
<div class="box"></div>
</div>
<div class ="col">
<div class="box"></div>
</div>
<div class ="col">
<div class="box"></div>
</div>
<div class ="col">
<div class="box"></div>
</div>
</div>
CSS:
.row {
display: table;
border: 1px solid green;
width: 400px; /* it changes by screen size actually */
padding: 5px;
}
.row:before, .row:after {
content: "";
}
.row:after {
clear: both;
}
.col {
float: left;
width: 25%;
}
.box {
border: 1px solid #DDD;
width: 80px;
height: 80px;
margin: 0 auto;
}
.col:first-child .box {
margin-left: 0;
}
.col:last-child .box {
margin-right: 0;
}
Use text-align:justify on the container, this way it will work no matter how many elements you have in your div (you don't have to work out % widths for each list item
Updated CSS
.row {
text-align: justify;
min-width: 412px;
border: 1px solid green;
width: 80%; /* it changes by screen size actually */
height: 90px;
padding: 5px;
}
.row:after {
content: '';
display: inline-block;
width: 100%;
}
.col {
display: inline-block;
}
.box {
border: 1px solid #DDD;
width: 80px;
height: 80px;
margin: 0 auto;
}
FIDDLE
You can make use of css3 flex boxes which is supported in modern browsers.
.row {
display: flex;
justify-content: space-between;
border: 1px solid green;
}
.box {
border: 1px solid #DDD;
width: 80px;
height: 80px;
}
<div class="row">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
jsfiddle demo
more about flex boxes # css tricks
Why not use flexbox ?
Demo
css
.flex-container {
padding: 5px;
margin: 0;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
justify-content: space-between; /* this make the end divs at sides and equal space between other divs */
}
.flex-item {
background: tomato;
padding: 5px;
width: 200px;
height: 150px;
margin-top: 10px;
line-height: 150px;
color: white;
font-weight: bold;
font-size: 3em;
text-align: center;
}
html
<div 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>
Read here for more detail on flexbox
you simply have to remove the padding attribute from the following
.row {
display: table;
border: 1px solid green;
width: 400px; /* it changes by screen size actually */
/*padding: 5px;*/
}
here is the demo.
Let me know if this was helpful or if you have anymore queries.

Resources