How to get flexbox to fill remaining height properly in Angular - html

There are so many questions people have asked and answered about getting a flexbox div to fill the remaining height, but they are all slightly disappointing.
I want to get a div to fill the screen height responsively, and to make the background green. I don't want to have to tell the css the height of anything, I just want it to fill up the available space.
Every solution I've seen reverts to specifying a height at some stage, and I don't want to do that because it means either scroll-bars or white spaces some of the time.
Just colouring the body background seems even more complicated in Angular and I don't want to mess with my theme if I can help it, but this would also be a way to achieve what I want. It just feels like there should be a way to just tell a div to fill the rest of the browser window and it's really bugging me.
HTML:
<div flex layout="column" class="outer">
<div class="top">
<span class="left-spacer"></span>
<span class="page-header">
HOME
</span>
</div>
<div class="middle">
<div class="middle-constrained">
<img src="{{image}}">
</div>
</div>
<div class="bottom">
3
</div>
</div>
CSS:
#import url('https://fonts.googleapis.com/css?family=Bungee|Bungee+Shade');
.outer {
display: flex;
flex-direction: column;
background-color: #009999;
min-height: 100%;
}
.top {
flex: 1;
order: 1;
display: flex;
flex-basis: 33%;
}
.middle {
flex: 8;
order: 2;
display: flex;
flex-basis: 33%;
}
.bottom {
order: 3;
flex: 1;
flex-basis: 33%;
background-color: #009999;
}
.left-spacer {
flex: 7;
background-color: #009999;
}
.page-header {
padding: 0px;
background-color: #009999;
flex: 1;
height: 50px;
font-family: 'Bungee', cursive;
font-size: 2em;
vertical-align: middle;
color: #E1E3F3;
}
.middle {
display: flex;
overflow: auto;
}
.middle-constrained {
flex: 1;
}
img {
width:100%;
height: 100%;
}
I also have an Angular Material Toolbar component at the top of my webpage.

Related

Empty space when I set height of a child element

I want to create a simple page with flex looks like this:
So this is what I try:
.container {
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.header {
height: 40px;
background-color: red;
width: 100%;
}
.sidenav {
background-color: blue;
align-items: flex-start;
}
.main {
background-color: green;
flex-grow: 1;
}
<div class="container">
<header class="header">Header</header>
<nav class="inner sidenav">Sidenav</nav>
<div class="inner main">Main</div>
</div>
My question is, when I set the height of the .header, there's a blank space between .header and the others. Anybody knows why? How can I fix it?
I know I can add more div to make it works, but I want a solution without adding any extra wrapper.
It seems that your content wrapped into two flex rows, and when height is distributed among those rows there are some extra space remained. All of that extra space is not given to last row automatically. So a gap remains unless you shrink the height of window to your contents' exact height.
If you want your second row to take remaining space using css, maybe you can assign remaining height to it with CSS like this:
.container {
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.header {
height: 40px;
background-color: red;
width: 100%;
}
.sidenav {
background-color: blue;
align-items: flex-start;
height: calc(100vh - 40px);
}
.main {
background-color: green;
flex-grow: 1;
}
body
{
margin: 0
}
<div class="container">
<header class="header">Header</header>
<nav class="inner sidenav">Sidenav</nav>
<div class="inner main">Main</div>
</div>

How to make an image fill a flex item with flex-grow?

I've read through all existing solutions in which images could fill the containing divs but I haven't found a solution for filling a div without a static dimension, such as divs that only have been laid out by flex-grow.
Currently the image will destroy the flex-grow proportions I have set on the container. I want the img to just fill the div and not stretch the div out.
As much as possible I don't want to inline style.
Is there an existing polyfill or solution to this?
.container {
display: flex;
min-height: 300px;
width: 500px;
flex: 1;
}
.sub-container {
flex: 1;
display: flex;
flex-direction: row;
}
.sub-container > div {
flex-grow: 1;
}
.first-container {
background-color: blue;
}
.second-container {
background-color: yellow;
}
.second-container>img {
max-height: 100%;
max-width: 100%;
object-fit: scale-down;
}
<div class="container">
<div class="sub-container">
<div class="first-container">
A
</div>
<div class="second-container">
<img src="https://internationalbarcodes.net/wp-content/uploads/2017/04/QR%20code%20example.jpg" />
</div>
</div>
</div>
http://jsfiddle.net/jojonarte/tu3nbw4q/
You have this in your code:
.sub-container > div {
flex-grow: 1;
}
Okay, that defines flex-grow.
But you haven't defined flex-basis. As a result, flex-basis keeps its default value, which is: auto (i.e., content-defined).
That's what you're seeing your layout: A flex item that is being sized by the content.
In other words, because the natural dimensions of the image are so large (in comparison to the size of the container), the image is taking up all free space and flex-grow is having no effect (it has no free space to distribute).
As a solution, add this to the rule:
.sub-container > div {
flex-grow: 1;
flex-basis: 0; /* new */
}
or, more efficiently:
.sub-container > div {
flex: 1; /* fg:1, fs:1, fb:0 */
}
revised fiddle
.container {
display: flex;
min-height: 300px;
width: 500px;
}
.sub-container {
flex: 1;
display: flex;
flex-direction: row;
}
/* ADJUSTMENT HERE */
.sub-container > div {
flex: 1;
}
.first-container {
background-color: blue;
}
.second-container {
background-color: yellow;
}
.second-container>img {
max-height: 100%;
max-width: 100%;
object-fit: scale-down;
}
<div class="container">
<div class="sub-container">
<div class="first-container">A</div>
<div class="second-container">
<img src="https://internationalbarcodes.net/wp-content/uploads/2017/04/QR%20code%20example.jpg" />
</div>
</div>
</div>
More information:
To avoid the problem described in the question, as a general rule, use the flex property instead of flex-grow, flex-shrink and flex-basis individually.
From the flexbox specification:
§ 7.2.1. Components of
Flexibility
Authors are encouraged to control flexibility using the flex
shorthand rather than with its longhand properties directly, as the
shorthand correctly resets any unspecified components to accommodate
common uses.
Learn more about the difference between flex-basis: auto and flex-basis: 0
Use background-image instead use img tag and use background-size: 100% 100%;:
See fiddle
.container {
display: flex;
min-height: 300px;
width: 500px;
flex: 1;
}
.sub-container {
flex: 1;
display: flex;
flex-direction: row;
}
.sub-container>div {
flex-grow: 1;
}
.first-container {
background-color: blue;
}
.second-container {
background: url(https://internationalbarcodes.net/wp-content/uploads/2017/04/QR%20code%20example.jpg);
background-repeat: no-repeat;
background-size: 100% 100%;
}
<div class="container">
<div class="sub-container">
<div class="first-container">
A
</div>
<div class="second-container">
</div>
</div>
</div>

Panel with two sections

I'm trying to create a panel with two sections, as shown above: a light green section on the left and the dark green wrapped around the light green box.
How can I achieve this? I tried putting a span with inline-block inside a div and tried height and width properties but it doesn't produce the desired effect.
Flexbox can help with this.
Create a container with display: flex property
Create two divs within this container and add a flex-basis property to each that equals panel width of 100% or desired number of pixel length
E.g. .panel { width = 500px; }, .div1 { flex-basis: 100px; }, .div2 { flex-basis: 400px; }
E.g. .panel { width = 100% }, .div { flex-basis: 25%; }, .div2 { flex-basis: 75%; }
Style divs (sections) accordingly - height, background-color, border, etc.
Within the second div (right section) add your icons and style as well
I used FontAwesome CDN for the icons.
Hope this helped, you can also see this Codepen I created.
HTML
<div class="container">
<div class="div1"></div>
<div class="div2">
<i class="fas fa-plus-square"></i>
<i class="fas fa-sync-alt"></i>
</div>
</div>
CSS
.container {
display: flex;
}
.container div{
height: 25px;
width: 100%;
}
.div1{
background-color:#abffb9;
flex-basis: 2%;
border: 1px solid #5cb85b;
}
.div2{
background-color:#5cb85b;
flex-basis: 98%;
text-align: right;
border: 1px solid #5cb85b;
}
.fas {
color: #fff;
}
Is this what you are after?
Flexbox is realy good for just this, you can read more about flexbox here.
.wrapper {
display: flex;
padding: 2px;
background-color: green;
}
.green-box {
flex: 0;
min-width: 20px;
background-color: Chartreuse;
}
.filler {
flex: 1;
text-align: right;
}
<div class="wrapper">
<div class="green-box">
</div>
<div class="filler">
Icon
</div>
</div>

get the height of the previous element

Can i get the height of the previous element using only CSS?
I am using calc() function to set dynamically height of the div B.
#b{
height:calc(100vh - heightOfPreviousElement);
}
I need to know the height of the previous element.
what i know is that, 100vh is equal to 100% of the screen height.
I used the code in the answer below.Using flex,
I have one problem. The height of the color orange become smaller.
You can easily achieve the effect you're looking for using flexbox. The trick is to allow the blue container (the one with the flexible height) to grow in size whenever the need arises, using flex: 1 1 auto, which is simply a shorthand for:
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
See proof-of-concept code snippet below:
body {
padding: 0;
margin: 0;
}
.wrapper {
display: flex;
flex-direction: column;
flex-wrap: no-wrap;
align-items: center;
justify-content: center;
height: 100vh;
}
.wrapper > div {
width: 100%;
}
#c1 {
background-color: #880015;
color: #fff;
height: 60px;
margin-bottom: 10px;
}
#c2 {
background-color: #ff7f27;
}
#c3 {
background-color: #00a2e8;
flex: 1 1 auto;
margin-bottom: 10px;
}
<div class="wrapper">
<div id="c1">height: 60px</div>
<div id="c2">height: auto (determined by content?)</div>
<div id="c3">flexible height</div>
</div>
No you can't select a previous element in CSS.
You might be interested in JQuery Prev OR Parents method for selecting previous element and apply height using .css() method?

Height is not correct in flexbox items in Chrome [duplicate]

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 6 years ago.
I've got a delicate problem for any CSS guru out there.
My green div has a flexible height, taking up the remaining.
And now I want to put a div inside that div which should be the half of the green div. But it seems like if Chrome treats it like half of the whole page rather than the flex item.
http://jsfiddle.net/unh5rw9t/1/
HTML
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>
CSS
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
}
#half_of_content {
height: 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
#Michael_B explained why Chrome behaves like this:
You gave the body a height: 100%. Then gave its child (.wrapper)
a height: 100%. Then gave its child (.content) a height: 100%.
So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be a 50% height
of body.
However, Firefox disagrees because, in fact, that height: 100% of .content is ignored and its height is calculated according to flex: 1.
That is, Chrome resolves the percentage with respect to the value of parent's height property. Firefox does it with respect to the resolved flexible height of the parent.
The right behavior is the Firefox's one. According to Definite and Indefinite Sizes,
If a percentage is going to be resolved against a flex item’s
main size, and the flex item has a definite flex
basis, and the flex container has a definite main
size, the flex item’s main size must be treated as
definite for the purpose of resolving the percentage, and the
percentage must resolve against the flexed main size of the
flex item (that is, after the layout algorithm below has been
completed for the flex item’s flex container, and the flex
item has acquired its final size).
Here is a workaround for Chrome:
#content {
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
height: auto;
}
This way the available space in #content will be distributed equally among #half_of_content and the ::after pseudo-element.
Assuming #content doesn't have other content, #half_of_content will be 50%. In your example you have a 2 in there, so it will be a bit less that 50%.
html,
body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
You could absolutely position div id="half_of_content".
#content {
flex: 1;
height: 100%;
background-color: green;
position: relative; /* new */
}
#half_of_content {
height: 50%;
background-color: yellow;
position: absolute; /* new */
width: 100%; /* new */
}
DEMO
With regard to your statement:
But it seems like if Chrome treats it like half of the whole page
rather than the flex item.
You gave the body a height: 100%. Then gave its child (.wrapper) a height: 100%. Then gave its child (.content) a height: 100%. So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be 50% height of body.
With absolute positioning, however, you don't need to specify parent heights.
Nesting flexboxes is a little buggy. I reworked your markup a little by adding an inner wrapper with display: flex; which seems to do the job. Here is the fiddle (also using class names instead of ids).
<div class="content">
<div class="wrapper-inner">
2
<div class="half">
2.1
</div>
</div>
</div>
.wrapper-inner {
position: absolute;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
Fix:
on #content set
display: flex;
flex-flow: column nowrap;
justify-content: flex-end
on #half_of_content set flex: 0 0 50%;
Caveat: you need to add an extra div as a child of #content.
Here's the full example:
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
display:flex;
flex-flow: column nowrap;
justify-content: flex-end;
background-color: green;
}
#half_of_content {
flex: 0 0 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>