full height columns and header with flexbox - css

I'm newish to flexbox. My current layout isn't working as well as I'd hoped - my columns are only as tall as the content within them.
+----------------+
| header |
+-+--------------+
|n|content |
|v+--------------+
+-+
empty
----------------------
I'm hoping flexbox will solve that. I'll have to retrofit my existing markup.
Page is full screen width, with a full-width header, then the rest of the page is fluid width content with a fixed width sidebar. (Some pages have a sidebar on the left, others have one on the right.)
Ideally, the two content areas will both extend to the bottom of the page (with their coloured backgrounds) but only go over the fold and scroll if the content is longer than a page.
+----------------+
| header |
+-+--------------+
|n| content |
|a| |
|v| |
--+-+--------------+--
Do I treat the entire page as the "container", in which I create two rows, one of which is split? Or do I just start the flexbox stuff with the second row that has the sidebar?
It seems to me, it has to be the former, if flexbox is to know how high my header is. Otherwise, when I set their heights to 100%, they'll go over the fold by an amount equal to my header.
I didn't see a header-and-split-columns as a simple example in the flexbox docs, but I'll continue to read and experiment.
(Naturally, it will also have to be responsive, so that, at smaller screen sizes, the elements wrap under each other to fit on a narrow screen.)

OK, gathering all the feedback I've gotten above, and borrowing heavily from here, this is what I came up with.
<div class="page-body no-nav no-aside">
<main>
<p>content</p>
</main>
<nav>nav</nav>
<aside>details</aside>
</div>
.
.wrapper {
display: flex;
min-height: 100vh;
flex-direction: column;
background-color: blue;
header {
height: 155px;
}
.page-body {
display: flex;
flex: 1;
background-color: lavender;
flex-direction: column;
min-height: calc(100vh - 155px);
min-height: -webkit-calc(100vh - 155px);
nav {
order: -1;
background-color: red;
}
aside {
background-color: orange;
}
&.no-nav nav,
&.no-aside aside {
display: none;
}
}
}
#media (min-width: 768px) {
.wrapper {
.page-body {
flex-direction: row;
flex: 1;
main {
flex: 1;
}
nav {
flex: 0 0 385px;
}
aside {
flex: 0 0 320px;
}
}
}
}
Header is fixed height
Page-body fills the rest of the page
pretty straightforward to add a footer if needed (see Holy-Grail article above)
all columns are full height, no scrolling unless content flows
sidebars are fixed width, content body is fluid
structure is responsive
added some functionality to hide/show the sidebars as-needed per page
Oddly, this defaults to small-screen as has a media query that overrides for larger screens. (Usually the other way around where I come from.)

You can use calc for the min-height (assuming header height as 50px):
.content {
min-height: calc(100% - 50px);
min-height: -webkit-calc(100% - 50px);
}
As for the fixed width sidebar, prevent it from growing or shrinking:
.sidebar {
flex-shrink: 0;
flex-grow: 0;
}
I would only put the sidebar and the content in the flex box. Put both the sidebar and the content inside a container div and assign display:flex to the container:
.container {
display: flex;
flex-direction: row;
}
You will likely need your sidebar to collapse or become fluid with media queries when the window width decreases to a certain point. Also, I find this tool helpful when working with flex, as it does get complex.

You can create two flexboxes - one to divide header and "rest", and the other inside "rest" to divide it into nav and content.
Also you can just set min-height of header, as can be seen here

I hope I've understood your question.. This approach might help get you started. Let me know if you have any specific questions...
body {
margin: 0;
height: 100vh;
font-family: sans-serif;
color: white;
}
.container {
height: 100%;
background: grey;
display: flex;
flex-direction: column;
}
header {
height: 150px;
background: blue;
}
.content {
height: 100%;
display: flex;
background: green;
}
.sidebar {
background: #76c5ff;
width: 200px;
}
.main {
background: #ef3a59;
flex: 1;
}
#media (max-width: 600px) {
body {
height: initial;
}
.content {
height: initial;
}
.content {
flex-direction: column;
}
.sidebar {
width: 100%;
order: 2; /* remove this to keep sidebar above main content */
}
}
<div class="container">
<header>header
</header>
<div class="content">
<div class="sidebar">sidebar</div>
<div class="main">main content</div>
</div>
</div>

Related

Is this layout achievable with flexbox and no media queries?

I am carrying out my first "web design project?", and I am having this issue:
If the screen is +922px, I want the articles (flex-items) to fill as much width as available, but always forming a two-column layout inside the main (flex-container). When the screen is less than 922px, I want them to position in one column.
Is it possible to do this with flexbox, or I made a bad decision and I should use grid/media queries/column-count: 2 instead?
For now, I am uncapable to give the articles a reasonable width without them displaying into a 1-column layout when I shrink the page a little. I would like the items to shrink/grow a bit according to the browser length.
Sorry for my English by the way.
.main {
grid-column: 2/3;
grid-row: 2/3;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.main__title {
min-width: 100%;
margin-bottom: 0;
}
.article {
width: 500px;
}
.article__title {
width: 100%;
}
.article__p {
max-width: 75%;
margin: 0px;
}
.article__img {
margin: 1em;
width: 20%;
float: left;
}
The entire code here: https://github.com/llfontbote/DAW-M9

flexbox one element fixed height, other filling

I want to make some kind of image viewer with some descriptive text below. Problem is, that the lower box with the description has a fixed height and the image should fill the remaining height of whatever container it is in.
I wanted to use flexbox for that, as I think it seems to be the most elegant and simple solution (without using JS).
This this code and codepen for my current work, which seems to work mostly:
html, body, #container {
height: 100%
}
#container {
display: flex;
flex-direction: column;
}
#container > #image {
/* flex-grow: 1; */ /* not needed here? */
max-width: 75%;
background-color: #fcc;
margin: 0 auto;
}
img {
max-height: 100%;
/* HERE IS WHERE MY PROBLEM STARTS!; */
max-width: 100%;
}
#container > #text {
flex-grow: 0;
flex-shrink: 0;
background-color: rgba(128, 128, 128, 0.7);
padding: 5px;
max-width: 75%;
margin: 15px auto 0;
/* TOP MARGIN DOESN'T WORK */
}
http://codepen.io/Kageetai/pen/AaCJy
I got most of it to work but the image is not resizing itself correclty. As you can see through the transparent background of the text box, it stretches itself over the border of the containing div and even behind the text box.
So how can I retain the image with the correct aspect ratio inside its container?
And furthermore the centering with margin: 0 auto; seems to make problems when resizing the window. The image is not centered anymore and the page needs a refresh to make it work again.
So does anyone know how to make the image behave correctly? :)
For image , you can set an height, margin and display.
For image container, give a 2 or 3 value to flex and none to other, so it fills as much space as avalaible.
DEMO
CSS used :
html,
body,
#container {
height: 100%
}
#container {
display: flex;
flex-direction: column;
}
#container > #text {
background-color: #ccf;
padding: 5px;
}
#container>#image {
flex:3;
display:flex;
}
img {
width:auto;
display:block;
margin:auto;
height:100%;
}
Here's a more basic demo of how to achieve this.
<html style="height: 100%">
<body style="height: 100%; margin: 0; display: flex; flex-direction: column">
<p>Toolbar</p>
<div style="background: #bbb; flex: 1">Image</div>
</body>
</html>
A demo can be seen over at Codepen.

CSS Overflow: auto out of div boundaries

I have a problem combining div boxes and the overflow: auto property for adding scrollbars if needed.
The problem is that I don't want the whole page to be scrollable, but just the content div, thus I added overflow: hidden to the body and overflow: auto to the content.
body
{
padding: 0;
margin: 0;
background-color: navy;
overflow: hidden; /** no scrollbar on whole page **/
height: 100%;
}
#content
{
background-color: green;
overflow: auto;
height: 100%;
}
Nevertheless, I'm not able to see the end of the page, as the div increases its size beyond the viewable part of the website.
Please suggest how to solve this problem and only keep the content div scrollable.
I uploaded an example of my problem here: jsfiddle.net/3n7ay/
I can only get this to work with a fixed header height, is there no solution for dynamic header size? It's hard for me to believe...
Thanks & Regards
I think you looking for overflow-y: scroll; instead?
See fiddle: http://jsfiddle.net/3n7ay/5/
If you set height: 100% to the content element and you have also an header in your viewport this will make the former not entirely visible inside the viewport itself.
So the height must be defined as 100% - <header height>, either via javascript (if you need to support older browser) or via CSS3 calc() function, e.g.
#content {
height: -webkit-calc(100% - <height of header>px);
height: -moz-calc(100% - <height of header>px);
height: calc(100% - <height of header>px);
}
Try flex box, if you don't concern about Ie8 and Ie9. You can see the compatibility situation in caniuse.com: flexbox
Make container a flex box:
#container {
background-color: yellow;
height: 100%;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-ms-flex-direction: column;
-webkit-flex-direction: column;
flex-direction: column;
}
Flex the content:
#content {
background-color: green;
overflow: auto;
height: 100%;
-ms-flex: 1;
-webkit-flex: 1;
flex: 1;
}
See fiddle: http://jsfiddle.net/r4JUk/4/

Responsive web design scenario

I am designing a 3 column web page layout like below.
To make it responsive I specified widths in %, min width in pixels and float:left. Now If I resize the page, all 3 DIVs (1,2, and 3) get resized first then 3rd DIV moves below of 1st DIV. If I resize more then 2nd DIV moves to below of 1st and 3rd moves below to 2nd.
This is because of float property. But I want to modify it in such a way that 3rd DIV should be moved first (as it is already being) then 1st DIV should be moved instead of 2nd DIV. 2nd DIV must be on the top.
How can I do this?
Reordering can be done with Flexbox. You will, however need 1 media query.
http://codepen.io/cimmanon/pen/fwqed
body {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
}
div {
-webkit-flex: 1 1 20em;
-ms-flex: 1 1 20em;
flex: 1 1 20em;
}
#media (max-width: 40em) {
.a, .c {
-ms-flex-order: 1;
-webkit-order: 1;
order: 1;
}
}
.a {
background: orange;
}
.b {
background: yellow;
}
.c {
background: grey;
}
Reordering can also be done with relative positioning (see: https://stackoverflow.com/questions/16307621/reordering-elements-at-specific-browser-widths).
Sorry I had some missed some details on how it should look earlier, here is another solution with some simple jQuery/javascript:
http://jsfiddle.net/jzxww/4/
This solution has Column 1 move to the bottom instead of to the middle.
Here is the code broken down
function resizeHandlr(){
trigger = $("#superwrap").width(); // get width of wrapper
$("#supersize").html("superwrap size: " + trigger + "px");
if (trigger > 600){
// if greater than 600px, make all widths 33.33% so they are responsive;
} else if ( (trigger < 600) && (trigger > 400)){
// if between 600 and 400px, make top columns 50% and bottom one 100%
// move column1 back to top of wrapper (if coming from < 400px)
} else if (trigger < 400) {
// if wrapper is less than 400px, make all widths 100%
// also MOVE column 1 to the bottom of wrapper
}
}
try this
//css
.left-col{float:left;width:33%}
.right-col{float:right;width:33%}
.main-col{margin: 0 33%}
//html
<div class="left-col"> some text </div>
<div class="right-col"> some text </div>
<div class="main-col"> some text </div>
I got pretty close to a 2,3,1. Check it out: http://jsfiddle.net/3QFaa/
New HTML Markup
<div id="superwrap">
<div id="muahaha">
<div id="col2">2</div>
<div id="col3">3</div>
</div>
<div id="col1">1</div>
CSS
#superwrap { position: relative; width: 100%; background-color: orange; min-width: 200px;}
#muahaha {top: 0px; width:66.66%; float: right; min-width: 200px; }
#muahaha:after {
content: "";
display: table;
clear: both;}
#col2, #col3 { float: left;}
#col1 { background-color: cyan; width: 33.33%; min-width: 200px;}
#col2 {background-color: yellow; width: 50%; min-width: 200px;}
#col3 { background-color: green; width: 50%; min-width: 200px;}
Thanks #sebastianG for the fiddle.
Only problem with this is, as you notice, col1 does not drop until it hits the very far right edge of #superwrap
Another nearly-perfect version:
If col1 does not have to be centered immediately:
http://jsfiddle.net/XDTEW/
Added float: left to col1
I also think you will be better using #media queries for different screen size scenarios.

force footer on bottom on pages with little content

I have a page with only a couple of lines of content. I want the footer to be pushed to the bottom.
<div id="footer"></div>
I don't want to use
#footer
{
position:fixed;
bottom:0;
}
AKA Sticky Footer
Is this possible without jQuery?
any suggestions?
This Flexbox solution is neater and far easier to implement:
HTML
<body>
<div class="content">
content
</div>
<footer class="footer"></footer>
</body>
CSS
html, body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
}
.content {
flex: 1 0 auto;
}
.footer {
flex-shrink: 0;
}
Just ensure you wrap the necessary divs inside the body.
Update 2021 - CSS GRID
Here is a solution using CSS Grid, this is by far the best way to do it on 2021.
html, body {
margin: 0;
height: 100%;
}
body {
display: grid;
grid-gap: 10px;
grid-template-columns: 1fr;
grid-template-areas: "main" "footer";
grid-template-rows: 1fr 80px;
}
main {
background-color: #F8BBD0;
grid-area: main;
}
footer {
background-color: #7E57C2;
grid-area: footer;
}
<body>
<main>The content</main>
<footer>Footer</footer>
</body>
Old Answer
There is another sticky footer by Ryan Fait that doesn't use position fixed:
* {
margin: 0;
}
html, body {
height: 100%;
}
.wrapper {
min-height: 100%;
height: auto !important; /* This line and the next line are not necessary unless you need IE6 support */
height: 100%;
margin: 0 auto -155px; /* the bottom margin is the negative value of the footer's height */
}
.footer, .push {
height: 155px; /* .push must be the same height as .footer */
}
Here is a solution that does not require that the footer be placed outside of the main wrapper element, which is how most people structure their pages.
html,
body {
margin: 0;
height: 100%;
}
.wrapper {
box-sizing: border-box;
position: relative;
padding-bottom: 1em; /* Height of footer */
min-height: 100%;
}
header {
background-color: #cff;
}
footer {
position: absolute;
bottom: 0;
width: 100%;
color: #fff;
background-color: #000;
}
<div class="wrapper">
<header>I am the header.</header>
<article>I am content that doesn't fill the page. The footer will appear at the bottom of the browser window. However, when I do fill the page, you will need to scroll down to see the footer.</article>
<footer>I am the footer.</footer>
</div>
Explanation
The wrapper element will fill 100% of the viewport height. (You could also use 100vh for the wrapper if you don't want to set the height of the html and body elements.) The wrapper also has a bottom padding to create a placeholder for the footer to sit.
The footer is absolutely positioned to the bottom of the wrapper and sits in the placeholder created by the wrapper's bottom padding.
This means that when the page does not have scrollbars, the footer will be positioned at the very bottom. However, when there is enough content for scrollbars to appear, the footer will be pushed down below the content.
(The color and background-color CSS properties in the example are for decoration only, obviously. They are included so that when you run the code, you can clearly see the separated sections.)
Try Sticky Footer Solution by Steve Hatcher
/*
Sticky Footer Solution
by Steve Hatcher
http://stever.ca
http://www.cssstickyfooter.com
*/
* {
margin: 0;
padding: 0;
}
/* must declare 0 margins on everything, also for main layout components use padding, not
vertical margins (top and bottom) to add spacing, else those margins get added to the total height
and your footer gets pushed down a bit more, creating vertical scroll bars in the browser */
html, body {
height: 100%;
}
#wrap {
min-height: 100%;
}
#main {
overflow: auto;
padding-bottom: 180px;
}
/* must be same height as the footer */
#footer {
position: relative;
margin-top: -180px; /* negative value of footer height */
height: 180px;
clear: both;
}
/*Opera Fix*/
body:before {
/* thanks to Maleika (Kohoutec)*/
content: "";
height: 100%;
float: left;
width: 0;
margin-top: -32767px; /* thank you Erik J - negate effect of float*/
}
/* IMPORTANT
You also need to include this conditional style in the <head> of your HTML file to feed this style to IE 6 and lower and 8 and higher.
<!--[if !IE 7]>
<style type="text/css">
#wrap {display:table;height:100%}
</style>
<![endif]-->
*/
Another way to do this if you don't know the footer size is to use javascript and css
html, body{
height:100%;
height:100%;
}
#footer{
background-color: #292c2f !important;
position:absolute;bottom:0px;
}
and Javascript part
$(document).ready(function(){
if ($(document).height() > $(window).height()) {
$('#footer').css('position', 'relative');
}
});
You can do this with another approach just easily by setting min-height on the tag before your footer tag.
.the-tag-before-footer{
min-height:30%;
}
I tried a lot of approaches, but results were different when page was totally fill or not. The simplest and efficient solution is to use flex.
html, body {height: 100%;}
body {display: flex; flex-direction: column;}
.content {flex: 1 0 auto; padding: 20px;}
.footer {flex-shrink: 0; padding: 20px;}
<div class="content">
<h1>The GOAT Footer with Flexbox</h1>
<p>You can add content to test with a full page</p>
</div>
<footer class="footer">
The GOAT Footer
</footer>
Credits to CSS Trick
First wrap all of your main content in a div element and give it a class of “wrapper” (or call it whatever you want).
HTML:
<body>
<div class="wrapper">
<h1>Main Content</h1>
</div>
<footer>
<p>Footer Content</p>
</footer>
</body>
Now, make sure you give your footer a height.
Then use the calc() function to set the height of your wrapper equal to the height of the viewport (display), minus the height of the footer.
.wrapper {
min-height: calc(100vh - 50px);
}
footer {
height: 50px;
}
Now, if you have extra margins on your wrapper content you will have to increase the amount of pixels you subtract from the viewport height to reflect that. Other than that, this is a super easy and quick fix. No javascript needed, and only two CSS rules.
The problem is simple to solve for anyone using Bootstrap 4 or higher, just include this snippet on your website:
<script>
$(document).ready(function(){
if ($('body').height() < $(window).height()) {
$('footer').addClass('position-absolute bottom-0');
} else {
$('footer').addClass('position-static');
}
});
</script>
Here we check if the height of the BODY tag is less than the height of the browser window, if positive we place the footer at the bottom of the page and if negative we make the footer static and it will remain where it is. You don't need to change your current code, you just need to include this javascript in your page or package, remembering that to work the <body> tag must have position: relative, if you haven't changed the tag's "position" property in CSS <body>, you don't need to do anything as it is the default value.
Make sure to include the code after jquery, without jquery it won't work.
If you are not using the <footer> tag, you should change the $('footer') selector as appropriate.

Resources