I am using css flex layout to build a dashboard and would like to put two widgets (one on top of the other) inside of a flex item and make them 50% height of their parent at all times (regardless of content). So if my html is:
<div class="flex-container">
<div class="flex-item">
<div class="widget" id="w1">
widget 1 content
</div>
<div class="widget" id="w2">
widget 2 content
</div>
</div>
</div>
and my css looks like:
.flex-container {
display: flex;
flex-direction: column;
}
.flex-item {
flex: 1;
}
How can I get the two .widgets to always occupy 50% height of .flex-item?
I've tried:
.flex-item {
flex: 1;
display: flex;
}
.widget {
flex: 1;
}
But this only works when the content in both widgets are the same.
I've worked up a more elaborate jsfiddle to better illustrate my issue.
Thanks in advance!
When you say that flex: 1 only works when the content in both widgets are the same, that is not correct. That would defeat the purpose of flex: 1.
flex: 1 tells flex items to distribute container space evenly among themselves. If there are four flex items with flex: 1, each will take 25%. Three would take 33.33%. And two flex items will take 50%. This is regardless of content quantity.
See this illustration: DEMO
The problem you're having is not clear in the code you posted in the question. However, it's apparent in your fiddle demo.
You have a main container with a height: 400px. You also have a rule adding 10px padding all-around to your divs. This adds 20px height to each div. You also have a header with height: 2em.
When you account for the extra heights the layout works.
Try these adjustments:
HTML (no changes)
CSS
div {
box-shadow: inset 0 0 0 1px rgba(30, 100, 200, 0.5);
padding: 10px; /* sneaky villain */
font-family: arial;
}
h1, p { margin: 0; }
#main-wrapper {
height: 400px; /* primary height */
display: flex;
flex-direction: column;
}
#header {
flex-shrink: 0;
height: 2em; /* header height */
}
#main-column-wrapper {
flex: 1;
display: flex;
flex-direction: row;
height: calc(100% - 2em - 20px); /* primary height - header height - padding */
}
#side-column {
width: 20%;
flex-shrink: 0;
}
#main-column {
flex: 1;
display: flex;
flex-direction: column;
height: calc(100% - 40px); /* main-column-wrapper height - padding (2 divs) */
}
#widget1,
#widget2 {
flex: 1;
flex-shrink: 0;
overflow: auto;
}
Revised Fiddle
Another option would be to use box-sizing: border-box to adjust for the padding. Learn more here: https://css-tricks.com/box-sizing/
Related
I have 3 buttons in a row which all vary in width. I want them to all gain width the same to fill the remaining width of the row, so the widest will still be wider than the others etc.
You can see below that what I've tried to do with flex has resulted in all the buttons being the same width. I know flex-grow can be used to proportionally grow each item, but I can't work out how to get them all to grow in relation to their original size.
You can see in the second row that the blue item is larger than the other two. I just want all three to expand from their current size equally to fill the row.
Thanks
.row-flex {
width: 100%;
display: flex;
flex-direction: row;
}
.button {
flex: 1;
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>
Short Answer
Switch from flex: 1 to flex: auto.
Explanation
The flex-grow property factors in two key pieces of data:
The free space in the row / column where it is being used.
The value of the flex-basis property.
Distribution of Free Space
The flex-grow property distributes free space in the container among flex items in the same line.
If there is no free space, flex-grow has no effect.
If there is negative free space (i.e., the total length of flex items is greater than the length of the container), then flex-grow has no effect and flex-shrink comes into play.
The flex-basis factor
When flex-basis is 0, flex-grow ignores the size of the content in flex items and treats all space on the line as free space.
This is absolute sizing. All space on the line is distributed.
When flex-basis is auto, the size of the content in flex items is first deducted to determine the free space in each item. flex-grow then distributes the free space among items (based on each item's flex-grow value).
This is relative sizing. Only extra space on the line is distributed.
Here's an illustration from the spec:
Examples:
flex: 1 (absolute sizing)
This shorthand rule breaks down to: flex-grow: 1 / flex-shrink: 1 / flex-basis: 0
Applied to all flex items, this will make them equal length, regardless of content. (Note that in some cases an override of default minimum sizing will be necessary for this effect to occur.)
flex-grow: 1 (relative sizing)
This rule by itself will factor in both content size and available space, because the default value for flex-basis is auto.
flex: auto (relative sizing)
This shorthand factors in both content size and available space because it breaks down to:
flex-grow: 1
flex-shrink: 1
flex-basis: auto
More variations here: 7.1.1. Basic Values of flex
additional keywords for search: difference between flex-basis auto 0 flex 1 auto
Not sure if this is entirely what you are after, but if you just set flex-grow:1 instead of flex:1;, I think that is your required result:
.row-flex {
width: 100%;
display: inline-flex;
flex-direction: row;
}
.button {
flex-grow: 1;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>
Using flex property you can set proportions:
.button {
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.row {
display: flex;
}
.button--1 {
background: red;
flex: 1 1 auto;
}
.button--2 {
background: green;
flex: 2 1 auto;
}
.button--3 {
background: blue;
flex: 3 1 auto;
}
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>
Minimalistic answer with (hopefully useful, explanatory) alternatives:
HTML:
<div class="row-flex">
Single
Larger title
Another really large title
</div>
CSS:
.row-flex {
display: flex;
}
.button {
flex-grow: 1; /* make the item grow proportionally to its original size */
/* default value is 0, the item does not grow */
/* a meaningful default for flexbox items positioning with */
/* justify-content: <value>; */
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
The following CSS declarations also work because all they do is override the default flex-grow: 0; to the (for the desired behavior required) flex-grow: 1;:
.button {
flex: auto;
...
}
which is a shorthand for:
.button {
flex: 1 1 auto;
...
}
which is a shorthand for:
.button {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
...
}
https://jsfiddle.net/wqmm0kxb/5/
html:
<div class="full">
<header><h1>header stuff</h1></header>
<section>
<div>
{lots and lots of content}
</div>
<div>b</div>
<div>c</div>
</section>
</div>
css:
.full {
position: fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
header {
flex: 78px 0 0;
background: #ececec;
color: black;
padding-left: 33px;
}
section {
flex: auto 1 1;
display: flex;
align-items: stretch;
> div {
flex: auto 1 1;
overflow-y: auto;
}
}
}
My outer container, '.full', takes up the full width and height of the screen, and uses display:flex to make sure that the header + section children stretch to take up all the space beneath them.
Now, what I want is naturally for the header to take up 78px and the section to take up {full height - 78px} -- but without doing anything like calc preferrably. And I want to be able to scroll in the div children of section, without scrolling affecting the other divs or the page as a whole.
This works perfectly in Chrome, but open up my fiddle in firefox, edge, ie and it doesn't work as expected. Section gets the height of {lots and lots of content} rather than only taking the remaining space of '.full'
What should I do to achieve the Chrome-like layout that I'm expecting?
Apply the overflow-y:auto for your section also, that will fix the issue in IE and Firefox.
section {
flex: auto 1 1;
display: flex;
align-items: stretch;
overflow-y: auto;
> div {
flex: auto 1 1;
overflow-y: auto;
}
}
Fiddle DEMO
Using the following CSS:
#menusidebar {
background-color: #6BC9DB;
margin: 0 0 0 0;
height: 100vh;
}
the left hand side sidebar of this page does not reach the bottom of its parent container #content-wrap.
Update: I tried using the flex box model:
.flex {
display: -webkit-flex;
display: flex;
flex-grow: 1;
}
<div id="content-wrap" class="fluid clearfix flex" data-content="content">
<aside role="complementary" class="two columns" id="menusidebar">
but the child of the flex element #menusidebar does not take up all remaining space of the flex parent #content-wrap.
Here is a start for you, using your sample link
Fiddle demo
where I changed these rules
#content-wrap {
background-color: #FFF;
margin: 0;
display: flex;
}
.column, .columns {
display: inline;
flex: 1;
margin-left: 10px;
margin-right: 10px;
}
#menusidebar {background-color: #6BC9DB; margin: 0 0 0 0;}
Stick with the flexbox strategy, as that one is the most forward-thinking. Add the following style to the container:
align-items: stretch;
And take off any heights set on the child elements (specifically #menusidebar).
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?
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