I have a simple plunker here.
.container {
display:flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
min-height: 4em;
}
.nav {
flex: 0 0 4em;
height: 1em;
}
.logo {
flex: 1 0 auto;
align-self: stretch;
}
This is working how I want it to in Chrome 49:
But not in IE11:
I have checked that IE isn't in compatability mode - it's not - it's in IE11 mode.
What's going on here?
This is a bug in IE11.
The min-height property on a flex container isn't recognized by flex items in IE11.
If you switch to height: 4em, you'll see that your layout works.
A simple workaround is to make .container a flex item.
In other words, add this to your code:
body {
display: flex;
}
.container {
width: 100%; /* or flex: 1 */
}
For whatever reason, by making your flex container also a flex item, the min-height rule is respected by the child elements.
More details here: Flexbugs: min-height on a flex container won't apply to its flex items
Related
I'd like to understand how Angular interprets my HTML and CSS code. Layouts that I've been using without Angular seem to break down.
Simple Example: I am trying to create a fixed height header div followed by a body div that fills the remaining space.
It works in vanilla HTML/CSS: https://jsfiddle.net/d4Lmbk2q/1/
HTML:
<div id='mainCont'></div>
<div id='bodyCont'></div>
CSS:
html,
body {
height: 100%;
width: 100%;
margin: 0;
}
body {
display: flex;
flex-flow: column;
align-items: stretch;
}
#mainCont {
background-color: blue;
flex: 0 0 1.8cm;
min-width: 970px;
}
#bodyCont {
background-color: green;
flex: 1 1 auto;
}
In Angular, nothing shows up (presumably because Angular inserts the empty app-root component wrapper element between the flex container and the flex items?): https://codesandbox.io/s/beautiful-pike-u7hbl?file=/src/app/app.component.css
Yes, the display:flex applies to the direct children of body element which in this case are not your divs but app-root tag
I fixed mine by adding a display of flex to the Angular element that's the direct child of the parent that was flexed. In your case it's app-root.
Here is what it will look like:
body {
display: flex;
flex-flow: column;
align-items: stretch;
}
app-root {
display: flex;
}
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>
align-content and justify-content seem to do nothing when I run it on Chrome and Firefox.
I'm not sure what's wrong.
#container {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: center;
height: 90vh;
}
#header {
flex: 1 0 200px;
background-color: lightgreen;
height: 200px;
border-radius: 1rem;
}
#main {
flex: 1 0 200px;
background-color: coral;
height: 200px;
border-radius: 1rem;
}
#footer {
flex: 1 0 200px;
background-color: silver;
height: 200px;
border-radius: 1rem;
}
#media screen and (max-width: 915px) {
#container {
flex-flow: column wrap-reverse;
}
}
<div id="container">
<div id="header">Header</div>
<div id="main">Main</div>
<div id="footer">Footer</div>
</div>
They're doing exactly what you're asking them to do. What's wrong here is your flex definition.
If you want them to be 200px each, you shouldn't give it a flex-grow value of 1 which you're doing in your shorthand flex-grow: *1* 0 200px.
Instead, rewrite the flex properties as such:
#header {
flex: 0 0 200px;
...
}
Working JSFiddle
As for why align-content isn't working, you only have 1 line of items, so it has nothing to do.
align-content
This aligns a flex container's lines within when there is extra space in the cross-axis, similar to how justify-content aligns individual items within the main-axis.
Note: this property has no effect when there is only one line of flex items.
From: CSS-Tricks
I'm guessing what you want is to center vertically and horizontally, in which case you don't want align-content, you want align-items.
Try replacing align-content: center with align-items: center to get the vertical centering.
JSFiddle example of align-items
I want to create a vertical list, where each row shrinks its width to perfectly contain its inner content (versus the default div behavior of expanding its width to fill the container).
I'd like to do this with only one HTML element for each row (no extra wrapping divs).
The following code does exactly what I want, but it doesn't work in Safari (bug?).
.container {
margin: 10px;
border: 2px solid #999;
padding: 5px;
display: flex;
flex-direction: column;
width: 300px
}
.row-item {
padding: 5px;
margin: 5px;
border: 1px solid green;
/* this will shrink the width to the inner content
in Chrome and Firefox, but not in Safari */
margin-right: auto;
}
<div class='container'>
<div class='row-item'>Item #1</div>
<div class='row-item'>Another Item...</div>
<div class='row-item'>Item No. 3</div>
</div>
Here is a codepen with the above code: http://codepen.io/anon/pen/woKYqx
I know that it is trivial to solve this problem by adding a wrapping div and then using display: inline-block on the inner element (or several other similar solutions).
However, it seems like it should be possible to solve this without adding extra HTML elements. It is a fairly simple layout.
Is there a cross-browser way to do this with a single HTML element for each row?
You're using margin-right: auto to push the element all the way to the left, which also forces the item to take the width of its content.
This is a good method but, as you've noted, it fails in Safari.
A simple alternative is to use align-self: flex-start on the flex items:
.row-item {
padding: 5px;
margin: 5px;
border: 1px solid green;
align-self: flex-start; /* NEW */
/* margin-right: auto; (can be kept or removed) */
}
OR, just use align-items: flex-start on the flex container.
.container {
margin: 10px;
border: 2px solid #999;
padding: 5px;
display: flex;
flex-direction: column;
align-items: flex-start; /* NEW */
width: 300px
}
You can erase all flex stuff and use float:left and clear:left on the children, and overflow-x: hidden on the parent:
http://codepen.io/anon/pen/pNjQJJ
When you are using display: flex you should also use the vendor prefixes for it.
too support older versions of browsers
when in doubt check up on caniuse.com
.container {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -webkit-flex; /* NEW - Chrome */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: flex;
/* ETC */
}
NOTE: caniuse.com have written about bugs being reported about flexbox childrens height in safari.
I have a container named #center in which I want to display canvas and a button inside it. I want the canvas object to take all the available space (respecting the button inside the container).
This is my code:
html, body {
width: 100%;
height: 100%;
}
#container {
display: flex;
height: 100%;
background-color: blue;
}
.block {
flex: 1;
}
#left {
background-color: green;
}
#center {
display: flex;
flex: 1;
flex-wrap: wrap;
align-content: flex-start;
}
#right {
background-color: orange;
}
#canvasObject {
display: block;
margin: 0 auto;
border: 1px solid;
background-color: yellow;
}
<div id="container">
<div id="left" class="block">Left</div>
<div id="center" class="block">
<canvas id="canvasObject">Your browser does not support Canvas.</canvas>
<button type="button">Click!</button>
</div>
<div id="right" class="block">Right</div>
</div>
If I do not have any button in my code, canvas occupy the full div but when I display the button, canvas does not seem to resize the desired height.
Example 1: Without button.
Example 2. With button.
How can I make that the canvas object will resize until the available height (also width but it is already doing it)?
Thanks in advance!
The problem is that you have align-content: flex-start on a row-direction flex container:
#center {
display: flex;
flex: 1;
flex-wrap: wrap;
align-content: flex-start; /* <-- source of the problem */
}
The align-content property controls the spacing between flex items in the cross-axis when there are multiple lines in the container.
When the button element is excluded, there is only one line in the flex container. In such a case, align-content has no effect (align-items would work).
But when you add the button, there are now two lines on wrap, and align-content takes over (align-items does not work).
Since align-content is set to flex-start in your code, both lines are packed to the top of the container. (For other options, try flex-end, center, space-between, space-around and stretch).
An efficient solution would be to use flex-direction: column and apply flex: 1 to the canvas.
#center {
display: flex;
flex-direction: column; /* new; stack flex items vertically */
flex: 1;
flex-wrap: wrap;
/* align-content: flex-start; <-- remove; not necessary */
}
#canvasObject {
flex: 1; /* new; consume all available free space */
/* display: block; <-- remove; not necessary */
/* margin: 0 auto; <-- remove; not necessary */
border: 1px solid;
background-color: yellow;
}
Revised Fiddle
W3C References:
8.4. Packing Flex Lines: the align-content property
8.3. Cross-axis Alignment: the align-items and align-self properties