What is the difference between the flex and height properties? - html

Given the following example, both will fill out the center to consume the remaining space in the page, given the page is using flex. I am leaning towards using the css property flex vs height in the body. Is there a difference that needs to be considered when applying one over the other?
CSS
.page {
display: flex;
flex-direction: column;
}
.header {
height: 100px;
}
.body {
flex: 1; // vs height: 100%;
}
.footer {
height: 40px;
}
HTML
<div class="page">
<div class="header">Sample Header</div>
<div class="body">Sample Body</div>
<div class="footer">Sample Footer</div>
</div>

When you set an element to flex: 1, that breaks down to:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
In a column-direction container (like you have), the flex properties above apply vertically. This means that flex-basis and height are equivalent properties.
flex-basis = height (in a column-direction container)
There is an obvious difference between flex-basis: 0 and height: 100%. It's the same difference as height: 0 and height: 100%.
In your situation, where there is a .header and a .footer consuming 140px of vertical space, setting the middle item (.body) to height: 100% would normally cause an overflow.
But since an initial value of a flex container is flex-shrink: 1, flex items are permitted to shrink, and this wouldn't happen. However, it's still sloppy and imprecise coding, in my view.
By setting .body to flex: 1, you're setting the height to 0, but also allowing it to consume free height with flex-grow: 1. I would say, in this case, that this solution is more efficient.
More details:
What are the differences between flex-basis and width?
§ 7.1.1. Basic Values of flex

There is a huge difference between flex and height.
First to answer your question.
Height 100% doesn't use the remaining space. It will use all the spaces of parent, in your case if page dom is height 200px; then body will also be height: 200px;.
Flex will be correct solution here to fill up the space (flex: 1).
Flex is more than filling the space, its more of a layout and it has influences on its child, how they position and align.

Try below code
.page {
display: flex;
flex-direction: column;
height: 100%;
}
.header {
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.body {
display: flex;
flex-direction: column;
height: 80vh;
align-items: center;
justify-content: center;
}
.footer {
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
<div class="page">
<div class="header">Sample Header</div>
<div class="body">Sample Body</div>
<div class="footer">Sample Footer</div>
</div>

Related

how to handle images when flex direction is set to column

I am working with flex layouts and images. My goal is to stack the flex-items on top of each other on smaller screen widths, by setting flex-direction: column; but there is a strange behavior i can't understand. The flex item that wraps the image seems to take the full width of the image. I have created a CodePen that illustrates the problem. Thank you in advance
Let the width of the flex item be dictated by the flex container, then size the image to the size of the flex item.
When you set up a flex-direction: column flex container, the height of your flex items is controlled by the flex properties (grow, shrink, basis).
The width of a flex item in a flex-direction: column flex container can either be dictated by the flex container, or it can be left to the flex item to “decide” how big it wants to be.
In this case align-items: start controls the width of your flex items. start means that the items can size themselves however they want, and they will be positioned at the start side of your flex container.
The flex item that wraps your image doesn’t have its own size (it has the default width: auto), so your image’s width: 100% can’t be resolved. In that case the image behaves as though it had width: auto, and basically renders at its full size. Then, the flex item takes on that size, and that’s why it’s so big in your flex container.
You can force all your flex items to be the width of your column flex container by not setting align-items and letting it use the default normal value, with stretches the flex items to the width of the flex container. Then your flex items have a specific size, and your image’s width: 100% can be resolved against that size.
Here’s a working example:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
background-color: #ccc;
padding: 10px;
display: flex;
flex-direction: column;
}
.item {
background-color: #ff1b68;
padding: 40px;
margin: 3px;
color: #fff;
font-size: 40px;
}
.item--2 {
height: 200px;
}
.item--3 {
}
.item--3 img {
width: 100%;
height: 100%;
object-fit: cover;
}
<div class="container">
<div class="item item--1">1</div>
<div class="item item--2">2</div>
<div class="item item--3">
<img
src="https://images7.alphacoders.com/462/thumb-1920-462576.jpg"
alt=""
/>
</div>
</div>
By default, each flex item has align-self: auto, which means it will look at the flex container’s align-items value. So you set align-items once, and all flex items use that. But you can specify different align-self for each item, if you want to, for example, keep your text flex items align-self: start, and your image flex item align-self: stretch.
You can use a calculated width on your image element setting it to view width units => width: calc(100vw - padding - margin). So your image element will be 100% of the view width minus the padding and margin of the it and its parent element. Also set your container to min-width: 1000px;.
If the following is not what you are looking for, please let me know.
Resize the browser to test dynamic resizing of image to fit within viewable screen
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
background-color: #ccc;
padding: 10px;
min-height: 1000px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
.item {
background-color: #ff1b68;
padding: 40px;
margin: 3px;
color: #fff;
font-size: 40px;
/*flex-grow: 1;*/
}
.item--2 {
height: 200px;
}
.item--3 {
order: 1;
}
.item--3 img {
width: calc(100vw - 130px);
object-fit: cover;
}
<div class="container">
<div class="item item--1">1</div>
<div class="item item--2">2</div>
<div class="item item--3">
<img src="https://images7.alphacoders.com/462/thumb-1920-462576.jpg" alt="">
</div>
</div>

Horizontal Margins going outside of parent div in flexbox

I'm getting some unexpected behavior with my margins using flex and I would like some help in understanding why.
I'v got some simple html like so:
<div className="dashboard">
<div className="dashboard__inner-container">Inner Container</div>
</div>
And my scss file looks like this:
.dashboard {
text-align: center;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
flex: 1 1 auto;
background-color: #f4f6f8;
}
.dashboard__inner-container {
display: flex;
flex-direction: column;
background-color: #ffffff;
flex: 1 1 auto;
width: 100%;
margin: 100px 50px;
}
What I am expecting is that the inner container will completely fill up the parent container, minus 100px on the top and bottom and 50px on the right and left. The vertical margin works as expected, but the horizontal margin actually extends out of the parent div, so that the inner container still appears to be taking up the entire width of the parent div.
I'm not sure if this is related to flexbox or not.
Here is an isolated CodePen https://codepen.io/MaxMillington2/pen/EQWZoj
When using align-items: center with column direction, the item will collapse to its content width, instead of with its default, stretch, which makes it fill its parent's width.
Additionally, when setting width: 100% to the inner, it will override the default stretch, which will make the item be 100% of parent's width + margin.
For the expected output, remove align-items: center on the outer and width: 100% on inner.
Stack snippet
html {
height: 100%;
overflow: auto;
}
.outer {
display: flex;
justify-content: center;
flex-direction: column;
background-color: #f4f6f8;
height: 100%;
}
.inner {
display: flex;
flex-direction: column;
background-color: #ffffff;
flex: 1 1 auto;
text-align: center;
margin: 100px 80px;
}
<div class='outer'>
outer
<div class='inner'>
inner
</div>
</div>

Setting percentage heights to flex items when container has dynamic height

I have a simple wrapper with 2 div elements in it.
I want the first one to gain 85% of the height and the second one to gain only 15% of the height.
It works when I set a fixed height to the wrapper. Though sadly my wrapper has a dynamic height.
Do you know how I can accomplish this?
I have also provided a plunker: http://plnkr.co/edit/HQpahfmRasij8Zougjkn?p=preview
Code:
.outer{
flex: 1;
display: flex;
flex-direction: column;
flex-basis: 0;
/* if i set the fixed height everthing works
though i do want a dynamic height
height: 800px; */
}
.main {
background-color: blue;
display: flex;
flex: 0 0 85%;
max-height: 85%;
flex-direction: row;
height: 400px;
}
.navigator {
background-color: red;
display: flex;
flex: 0 0 15%;
max-height: 15%;
flex-direction: row;
height: 400px;
}
<div class="outer">
<div class="main" >
<!-- this container should have 85% of the outer containers height -->
</div>
<div class="navigator" >
<!-- this container should have 15% of the outer containers height -->
</div>
</div>
You can do the initial (outer) layout without flex, as I can't see the point when it's not needed.
The requirement is the same though, that the .outer's parent need a height, either inherited or set.
html, body {
height: 100%;
margin: 0;
}
.outer {
height: 100%;
}
.main {
background-color: blue;
height: 85%;
display: flex; /* this is for main's children */
flex-direction: row; /* this is for main's children */
}
.navigator {
background-color: red;
height: 15%;
display: flex; /* this is for nav's children */
flex-direction: row; /* this is for nav's children */
}
<div class="outer">
<div class="main" >
<!-- this container should have 85% of the outer containers height -->
</div>
<div class="navigator" >
<!-- this container should have 15% of the outer containers height -->
</div>
</div>
You can try sizing the flex items with flex-grow instead of flex-basis or height.
In the following example, one flex item will occupy 85% of the available space in the container. The other flex item will take the remaining 15%.
HTML (no changes)
CSS
.outer {
display: flex;
flex-direction: column;
}
.main { flex-grow: 85; }
.navigator { flex-grow: 15; } /* flex-grow: 1 would work as well */
Revised Plunkr
Learn more about flex heights here: Heights rendering differently in Chrome and Firefox
if they are direct childs of body, then you first need to set height on patrents : html & body in order to have an inheritable value.
then outer is no longer needed, body is there already.
Set height to the smallest (and eventually a min-height) and request the other to grow via just : flex:1;.
html,
body {
height: 100%;
margin: 0;
}
body {
display: flex;
flex-direction: column;
}
.main {
flex: 1;
background: tomato;
}
.navigator {
height: 15%;
min-height: 2em;
background: lime;
}
<div class="main">
<!-- this container should have 85% of the outer containers height -->
main
</div>
<div class="navigator">
navigator
<!-- this container should have 15% of the outer containers height -->
</div>
http://plnkr.co/edit/R502OvyV2RR8GZ96UJvt?p=preview
comment pulled up here :
#JuHwon then, does the parent has a known size that it can be
inherited.
could you set up an example that shows your trouble.
% values need a reference to calculate a ratio from it, within flex imbrication height should be usable or something like
flex:85; & flex:15; http://codepen.io/gc-nomade/pen/pgOjXB

Vertically centering with flexbox

I'm trying to center a div on a webpage using flexbox. I'm setting the following CSS properties. I see that it's being centered horizontally, but not vertically.
.flex-container {
display: flex;
align-items: center;
justify-content: center;
}
Here's the fiddle: JSFIDDLE
Can you explain what I'm doing wrong?
A <div> element without an explicit height defaults to the height of it's contents, as all block elements do. You'd probably want to set it to 100% of it's parent, the <body>, but that's not enough, since that is also a block element. So again, you need to set that to 100% height, to match it's parent, the <html>. And yet again, 100% is still required.
But once all that is done, you get that annoying vertical scroll bar. That's a result of the default margin the body has, and the way the box model is defined. You have several ways you can combat that, but the easiest is to set your margins to 0.
See corrected fiddle.
html, body {
height: 100%;
margin: 0px;
}
.flex-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.item {
background-color: blue;
height: 50px;
width: 50px;
}
<div class="flex-container">
<div class="item">
</div>
</div>
You just need to set html, body, and your flex container to height: 100%. The reason it wasn't working is that your flex container didn't have an explicit height set, so it defaulted to the height of its contents.
Live Demo:
html, body {
height: 100%;
}
.flex-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.item {
background-color: blue;
height: 50px;
width: 50px;
}
<div class="flex-container">
<div class="item">
</div>
</div>
JSFiddle Version: http://jsfiddle.net/d4vkq3s7/3/

Flexbox wrap - different alignment for last row

I'm using flex box to align two items to left and right of the container, while vertically centre-aligning them. Here's a very simple example of what I'm trying to achieve.
HTML:
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
CSS:
.container {
width:100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
}
Here's the jsfiddle of the example.
This works perfectly well if the screen is wide enough to fit both internal divs on one row. However when the screen size is small (e.g. a mobile phone) and the divs wrap onto the second line, the second one also becomes aligned to the left side (i.e. flex-start). How can I force the second div to always be aligned against the right border, regardless of whether it's on the first row or wrapped onto the second one?
EDIT: In the example, I assigned fixed width to the two child elements - this is for simplicity only. In the real life application, all widths are dynamically changing based on the content read from the database at run-time. Hence, any solution that's based on fixed sizes will not work.
You can try adding some left margin to push your .second element to the right:
.second {
margin-left: auto;
}
.container {
width:100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
margin-left: auto;
}
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
Or, similarly, justify all elements to the right but push .first element to the left:
.container {
justify-content: flex-end;
}
.first {
margin-right: auto;
}
.container {
width:100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-end;
align-items: center;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
margin-right: auto;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
}
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
I found a solution but it is rather "hacky" in nature (see demo here, explanation later), in the sense that it requires you to explicitly know the width of the parent container which will trigger a layout change based on #media.
The reason why your code is not working is because of the confusion over how align-self works. In the flexbox model, "align" refers to alignment along the cross-axis (i.e. in a conventional sense of a "row" layout direction, that will refer to vertical alignment), while "justify" refers to alignment along the main axis (i.e. the row). To better explain my point, I hereby attach an image made by Chris Coyier from his flexbox guide:
Therefore, align-self: flex-start means telling the .first to align to the top of the container, and align-self: flex-end means telling .second to align to the bottom of the container. In this case, since you have not declared an explicit height for the parent, the parent will take on the height of its tallest child. Since both .first and .second are 100px tall, the parent will also have a computed height of 100px, therefore making no difference in the alignment (because both with be flush with the start and end of the cross axis).
A hack would be switching the flex-direction to row, with the following restrictions: You know how wide your container will be, or the explicit widths of its children. In this case the breakpoint will be at 400px, where .first and .second will intersect each other.
.container {
width:100%;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-between;
height: 100px;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
align-self: flex-start;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
align-self: flex-end;
}
#media screen and (max-width: 400px) {
.container {
height: 200px;
}
}
Then again, here is a proof-of-concept fiddle, modified from your original one: http://jsfiddle.net/teddyrised/cncozfem/2/