Vertically centered nested flex box - css

I am trying to achieve a simple layout with three vertical sections:
Small header on top of the page.
Main content, expanded if necessary so that the footer remains at the bottom of the page.
Footer at the bottom of the page.
The main content section should be further divided in two sections: a very small form with an input box and a button and a 5-row-max table showing some tabular data. The table should take up as much vertical space as needed, an the small form should be centered in the remaining vertical space.
I've tried using flex boxes but there is something I am doing wrong; I cannot manage to vertically center the tiny form in the available space. This is a simplified version of what I've done so far (best viewed in full screen):
body {
margin:0;
min-height:100vh;
display:flex;
flex-direction:column;
align-items:center;
}
main {
flex:1;
display:flex;
flex-direction:column;
}
main>form {
flex:1;
}
<body>
<header>header</header>
<main>
<form>
<h1>Form with inputs</h1>
<label>Inputs</label>
<input type="text">
<button>Button</button>
</form>
<div>
<h1>Other content</h1>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</main>
<footer>footer</footer>
</body>
I have tried multiple combinations of justify-content, align-content, align-items and align-self but the more I try, the less I seem to understand what I am doing :-(
Can anyone who does, provide me with any hints as to what I am doing wrong?
EDIT: If I could use fixed heights for some elements, I might do something like this (which also illustrates what I am after, better viewed in full screen):
* {
box-sizing:border-box;
}
html {
height:100%;
}
body {
margin:0;
height:100%;
position:relative;
}
header {
height:40px;
background-color:#E6ECC1;
}
main {
height:calc(100% - 80px);
background-color:#dfd;
}
h1 {
margin:0;
padding:10px 0;
}
main>form {
height:calc(100% - 150px);
background-color:#C1E4EC;
}
main>form:before {
content:"";
display:inline-block;
height:100%;
vertical-align:middle;
}
main>form>div {
display: inline-block;
vertical-align: middle;
width: calc(100% - 4px);
text-align: center;
}
main>div {
padding:0 20px;
height:150px;
position:absolute;
bottom:40px;
}
footer {
position:absolute;
height:40px;
width:100%;
bottom:0;
background-color:#fdd;
}
<body>
<header>header</header>
<main>
<form>
<div>
<h1>Form with inputs</h1>
<label>Inputs</label>
<input type="text">
<button>Button</button>
</div>
</form>
<div>
<h1>Other content</h1>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</main>
<footer>footer</footer>
</body>
I thought I would be able to implement this more cleanly using two nested flex boxes; an outer one providing room for the header at the top, the footer at the bottom and a mid section that can grow to fill all available space in between, and an inner one dividing the outer mid section into two; a bottom one with a constant but unknown height and a top one taking up all remaining space in the mid section. The content of this block, much smaller than the available area when the page is viewed in a large display, should be centered both horizontally and vertically in the available area.
When I only use an outer flex box (the <body> element in my original snippet) the content is centered vertically between the header and the footer. But when I try to split the mid section (the <main> element in my original snippet), the form is pushed upwards. It is as if the height of the flex:1 element in the outer box were not available to its children elements.
Thank you very much, have a good day.

Your centering (justify/align-content) isn't inherited so you have to restate it for each flex-container.
body {
margin: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
}
header {
background: green
}
main {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: pink;
}
main>form {
background: orange;
}
<body>
<header>header</header>
<main>
<form>
<h1>Form with inputs</h1>
<label>Inputs</label>
<input type="text">
<button>Button</button>
</form>
<div>
<h1>Other content</h1>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</main>
<footer>footer</footer>
</body>

I thank everyone who answered, although the answers did not quite do what I was trying to do. In the end, I have managed what I was after by wrapping the form inside an extra div to which I applied the flex attributes:
body {
margin: 0;
background-color: #F3F3F3;
display: flex;
flex-direction: column;
height: 100vh;
}
header {
background-color: #fdd;
}
main {
flex: 1;
display: flex;
flex-direction: column;
}
div.form {
background-color: #dfd;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 20px;
}
div.other {
background-color: #fdb;
padding: 0 10vw;
}
footer {
background-color: #ddf;
}
<body>
<header>header</header>
<main>
<div class="form">
<form>
<h1>Form with inputs</h1>
<label>Inputs</label>
<input type="text">
<button>Button</button>
</form>
</div>
<div class="other">
<h1>Other content</h1>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</main>
<footer>footer</footer>
</body>
I hope this can help someone else with a similar problem in the future!

Get rid of align-items: center; because it turns block elements into inline-blocks, use text-align: center instead.
both html and body would require a defined height of 100%
If you want the form inside main to take most space, then simply apply flex: 1 to it.
Working simplified demo:
html, body {margin: 0; padding: 0; height: 100%; text-align: center;}
body { width: 100%; display:flex; flex-direction:column; }
header { padding: 1em; background: lightblue; }
footer { padding: 1em; background: gray; }
main { flex:1; display:flex; flex-direction:column; background: lightyellow; overflow: auto;}
main > form { border-bottom:1px dashed gold; flex:1; }
#data { padding: 1em; }
main ul { margin: 0; padding: 0; display: inline-block }
<header>header</header>
<main>
<form>
<h1>Form with inputs</h1>
<label>Inputs</label>
<input type="text">
<button>Button</button>
</form>
<div id="data">
<h1>Other content</h1>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</main>
<footer>footer</footer>
jsFiddle: https://jsfiddle.net/azizn/hLse4wa7/

Related

Put nav and img elements inline and above a common border

I am trying to put nav and img elements next to each other on top of the page.
I am putting both elements in the top_bar container.
I have tried setting the top_bar to display: inline-block;, reducing the width of nav and floating it to left and also floating the img to right. Then I have tried combinations of those, but nothing gives me the result I want. Either the elements start to jump around or the logo is put below the top_bar border.
How can I have nav and img inline and both above the top_bar bottom border?
EDIT: I also want the nav element to be positioned left-most of the page, and img right-most.
<!DOCTYPE HTML>
<html>
<head>
<style>
#top_bar {
border-bottom: 1px solid silver;
}
nav ul li {
display: inline-block;
}
img {
width: 130px;
height: 30px;
}
</style>
</head>
<body>
<div id="top_bar">
<nav>
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</nav>
<img src="cs_logo.png" alt="Image not found"></img>
</div>
</body>
</html>
Add display: flex; to #top_bar
#top_bar {
border-bottom: 1px solid silver;
display: flex;
justify-content: space-between;
}
nav ul li {
display: inline-block;
}
img {
width: 130px;
height: 30px;
}
<div id="top_bar">
<nav>
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</nav>
<img src="cs_logo.png" alt="Image not found"></img>
</div>
<!DOCTYPE HTML>
<html>
<head>
<style>
#top_bar {
border-bottom: 1px solid silver;
display: flex;
flex-direction: row;
align-items: center;
}
nav ul li {
display: inline-block;
}
img {
width: 130px;
height: 30px;
}
</style>
</head>
<body>
<div id="top_bar">
<nav>
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</nav>
<img src="cs_logo.png" alt="Image not found"></img>
</div>
</body>
</html>
We can use CSS flex properties to achieve this. But please make sure that you are using vendor prefixes for cross browser compatability.
Your code is missing some declarations.
At first your class #top_bar should have a width declaration.
To make things easyier you could use a class instead of only declare
the image size.
Here´s a fiddle of your code that i´ve modified: https://jsfiddle.net/Thorske/nyv6mwgz/
Modified css:
* {
margin : 0:
padding : 0;
}
#top_bar {
margin : 0 auto;
width : 100%;
border-bottom: 1px solid silver;
}
.clear {
clear : both;
}
nav {
float : left;
width : 80%;
}
nav ul li {
display: inline-block;
}
.img_container {
float : right;
width : 20%;
}
.img_conatiner img {
width: 130px;
height: 30px;
}
Modifed html:
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<div id="top_bar">
<nav>
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</nav>
<div class="img_container">
<img src="cs_logo.png" alt="Image not found" />
</div>
<div class="clear"></div>
</div>
</body>
</html>
There only simple changes:
the #top_bar has now a defined width.
nav has now a defined width and float.
added the class "img_container" with defindet width and float
which contains the image.
the class clear keeps everything were it is supposed to be.
Since i don´t know if you want to make your code "responsiv" you´ve
to set your values for "width" yourself.

Centering Navigation around a centre logo image

I have a navigation bar as shown here: http://i.imgur.com/4rxkS2K.jpg
I am using foundation to build a website, the way I have built the nav bar is as follows:
HTML:
<nav class="top-bar">
<ul>
<li>About</li>
<li id="menu-divider">|</li>
<li>Testimonials</li>
<li><img src="images/logo.png" alt=""></li>
<li>Services</li>
<li id="menu-divider">|</li>
<li>Contact</li>
</ul>
</nav>
CSS:
.top-bar { font-family: 'bebas_neueregular';
height: 150px;
line-height: 100px;
padding: 18px;
width: 100%;
position: relative;
text-align:center;
margin-bottom:10px; }
.top-bar ul { display:inline-block;
margin-left: auto ;
margin-right: auto ;}
.top-bar ul > li { display:inline-block;
margin-left: auto ;
margin-right: auto ;}
#menu-divider { color:#ffffff;
font-size: 24px;}
As you can see in the picture, the way I have built it means that my center li element (my logo picture) is not in exact center as the other li elements are of different widths meaning they are all centered collectively. What I'm after is the logo in the dead center then the other li elements as they are centered around the logo.
Thanks in advance for any help!
You can play around but I'm pretty sure this does the trick:
http://codepen.io/anon/pen/dYXQpz
Use 3 containers (that means you lose your nav as a ul). Flex them and inside of the left and right one, flex the elements (end for the first, start for the other)
<div class="nav-bar">
<div class="sideNav leftNav">
<div class="menu">
MENU 1
</div>
<div class="split"></div>
<div class="menu">
MENU 2
</div>
</div>
<div class="logo">
<img src="https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcSN9qhGx6NftAepiMOjdGXkcW-UxkO9dtQ4VGRlepyzNC2S8xQCcA" />
</div>
<div class="sideNav rightNav">
<div class="menu">
MENU 3
</div>
<div class="split"></div>
<div class="menu">
MENU 4
</div>
</div>
</div>
Then apply the css. It can be improved but it can help you get started.
.nav-bar {
background: pink;
display: flex;
}
.sideNav {
flex: 1 0 auto;
background: red;
display: flex;
}
.leftNav {
justify-content: flex-end;
}
.rightNav {
justify-content: flex-start;
}
.sideNav > div {
margin: 100px 20px 0 20px;
}
.split{width: 2px;background: white;height: 16px}
Hope that helps. I loves flexbox.

CSS keep menu in container and expand background to full screen

The picture below shows what I would like to get.
It is a menu within a container, where the menu may wrap to multiple lines when the window/screen gets too narrow for all menu items to fit in. At the same time I would like the menu to have a background which expands to full screen in width, while expanding in height with the menu when it gets wrapped to multiple lines. Currently I think this is not possible with CSS, but I am also just a CSS amateur. My current solution involves #media queries to set the height of the menu background for resolutions where wrapping appears. This does not take into account that font-size could change, thus making each line of menu higher.
Here is a jsFiddle with a basic setup, which does NOT what I want:
https://jsfiddle.net/n3jmyq2f/3/ (Edited, was not the final version)
Here is the code:
<div class="container">
<div class="menu_wrap">
<div class="menu_bg"></div>
<div class="menu">
<ul>
<li>item 1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
<li>item6</li>
</ul>
</div>
</div>
<div class="content">It's me, Mario!</div>
CSS:
.container {
width:50%;
margin: 0 auto;
background:lightgreen;
height:300px;
}
.menu_bg{
position: absolute;
background: #afafaf;
width: 100%;
left:0;
height:30px;
z-index: -1;
}
ul {
height:30px;
background: #afafaf;
}
li {
display:inline-block;
}
The first option is the simplest.
Stop thinking of the .container as something that must contain everything. It's just a class that can be reused as and when required.
If you take the menu div out of the "container" but put a .container div inside you get the effect you are looking for.
JSfiddle Demo
*,
body {
padding: 0;
margin: 0;
}
.container {
width: 50%;
margin: 0 auto;
background: lightgreen;
}
.menu {
background: #afafaf;
}
ul {
border: 1px solid green;
}
li {
display: inline-block;
}
.content {
height: 300px;
}
<div class="menu">
<div class="container">
<ul>
<li>item 1
</li>
<li>item2
</li>
<li>item3
</li>
<li>item4
</li>
<li>item5
</li>
<li>item6
</li>
</ul>
</div>
</div>
<div class="container">
<div class="content">It's me, Mario!</div>
</div>
2nd Option
Use a pseudo-element
*,
body {
margin: 0;
padding: 0;
}
.container {
width: 50%;
margin: 0 auto;
background: lightgreen;
height: 300px;
}
ul {
background: #afafaf;
position: relative;
border: 1px solid green;
}
ul:before {
content: '';
position: absolute;
height: 100%;
background: inherit;
width: 100vw;
left: 50%;
transform: translateX(-50%);
z-index: -1
}
li {
display: inline-block;
}
<div class="container">
<div class="menu">
<ul>
<li>item 1
</li>
<li>item2
</li>
<li>item3
</li>
<li>item4
</li>
<li>item5
</li>
<li>item6
</li>
</ul>
</div>
<div class="content">It's me, Mario!</div>
</div>
JSfiddle Demo
if in .container you change
width:50%;
to
width:100%;
it will do it
fiddle
you could also use the .menu-wrap class (which I've seen in your markup) to do this

Centering floating elements

Currently I have the following code...
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<meta charset="UTF-8" />
<link href="verna.css" type="text/css" rel="stylesheet" />
</head>
<body>
<section id="devices">
<h1>Gruppen</h1>
<div class="group">
<h2>Gruppe 1</h2>
<ul>
<li class="device">Schalter 1</li>
<li class="device">Schalter 2</li>
<li class="device">Schalter 3</li>
</ul>
</div>
<div class="group">
<h2>Gruppe 2</h2>
<ul>
<li class="device">Schalter 1</li>
<li class="device">Schalter 2</li>
<li class="device">Schalter 3</li>
</ul>
</div>
</section>
</body>
</html>
* {
margin: 0;
padding: 0;
}
ul {
list-style-type: none;
}
#devices {
background-color: yellow;
}
#devices .group {
background-color: gray;
}
#devices .group ul {
text-align: center;
}
#devices .group .device {
background-color: green;
display: inline-block;
margin: 5px;
max-width: 200px;
width: 100%;
}
... which looks like this:
But I want that the green <li>-elements floats in columns. It should look like this:
Please note: The number of the green <li>-elements is variable, there can be more or less than three elements and there can be more than two columns! I want to order the <li>-elements "column-wise" and center them...
Thanks for help :-)
The thing that is centering "Schalter 3" is text-align: center;. We can fix this by removing
#devices .group ul {
text-align: center;
}
and adding:
#devices .group ul {
margin-left: 50px;
}
#devices .group li {
text-align: center;
}
in its place. This centers the text in the li element, instead of centering the li element inside the ul. And it adds the margin to the left to get the indent you wanted.
Working Fiddle.
Restructure your html so that each "column" is it's own container (div) which has an appropriate width. Alternatively, if you hate yourself, use a table.
Check out this fiddle.
The trick was to turn the lis back into block-level elements so that they could have width. Then set width: 40%; (40% leaves a little room for the 5px margin) and float: left;. Also adding overflow: auto; to the ul so that it would contain its floated lis.

Using 960.gs and sticky footer content div background does not stretch to the bottom of the page

I'm using the 960.gs frameowrk and http://www.cssstickyfooter.com and want to have a separate back ground colour for the main content div. This div won't stretch the background to the bottom of the page.
HTML:
<div id="wrapper">
<div id="content" class="container_12">
<div class="grid_12" id="header"><img src=logo.png" alt="" width="145" height="160" border="0" /></div><!--header-->
<div class="clear"></div>
<div class="grid_12" id="navbar">
<ul>
<li>Home</li>
<li>menu 1</li>
<li>menu 2</li>
<li>menu 3</li>
<li>menu 4</li>
<li>menu 5</li>
</ul>
</div><!--navbar-->
<div class="clear"></div>
<div class="grid_12" id="content_body">
<div class="grid_4" id="sidebar">
sidebar left
</div> <!--sidebar-->
<div class="grid_7" id="body_right">
body right
</div> <!--body_right-->
</div> <!--content_body-->
<div class="clear"></div>
</div><!--content-->
</div> <!--wrapper-->
<div id="footer"> footer </div> <!--footer-->
CSS:
html, body, #wrapper {height: 100%;}
body > #wrapper { height: auto; min-height: 100%; }
/* must be same height as the footer */
#content { overflow: auto;
padding-bottom: -1.5em;
}
#footer {
position: relative;
margin-top: -1.5em; /* negative value of footer height */
height: 1.5em;
clear: both;
}
/*Opera Fix*/
body:before { /* thanks to Maleika (Kohoutec)*/
content: "";
height:100%;
float: left;
width: 0;
margin-top: -32767px; /* thank you Erik J */
}
body {
min-width: 960px;
background: #E9F2F9;
}
div#header{
background-color: #3399cc;
}
div#navbar {
background-color: #FF9900;
}
div#navbar LI{
margin: 0 auto;
display: inline;
padding-right: 5px;
}
div#content_body{
background: #9CC4E4;
}
You have a div class="clear" but clear isn't defined in your CSS - you need to specify "clear:both" in a .clear CSS class.

Resources