i have a complex layout in which i have a div generated by JavaScript with dynamic height, he is called ".outer" . This div has some nested divs, finally leading to a div called ".target". I need the target div to be at ".outers" height. And i don't want to address the inner divs since they are varying markup generated by my JS Framework.
I do not want to set the height via JS, i can not set position to absolute nor relative in ".outer"
HTML:
<div class="outer">
<div class="inner">
<div class="anotherInner">
<div class="target">
This div should be outer's height no matter how many divs are between target and outer like ".inner"
</div>
</div>
</div>
</div>
CSS:
body {
background: #000;
}
.outer {
background: #333;
height: 500px; /* this is not a pixel value, only for example*/
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: flex-start;
align-content: stretch;
align-items: stretch;
}
.inner {
background: #555;
}
.target {
background: #777;
order: 0;
flex: 1 1 auto;
align-self: auto;
}
Example:
http://codepen.io/anon/pen/akwWZK?editors=1100
The only possible way to do this in FlexBox is to address the .inner div's in your CSS by adding display: flex; to them.
I've created a working example for you here: http://codepen.io/mattpark22/pen/rLwwZp
To '.inner' add:
display: flex;
To '.target' add:
height: 100%;
To '.outer' change, flex-direction to:
flex-direction: row;
My codepen example also cleans up some CSS which isn't required.
Related
I have a container with children items:
HTML
<div id="container">
<div className="item">1</div>
<div className="item">2</div>
<div className="item">3</div>
<div className="item">4</div>
</div>
CSS
#container {
display: flex;
flex-direction: row;
gap: 10px;
}
.item {
flex: 1;
text-align: center;
padding: 0px;
font-size: 30px;
background: #34ace0;
}
This flexbox container sits inside a grid layout, and the cell to the left of the one here has contents which cause the height of the flexbox shown here to be higher than the contents, as shown here:
I need the squares with the numbers inside to stretch/fill the height of its container, like this
...but with the text centered vertically as well.
I tried setting the height of the .item to 100% but it doesn't fill. Is there something like the free-remaining-space used in grid for flexbox?
Make sure the grid layout container has height of 100vh and the container you've shown also has height of 100%.
To center the text inside of each item, you can make each of them display: flex.
.grid-container {
height: 100vh;
}
#container {
height: 100%;
display: flex;
flex-direction: row;
gap: 10px;
}
.item {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex: 1;
padding: 0px;
font-size: 30px;
background: #34ace0;
}
I'd like to horizontally center align a flex child inside a flex container.
However, when the child gets align-self: center it shrinks to width = 0.
Note that both the container and the child have max-width.
How would you solve this?
.container {
display: flex;
flex-direction: column;
max-width: 400px;
outline: 2px solid red;
}
.child {
display: flex;
flex-direction: column;
max-width: 200px;
height: 50px;
background-color: #ccc;
/* This causing the child to shrink to width = 0 */
/* align-self: center; */
}
<div class="container">
<div class="child">
</div>
</div>
The issue is the stretch effect that you disable by changing the alignment of the element. By default align-items is set to stretch thus the element will try to fill its parent width (or height for a row direction).
You can put back this feature using width:100%
.container {
display: flex;
flex-direction: column;
max-width: 400px;
outline: 2px solid red;
}
.child {
display: flex;
flex-direction: column;
max-width: 200px;
height: 50px;
width:100%;
background-color: #ccc;
align-self: center;
}
<div class="container">
<div class="child">
</div>
</div>
align-items sets the default alignment for all of the flex container’s items, including anonymous flex items. align-self allows this default alignment to be overridden for individual flex items.ref
I have a complex layout where I center various elements vertically and horizontally with flexbox.
The last element then has margin-right:auto; applied to push the elements left (and negate centering them).
This works correctly everywhere except on IE10/11 and has been driving me crazy.
HTML/CSS sample:
#container {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-ms-flex-flow: row wrap;
-webkit-flex-flow: row wrap;
flex-flow: row wrap;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
-ms-flex-line-pack: center;
-webkit-align-content: center;
align-content: center;
}
#second-item {
margin-right: auto;
}
/* just some colors - not important */
#container {
height: 200px;
width: 100%;
background: red;
}
#container > div {
background: blue;
padding: 10px;
outline: 1px solid yellow;
}
<div id='container'>
<div id='first-item'>first item</div>
<div id='second-item'>second item</div>
</div>
http://codepen.io/anon/pen/NrWVbR
You'll see two items on the screen that should be left-aligned on the side of the red parent (i.e. they should both be centered, but the last item has margin-right:auto; applied and is filling the entire line, pushing the other item and itself on the side) - this is the correct behaviour. Except in IE10/11 where both items are incorrectly centered i.e. the second item's margin-right:auto; is ignored.
Any IE/flexbox experts out there that have encountered something like this before?
This appears to be an IE bug.
According to the flexbox specification:
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.
Note: If free space is distributed to auto margins, the alignment properties will have no effect in that dimension because the margins will have stolen all the free space left over after flexing.
In other words, auto margins take precedence over justify-content.
In fact, if an element has auto margins applied, then keyword alignment properties such as justify-content and align-self have no effect (because the auto margins have taken all the space).
Your code works as expected in Chrome and Firefox because those browsers are in compliance with the spec.
IE10 and IE11 appear to not be in compliance. They are not applying the auto margin as defined in the spec.
(Note that IE10 is built on a previous version of the spec.)
Solutions
Method #1: Use auto margins only
If justify-content is removed, auto margins work fine in IE10/11.
So don't use justify-content. Use auto margins all the way through. (See examples of alignment with auto margins).
Method #2: Use an invisible spacer div
Create a third div with visibility: hidden and flex-grow:1. This will naturally shift #first-item and #second-item to the left edge, with no need for auto margins.
#container {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
align-content: center;
}
#third-item {
flex-grow: 1;
visibility: hidden;
}
/* just some colors - not important */
#container {
height: 200px;
width: 100%;
background: pink;
}
#container > div {
background: cornflowerblue;
padding: 10px;
outline: 1px solid yellow;
}
<div id='container'>
<div id='first-item'>first item</div>
<div id='second-item'>second item</div>
<div id='third-item'>third item</div>
</div>
I have a complex layout where I center various elements vertically and horizontally with flexbox.
The last element then has margin-right:auto; applied to push the elements left (and negate centering them).
This works correctly everywhere except on IE10/11 and has been driving me crazy.
HTML/CSS sample:
#container {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-ms-flex-flow: row wrap;
-webkit-flex-flow: row wrap;
flex-flow: row wrap;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
-ms-flex-line-pack: center;
-webkit-align-content: center;
align-content: center;
}
#second-item {
margin-right: auto;
}
/* just some colors - not important */
#container {
height: 200px;
width: 100%;
background: red;
}
#container > div {
background: blue;
padding: 10px;
outline: 1px solid yellow;
}
<div id='container'>
<div id='first-item'>first item</div>
<div id='second-item'>second item</div>
</div>
http://codepen.io/anon/pen/NrWVbR
You'll see two items on the screen that should be left-aligned on the side of the red parent (i.e. they should both be centered, but the last item has margin-right:auto; applied and is filling the entire line, pushing the other item and itself on the side) - this is the correct behaviour. Except in IE10/11 where both items are incorrectly centered i.e. the second item's margin-right:auto; is ignored.
Any IE/flexbox experts out there that have encountered something like this before?
This appears to be an IE bug.
According to the flexbox specification:
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.
Note: If free space is distributed to auto margins, the alignment properties will have no effect in that dimension because the margins will have stolen all the free space left over after flexing.
In other words, auto margins take precedence over justify-content.
In fact, if an element has auto margins applied, then keyword alignment properties such as justify-content and align-self have no effect (because the auto margins have taken all the space).
Your code works as expected in Chrome and Firefox because those browsers are in compliance with the spec.
IE10 and IE11 appear to not be in compliance. They are not applying the auto margin as defined in the spec.
(Note that IE10 is built on a previous version of the spec.)
Solutions
Method #1: Use auto margins only
If justify-content is removed, auto margins work fine in IE10/11.
So don't use justify-content. Use auto margins all the way through. (See examples of alignment with auto margins).
Method #2: Use an invisible spacer div
Create a third div with visibility: hidden and flex-grow:1. This will naturally shift #first-item and #second-item to the left edge, with no need for auto margins.
#container {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
align-content: center;
}
#third-item {
flex-grow: 1;
visibility: hidden;
}
/* just some colors - not important */
#container {
height: 200px;
width: 100%;
background: pink;
}
#container > div {
background: cornflowerblue;
padding: 10px;
outline: 1px solid yellow;
}
<div id='container'>
<div id='first-item'>first item</div>
<div id='second-item'>second item</div>
<div id='third-item'>third item</div>
</div>
I have a flex container with two flex items. I want to set a margin-top on the second one, but only when it's wrapped and not at the first flex line.
If possible, I want to avoid using media queries.
I thought margin-bottom on the first element could be a solution. However, it adds space at the bottom when the elements are not wrapped, so same problem.
This is my code:
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.item-big {
background: blue;
width: 300px;
}
.item-small {
background: red;
margin-top: 30px;
}
<div class="container">
<div class="item-big">
FIRST BIG ELEM
</div>
<div class="item-small">
SECOND SMALL ELEM
</div>
</div>
You can add some margin-top to both flex items, and a negative margin-top of the same amount to the flex container.
This way, the negative margin of the flex container will neutralize the margin of the flex items at the first line, but not the margin of the items that wrapped to other lines.
.container {
margin-top: -30px;
}
.item-big, .item-small {
margin-top: 30px;
}
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
margin-top: -30px;
}
.item-big, .item-small {
margin-top: 30px;
background: red;
}
.item-big {
background: blue;
width: 300px;
}
<div class="container">
<div class="item-big">
FIRST BIG ELEM
</div>
<div class="item-small">
SECOND SMALL ELEM
</div>
</div>
Nowadays there is overall support (MDN) for the css (row-)gap property in flex layout containers which this answer proposes. The way to go 🙌🏼.
If your browser supports the CSS gap property you can use it like this
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
gap: 20px;
}
gap adds an extra space surrounding the flex-child items. If you want to add some extra space only at the top and bottom, use row-gap instead.
For browsers that not supports the gap property you can use the lobotomized owl selector which selects every element which has an adjacent item right before it, this means it won't select the first one.
.container > * + * {
margin-top: 20px;
}
If you want to add this marign using * + * operator only if the elements are stacked on top of each other, you should wrap it in #media.
The third solution with :not() and :first-child CSS pseudo-class
.container:not(:first-child) {
margin-top: 20px;
}