Issue with flexbox - html

I'm new to flexbox and I created the following in order to have a top-navigation, with three columns below the top-navigation. When I open my HTML file the top-navigation is 80px tall but the three columns are only 50%, less the 80px for the header. I don't understand what is going on? Should the three columns not just fill in the difference?
body {
font: 24px Helvetica;
background: #999999;
}
.layout {
min-height: 100vh;
display: flex;
flex-flow: row;
flex-wrap: wrap;
}
.top-navigation {
width: 100vw;
height: 80px;
background: #cc2936;
}
.left-sidebar {
width: 25%;
background: #dcdcdc;
flexgrow: 1;
}
.main-outlet {
width: 50%;
background: #ffffff;
flexgrow: 1;
}
.right-sidebar {
width: 25%;
background: #dcdcdc;
flexgrow: 1;
}
<div class="layout">
<div class="box top-navigation"></div>
<div class="box left-sidebar"></div>
<div class="box main-outlet"></div>
<div class="box right-sidebar"></div>
</div>

I think you need to change your layout a little bit. You can then set the wrapping div to have flex-direction: column and align-content: stretchto the three columns like this:
body {
font: 24px Helvetica;
background: #999999;
margin: 0;
}
.layout {
min-height: 100vh;
display: flex;
flex-direction: column;
flex-flow: row;
flex-wrap: wrap;
align-content: stretch;
}
.top-navigation {
width: 100vw;
height: 80px;
background: #cc2936;
}
.left-sidebar {
width: 25%;
background: #dcdcdc;
}
.main-outlet {
width: 50%;
background: #ffffff;
}
.right-sidebar {
width: 25%;
background: #dcdcdc;
}
<div class="box top-navigation"></div>
<div class="layout">
<div class="box left-sidebar"></div>
<div class="box main-outlet"></div>
<div class="box right-sidebar"></div>
</div>

Related

How do I divide blocks in my page with flexbox?

I'm facing this problem where I want to have a header, sidebar and content with flexbox. I can't get to a solution to divide these 3 childs. I've been trying to use flex-grow and flex-direction:row but I'm having a problem.
Image of the website
How I want it to be
<style>
.parent {
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
height: 100vh;
border: 20px solid black;
display: flex;
flex-direction: column;
}
.header {
width: 200px;
height: 200px;
background: cornflowerblue;
}
.side {
width: 200px;
height: 200px;
background: rgb(219, 133, 133);
}
.content {
width: 200px;
height: 200px;
background: rgb(115, 202, 180);
}
.text {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 190px;
color: #fff;
}
</style>
<div class="parent">
<div class="header">
<h2 class="text">Header</h2>
</div>
<div class="side">
<h2 class="text">Side</h2>
</div>
<div class="content">
<h2 class="text">Content</h2>
</div>
</div>
You need to create two containers, one for all your elements and one for your header and content.
<div class="parent"> <!-- Container 1 -->
<div class="side">
<h2 class="text">Side</h2>
</div>
<div class="container"> <!-- Container 2 -->
<div class="header">
<h2 class="text">Header</h2>
</div>
<div class="content">
<h2 class="text">Content</h2>
</div>
</div>
</div>
Then, you can treat each container as a separate flex-box. the parent will have a flex-direction: row; and the container will have flex-direction: column;.
You also want to set values in percentages, not absolute values as you have right now (200px, 20rem..).
.parent {
box-sizing: border-box;
margin: 0;
padding: 0;
height: 100vh;
border: 20px solid black;
display: flex;
flex-direction: row;
}
.header {
height: 30%;
background: cornflowerblue;
}
.side {
width: 30%;
height: 100%;
background: rgb(219, 133, 133);
}
.content {
height: 70%;
background: rgb(115, 202, 180);
}
.text {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 190px;
color: #fff;
}
.container {
display: flex;
flex-direction: column;
width: 70%;
height: 100%;
}
JSFiddle
Images to illustrate the separation:
You have to wrap your header & content section inside another div. Something like this below example. However, The best way to achieve this layout is using a CSS grid. Here is the complete CSS grid guide
.parent {
display: flex;
height: 100vh;
background: #000;
padding: 5px;
margin: 0;
}
.side {
border: 1px solid #000;
width: 30vw;
display: flex;
justify-content: center;
align-items: center;
background: #fff;
margin-right: 5px;
}
.main-body {
border: 1px solid #000;
width: 70vw;
}
.header,
.content {
display: flex;
justify-content: center;
background: #fff;
}
.header {
height: 25vh;
margin-bottom: 5px;
}
.content {
align-items:center;
height: 70vh;
}
<div class="parent">
<div class="side">
<h2 class="text">Side</h2>
</div>
<div class="main-body">
<div class="header">
<h2 class="text">Header</h2>
</div>
<div class="content">
<h2 class="text">Content</h2>
</div>
</div>
</div>
I don't think that you deeply understand how flexbox work. You should read more about it. I advice you to read a book called CSS-in Depth. You can download it online from a website called Z-lib. Try to understand the code that I posted for you.
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.parent {
height: 100vh;
border: 20px solid black;
display: flex;
background: pink;
}
.main {
display: flex;
backgound-color: green;
flex-direction: column;
flex: 2
}
.header {
background: cornflowerblue;
}
.side {
flex: 1;
background: rgb(219, 133, 133);
}
.content {
background: rgb(115, 202, 180);
flex: 1
}
.text {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 190px;
color: #fff;
}
</style>
<div class="parent">
<div class="side">
<h2 class="text">Side</h2>
</div>
<div class="main">
<div class="header">
<h2 class="text">Header</h2>
</div>
<div class="content">
<h2 class="text">Content</h2>
</div>
</div>
</div>

Flexbox layout multiple items wrapping around a big one

I want to have a layout like the following image using flexbox:
I have tried the following but no luck so far:
.flex-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 200px;
}
.flex-item:not(:first-child) {
width: calc(100% - 50px);
background-color: gray;
border: 1px solid blue;
}
.flex-item:first-child {
width: 50px;
height: 100%;
border: 1px solid blue;
background-color: red;
}
<div class="flex-container">
<div class="flex-item">item 1(long)</div>
<div class="flex-item">item 2</div>
<div class="flex-item">item 3</div>
<div class="flex-item">item 4</div>
</div>
I need the DOM structure to be like this, otherwise, I already know how to achieve this with nested elements.
It's possible using your DOM structure but I doubt it will be particularly useful, and as others have said, you're better off using Grid or even just inline elements. The trouble is you are trying to mix two layout contexts and flexbox isn't really built for that.
Give the container a explicit height and the wider elements a flex:1 property, which will make them grow to fill the remaining space. I used nth-child as it is more readable to me and your original code didn't actually behave as you intended when put into codepen.
.flex-container {
border: 1px solid green;
display: flex;
flex-direction: column;
flex-wrap: wrap;
width: 200px;
height: 200px;
}
.flex-item {
height: 100%;
width: 50px;
background-color: gray;
border: 1px solid blue;
}
.flex-item:nth-child(n+2) {
width: calc(100% - 50px);
flex: 1;
border: 1px solid blue;
background-color: red;
}
<div class="flex-container">
<div class="flex-item">item 1(long)</div>
<div class="flex-item">item 2</div>
<div class="flex-item">item 3</div>
<div class="flex-item">item 4</div>
</div>
CSS Grid Layout would be more appropriate.
body {
background: white;
color: #323232;
font-weight: 300;
height: 100vh;
margin: 0;
font-family: Helvetica neue, roboto;
}
.flex-container {
display: grid;
width: 90%;
height: 50%;
margin: 2rem auto;
text-align: center;
grid-template-columns: 25% 75%;
grid-template-rows: 25% 25% 50%;
}
.flex-item1 {
grid-column: 1 / 2;
grid-row: 1 / 4;
background: pink;
}
.flex-item2 {
grid-column: 2 / 3;
grid-row: 1 / 2;
background: lightcoral;
}
.flex-item3 {
grid-column: 2 / 3;
grid-row: 2 / 3;
background: lemonchiffon;
}
.flex-item4 {
grid-column: 2 / 3;
grid-row: 3 / 4;
background: lightblue;
}
<div class="flex-container">
<div class="flex-item1">item 1</div>
<div class="flex-item2">item 2</div>
<div class="flex-item3">item 3</div>
<div class="flex-item4">item 4</div>
</div>
Although you can do it with Flexbox.
It makes more sense to me to make a small change to the DOM structure.
Your items 2, 3, 4 would be wrapped in an other Flex container.
body {
background: white;
color: #323232;
font-weight: 300;
height: 100vh;
margin: 0;
display: flex;
font-family: Helvetica neue, roboto;
}
.flex-container {
display: flex;
flex-wrap: wrap;
width: 90%;
height: 50%;
margin: 1rem;
text-align: center;
}
.flex-itemA {
width: 25%;
background: pink;
}
/* Flex-itemB and Flex container itself for the next 3 elements */
.flex-itemB {
width: 75%;
display: flex;
flex-wrap: wrap;
flex-direction: column;
background: lightblue;
}
.flex-itemB1,
.flex-itemB2 {
height: 25%;
}
.flex-itemB1 {
background: lightcoral;
}
.flex-itemB2 {
background: lemonchiffon;
}
<div class="flex-container">
<div class="flex-itemA">item A</div>
<div class="flex-itemB">
<div class="flex-itemB1">item B1</div>
<div class="flex-itemB2">item B2</div>
<div class="flex-itemB3">item B3</div>
</div>
</div>
EDIT based on #lawrence-witt answer
Or if you really want to keep the DOM structure that way and use Flexbox and not Grid. Then you could do it like #lawrence-witt suggested.
I kept the :nth-child selectors although it would be easy to add a class for each element and avoid increasing the specificity.
body {
background: white;
color: #323232;
font-weight: 300;
height: 100vh;
margin: 0;
font-family: Helvetica neue, roboto;
}
.flex-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
width: 90%;
height: 50%;
margin: 2rem 5%;
text-align: center;
}
.flex-item {
height: 100%;
width: 25%;
background: pink;
}
.flex-item:nth-child(n + 2) {
width: 75%;
/* This will make the height = 25% since the last element will have flex-grow: 1 */
flex: 0.5;
}
.flex-item:nth-child(2) {
background: lightcoral;
}
.flex-item:nth-child(3) {
background: lemonchiffon;
}
.flex-item:nth-child(4) {
flex: 1;
background: lightblue;
}
<div class="flex-container">
<div class="flex-item">item 1</div>
<div class="flex-item">item 2</div>
<div class="flex-item">item 3</div>
<div class="flex-item">item 4</div>
</div>

Flexbox grow div to take up remaining height

versions of this have been asked before and these questions helped me so far as to have a flex item that grows in height. However, it grows too much :)
Please see the code pen or the code here
https://codepen.io/surf-n-code/pen/wvwrbKW
Basically I have this Code
html,
body {
height: 100%;
}
.container {
height: 100%;
min-height: 100%;
display: flex;
flex-direction: column;
}
.box {
text-align: center;
color: white;
font-family: sans-serif;
font-size: 36px;
padding: 20px;
display: flex;
flex-direction: column;
justify-content: center;
}
.box-1 {
background-color: green;
height: 60px;
}
.box-2 {
background-color: blue;
flex: 1;
}
.box-3 {
background-color: red;
height: 60px;
}
<body>
<header>
<div class="box box-0">Header - sticks to top</div>
</header>
<main class="full-height">
<div class="nd_container">
<div class="box box-1">content</div>
<div class="box box-2">Flex grow</div>
</div>
</main>
<footer>
<div class="box box-4">Footer - stick to bottom</div>
</footer>
</body>
I would expect the box-2 to increase in size just enough such that the footer sticks exactly to the bottom of the page. I do not want any scrolling due to the created whitespace.
Any help is much appreciated :)
I hope this is what you expecting check out my answer.
NOTE:CHECK OUT MY ANSWER IN FULL SCREEN MODE
box-2 to increase in size just enough such that the footer sticks exactly to the bottom of the page.
html,
body {
height: 100%;
margin: 0;
height: 100vh;
display: flex;
flex-flow: column;
}
.nd_container {
height: 100%;
min-height: 100%;
display: flex;
flex-flow: column;
}
.nd_container .box {
text-align: center;
color: white;
font-family: sans-serif;
font-size: 36px;
padding: 20px;
justify-content: center;
}
.nd_container .box-1 {
background-color: green;
flex: 0 1 60px;
}
.nd_container .box-2 {
background-color: red;
flex: 1 1 auto;
}
.box {
text-align: center;
color: white;
font-family: sans-serif;
font-size: 36px;
display: flex;
flex-direction: column;
justify-content: center;
}
.box.box-0 {
background-color: #03a9f4;
height: 100%;
}
.box.box-4 {
background-color: #0c5460;
height: 100%;
}
header {
flex: 0 1 155px;
}
main {
flex: 1 1 auto;
}
footer {
flex: 0 1 155px;
}
<body>
<header>
<div class="box box-0">Header - sticks to top</div>
</header>
<main class="full-height">
<div class="nd_container">
<div class="box box-1">content</div>
<div class="box box-2">Flex grow</div>
</div>
</main>
<footer>
<div class="box box-4">Footer - stick to bottom</div>
</footer>
</body>

How to make flex item height of its parent?

I have a simple nav type layout using flex to space items with different widths horizontally. The items have lines between but as they different heights because the content had different heights
How can I make the items the height of the parent so all dividing lines go to the top of the parent.
https://codepen.io/anon/pen/zbEMVd
* {
font-family: sans-serif;
}
.wrap {
border: 1px solid grey;
display: flex;
padding: 5px;
justify-content: space-between;
max-width: 1200px;
}
.item:not(:last-of-type) {
border-right: 2px solid red;
}
.item-1 {
width: 150px;
}
.item-2 {
width: 50px;
}
.item-3 {
width: 50px;
}
.item-4 {
width: 50px;
}
.item-5 {
flex: 1;
}
.item-6 {
width: 50px;
}
<div class="wrap">
<div class="item item-1">One</div>
<div class="item item-2">Two Two Two Two Two </div>
<div class="item item-3">Three Three Three</div>
<div class="item item-4">Four</div>
<div class="item item-5">Five</div>
<div class="item item-6">Six</div>
</div>
Remove align-self from .item, and add display:flex; align-items: flex-end; instead.
.item{
display: flex;
align-items: flex-end;
/* ... */
}
https://codepen.io/anon/pen/ZPXVra
Make the item element a reverse-column flexbox (and remove align-self: flex-end from it) to get the effect - see demo below:
* {
font-family: sans-serif;
}
.wrap {
border: 1px solid grey;
display: flex;
padding: 5px;
justify-content: space-between;
max-width: 1200px;
}
.item {
/* align-self: flex-end; */
display: flex; /* ADDED */
flex-direction: column-reverse; /* ADDED */
background: #ddd;
}
.item:not(:last-of-type) {
border-right: 2px solid red;
}
.item-1 {
width: 150px;
}
.item-2 {
width: 50px;
}
.item-3 {
width: 50px;
}
.item-4 {
width: 50px;
}
.item-5 {
flex: 1;
}
.item-6 {
width: 50px;
}
<div class="wrap">
<div class="item item-1">One</div>
<div class="item item-2">Two Two Two Two Two </div>
<div class="item item-3">Three Three Three</div>
<div class="item item-4">Four</div>
<div class="item item-5">Five</div>
<div class="item item-6">Six</div>
</div>

Wrap element to new line/row using flexbox

I have trouble forcing an item into the next row in a flexbox layout.
How can I do something like the following image?
This is what I got so far:
#wrap {
display: flex;
width: 86vw;
height: auto;
box-sizing: border-box;
margin: 0 auto;
}
.item1,
.item2 {
width: 50%;
height: 24.5vw;
background: #4add69;
}
.item1 {
margin-right: 10px;
}
.item2 {
margin-left: 10px;
}
.item3 {
width: 60%;
height: 40vw;
background: #d56c6c;
}
<div id="wrap">
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
</div>
Your code is fine but missing two things.
Use flex-wrap: wrap to
create a new row. Modify the width of the first two items to be
present in a single row.
For the last two items, you need to nest it inside a container and
then wrap them again.
Manipulate the dimension(width, height) and margin values to achieve the perfect/suitable layout.
JSfiddle Demo
* {
margin: 0;
padding: 0;
}
body {
background: #232323;
padding: 10px;
}
#wrap {
display: flex;
width: 86vw;
height: auto;
box-sizing: border-box;
margin: 0 auto;
flex-wrap: wrap;
background: #232323;
/* Added */
}
.item1,
.item2 {
width: 48%;
/* Modified */
height: 24.5vw;
background: #4add69;
margin-bottom: 10px;
}
.item1 {
margin-right: 10px;
}
.item2 {
margin-left: 10px;
}
.item3 {
width: 55%;
height: 40vw;
background: #d56c6c;
margin-right: 10px;
}
.nested-items {
display: flex;
width: 42%;
flex-wrap: wrap;
align-content: space-between;
}
.item4,
.item5 {
background: lightblue;
width: 100%;
height: 49%;
}
<div id="wrap">
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
<div class="nested-items">
<div class="item4"></div>
<div class="item5"></div>
</div>
</div>
Essentially you need an extra wrapping div for the two 'small' elements like so:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.wrap {
width: 75%;
margin: 1em auto;
border: 1px solid green;
padding: .25em;
display: flex;
flex-wrap: wrap;
}
.wrap div {
border: 1px solid grey;
margin-bottom: 1px;
}
.box {
height: 80px;
background: lightblue;
flex: 0 0 50%;
}
.tall {
flex: 0 0 65%;
height: 160px;
}
.col {
flex: 0 0 35%;
display: flex;
flex-wrap: wrap;
}
.mini {
flex: 0 0 100%;
height: 80px;
background: pink;
}
<div class="wrap">
<div class="box"></div>
<div class="box"></div>
<div class="box tall"></div>
<div class="box col">
<div class="mini"></div>
<div class="mini"></div>
</div>
</div>
I've used a single overall element here with wrapping but the image suggests that this would be much simpler with actual rows and the extra wrapper mentioned before.
Codepen Demo of 2nd option with rows.