I'm attempting to learn flexbox and I'm trying to achieve the following layout.
+----------+----------+
| |nav |
| header +----------+
| |section |
+----------+----------+
HTML Structure
<header></header>
<nav></nav>
<section></section>
Layout Requirements
Width of each element is exactly 50vw (or 50%)
Header content is always centered and fixed. Takes up 100vh.
Nav content is fixed
Section content is scrollable, overflow is hidden.
Is this even possible with flexbox?
On mobile devices, I want to have all three in a column but that part is easy.
body {
display: flex;
flex-flow: column wrap;
height: 100vh; /* key rule; this tells flex items where to wrap
to form second column */
}
header {
flex: 0 0 100%;
width: 50%;
/* center content */
display: flex;
justify-content: center;
align-items: center;
}
nav, section {
flex: 0 0 50%;
width: 50%;
}
/* non-essential decorative styles */
* { box-sizing: border-box; margin: 0; }
header { background-color: aqua; }
nav { background-color: tomato; }
section { background-color: lightgreen; }
<header>header</header>
<nav>nav</nav>
<section>section</section>
For a detailed explanation and alternative methods see my answer here:
Is it possible for flex items to align tightly to the items above them?
if you want to use flexbox you can get away with doing a dual container layout.
HTML
<div class="flex-container">
<header>Something</header>
<div class="flex-child-container">
<nav>nav</nav>
<section>section</section>
</div>
</div>
CSS
div {
display: flex;
width: 100%;
height: 100%
}
.flex-child-container {
flex-direction: column;
}
Related
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>
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
I have a layout that gets customized by many different clients so the html structure is locked down to
<div class="container">
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
</div>
NOTE: not using bootstrap, container is just the applicable name
In the UI I need to be able to use CSS to make many different layouts from this structure without altering it. There is one in particular I can't figure out. The desired layout is this:
I know that if it were all vertical it would be easily doo-able with simple width and float styles. I also know that throwing a containing div around the first two children would be an easy solution but again requirements are to leave the html unchanged.
I've tried:
.container {
display: flex;
flex-wrap: wrap;
}
.container > div {
width: 33.33335;
height: 400px;
}
.container > div:nth-child(1),
.container > div:nth-child(2) {
height: 200px;
}
setting appropriate heights to the child divs where the first two are half the height of the others.
Similarly, I've tried:
.container > div {
float: left;
}
.container > div {
height: 400px;
width: 33.33333%;
}
.container > div:nth-child(1),
.container > div:nth-child(2) {
height: 200px;
}
and again giving the first two children a height that is half the others. Nothing has worked, in all outcomes either the first two stack and the others do not float/flex up or the the first two do not stack at all.
Can anyone figure a CSS method of styling this structure for the desired UI?
Appreciate the help.
If you can set a fixed height on the container, you can use flexbox with flex-flow: column wrap. The fixed height is necessary to tell flex items where to wrap. Here's an example:
.container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-around; /* vertical alignment */
align-content: center; /* horizontal alignment */
height: 320px; /* essential for this method to work */
background-color: lightyellow;
border: 1px dashed red;
}
.container>div {
flex: 0 0 90%; /* flex-grow, flex-shrink, flex-basis */
width: 30%;
margin: 5px;
background-color: lightgreen;
}
.container>div:nth-child(1),
.container>div:nth-child(2) {
flex-basis: 40%; /* override flex-basis from rule above */
}
<div class="container">
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
</div>
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/
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