I'm trying to create a somewhat complicated layout with two columns taking up the remaining height of their parent but where one of the two columns is able to exceed these bounds if its content requires it. (In my case, this is an image but I don't believe this matters).
Here's a picture of the desired result which I'm sure will explain much better what I'm looking after.
Note: Here the red border represents the screen bounds (100vw x 100vh).
Here's what I tried so far:
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
.top {
background: orchid;
}
.columns {
flex: 1;
display: flex;
}
.columns>* {
flex: 1;
}
.left {
background: lightgreen;
/* Just make it larger than 100% */
height: calc(100% + 25px);
}
.right {
background: cornflowerblue;
}
<div class="container">
<div class="top">
Top Content
</div>
<div class="columns">
<div class="left">
Left Column
</div>
<div class="right">
Right Column
</div>
</div>
</div>
<div class="additional">
Additional Content
</div>
As you can see, the "additional content" section isn't pushed properly. This is because the left column is overflowing but isn't technically affecting its parent. I believe that if it did, then the right column wouldn't be sized properly. So this seems like two conflicting conditions and I'm not sure what to do.
Im not sure if this is the result you are looking for, but give it a try and let me know.
.container {
display: flex;
flex-direction: column;
height:max-content;
}
.top {
background: orchid;
}
.columns {
flex: 1;
display: flex;
}
.columns>* {
flex: 1;
}
.left {
background: lightgreen;
/* Just make it larger than 100% */
height: fit-content;
}
.right {
background: cornflowerblue;
max-height: 100vh;
}
First, the container is set to max-content, meaning that it will be as hight as the highes element inside it. Next, the right column is set to max-height:100vh, meaning that if your left column is not as high as 100vh, your container will be affected by that right column. As soon as left column exceeds 100vh mark of right column, the height:fit-content of left column makes its parent expand, leading to pushing the additional content properly while right column stays at 100vh.
In this case, if left column does not have enough content, it will get smaller then right column, if this is not desired behaviour, change the left-column height as you desire, but always us height properties that are affected by content (or min/max).
Related
I have 3 divs inside a container. There are no nested divs.
I am using flex and order property.
On mobile, it is ok with order property.
But on larger screens it fails.
I did not use a container div for divs 2 and 3 in order to order them as 2,1,3 on mobile.
HTML FILE
<div class="container">
<div class="orange">1</div>
<div class="blue">2</div>
<div class="green">3</div>
</div>
CSS FILE
/*************** MOBILE *************/
.container
{
display: flex;
flex-wrap: wrap;
}
div.blue
{
order:1;
width: 100%;
}
div.orange
{
order:2;
width: 100%;
}
div.green
{
order:3;
width: 100%;
}
/***************************/
#media screen and (min-width:1200px)
{
.container
{
justify-content: space-between;
}
div.blue
{
order:2;
width: 36%;
}
div.orange
{
order:1;
width: 60%;
}
div.green
{
order:3;
width: 36%;
}
}
In your layout, using row wrap for the desktop view will be difficult, if not impossible, to implement with CSS. At a minimum, things would get overly complex. Why?
Because flexbox is not a grid system. It's a layout system designed to align content by distribution of space in the container.
In flexbox, items in a row wrap container must wrap to new rows. This means that div3 cannot wrap beneath div2. It must wrap beneath div1.
Here's how items wrap in a flex container with row wrap:
If div3 were to wrap under div2, that wouldn't be a row, that would be a grid, and flex items are confined to a straight, unbending row.
Put another way, you can't make a flex item wrap under another item in the same row.
As a result, white space created by items that aren't the tallest in the row is preserved in each column, creating unsightly gaps.
For your desired layout to work in row wrap, flex items would have to exit their row in order to close the gap – maybe with absolute positioning – which flexbox cannot do.
One way to align the items would be to wrap div2 and div3 in their own container. This new container would be a sibling to div1. It can then become a nested flex container with flex-direction: column. Now the gaps are gone and layout looks right.
Except, in this particular case, you need the order property to work (meaning all items must have the same parent), so a nested flex container is out of the question.
What may work is column wrap instead of row wrap:
/*************** MOBILE *************/
.container {
display: flex;
flex-direction: column;
height: 200px; /* necessary so items know where to wrap */
}
div.orange {
background-color: orange;
}
div.blue {
order: -1;
background-color: aqua;
}
div.green {
background-color: lightgreen;
}
.container > div {
width: 100%;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
/***************************/
#media screen and (min-width: 800px) {
.container {
flex-wrap: wrap;
}
div.orange {
flex-basis: 100%;
width: 50%;
}
div.blue {
flex-basis: 50%;
width: 50%;
order: 0;
}
div.green {
flex-basis: 50%;
width: 50%;
}
}
<div class="container">
<div class="orange">1</div>
<div class="blue">2</div>
<div class="green">3</div>
</div>
jsFiddle
Here are two other options:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
CSS Grid Layout Module Level 1
This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design. In the grid layout model, the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.
source: https://drafts.csswg.org/css-grid/
Related post: Is it possible for flex items to align tightly to the items above them?
I am using flexbox to create my 2 column layout. Everything is working well, however I'd like to have my list items in my right column always take up the full height. Each <li> element contains an <img> element.
When I start to shrink the window width, as you can see, the <ul> element's height starts to scale up to keep it's aspect.
If I make the window really wide, the list element(s) will start to get clipped off.
I'd like to always be able to see all 4 list items. I'd be OK if I have to lock the width(s) or height(s) down. As you can see, I've set a min/max height but no luck. I am also OK with using the <li> elements as a container/viewable area for the images. Meaning, if the image inside the <li> gets clipped off overflow:hidden or something - that's fine. I am just trying to keep the two columns 50% each, and the right column always take the full height.
HTML
<div id="container">
<div id="foo">
...
</div>
<div id="bar">
<ul>
<li><img></li>
<li><img></li>
</ul>
</div>
</div>
CSS
#container {
display: flex;
flex-direction: row;
height: 600px;
min-height: 600px;
max-height: 600px;
}
#foo {
display: flex;
flex-direction: column;
order: 1;
width: 50%;
}
#bar {
display: flex;
flex-direction: column;
order: 2;
width: 50%;
}
Only give display: flex to the parent container. All children the inside parent container will be equal to the height of the child with the maximum height.
.container {
display: flex;
}
.foo {
width: 50%;
order: 1;
}
.bar {
width: 50%;
order: 2;
}
I have 3 divs inside a container. There are no nested divs.
I am using flex and order property.
On mobile, it is ok with order property.
But on larger screens it fails.
I did not use a container div for divs 2 and 3 in order to order them as 2,1,3 on mobile.
HTML FILE
<div class="container">
<div class="orange">1</div>
<div class="blue">2</div>
<div class="green">3</div>
</div>
CSS FILE
/*************** MOBILE *************/
.container
{
display: flex;
flex-wrap: wrap;
}
div.blue
{
order:1;
width: 100%;
}
div.orange
{
order:2;
width: 100%;
}
div.green
{
order:3;
width: 100%;
}
/***************************/
#media screen and (min-width:1200px)
{
.container
{
justify-content: space-between;
}
div.blue
{
order:2;
width: 36%;
}
div.orange
{
order:1;
width: 60%;
}
div.green
{
order:3;
width: 36%;
}
}
In your layout, using row wrap for the desktop view will be difficult, if not impossible, to implement with CSS. At a minimum, things would get overly complex. Why?
Because flexbox is not a grid system. It's a layout system designed to align content by distribution of space in the container.
In flexbox, items in a row wrap container must wrap to new rows. This means that div3 cannot wrap beneath div2. It must wrap beneath div1.
Here's how items wrap in a flex container with row wrap:
If div3 were to wrap under div2, that wouldn't be a row, that would be a grid, and flex items are confined to a straight, unbending row.
Put another way, you can't make a flex item wrap under another item in the same row.
As a result, white space created by items that aren't the tallest in the row is preserved in each column, creating unsightly gaps.
For your desired layout to work in row wrap, flex items would have to exit their row in order to close the gap – maybe with absolute positioning – which flexbox cannot do.
One way to align the items would be to wrap div2 and div3 in their own container. This new container would be a sibling to div1. It can then become a nested flex container with flex-direction: column. Now the gaps are gone and layout looks right.
Except, in this particular case, you need the order property to work (meaning all items must have the same parent), so a nested flex container is out of the question.
What may work is column wrap instead of row wrap:
/*************** MOBILE *************/
.container {
display: flex;
flex-direction: column;
height: 200px; /* necessary so items know where to wrap */
}
div.orange {
background-color: orange;
}
div.blue {
order: -1;
background-color: aqua;
}
div.green {
background-color: lightgreen;
}
.container > div {
width: 100%;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
/***************************/
#media screen and (min-width: 800px) {
.container {
flex-wrap: wrap;
}
div.orange {
flex-basis: 100%;
width: 50%;
}
div.blue {
flex-basis: 50%;
width: 50%;
order: 0;
}
div.green {
flex-basis: 50%;
width: 50%;
}
}
<div class="container">
<div class="orange">1</div>
<div class="blue">2</div>
<div class="green">3</div>
</div>
jsFiddle
Here are two other options:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
CSS Grid Layout Module Level 1
This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design. In the grid layout model, the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.
source: https://drafts.csswg.org/css-grid/
Related post: Is it possible for flex items to align tightly to the items above them?
I am building a page which has 8 items distributed over two rows using a flexbox container. Each item is 25% wide and 50% high. Because it is a horizontal scrolling page, I use px instead of % (values are generated by javascript based on the screen size). For this example I'm using a screen size of 1440px.
Now when I click on one of the items, it has to go to the very start, become twice as wide and twice as high.
It currently looks like this (ignore the blurry images please):
Initial state
Making the items wider is no problem (using flex-basis: 720px), but when I make the first item higher (height 100%), the items that were previously on the second row are no longer visible. Instead they are pushed down because of the first image: State when I make the first item bigger
What I actually want is that the smaller items are evenly distributed next to the bigger item. Is this possible?
This is my HTML markup (it contains web2py syntax, but there are 8 items in total):
<div class="scrollable">
<div class="flexcontainer">
{{for s in stages:}}
<div class="flexitem">
<img src="{{=URL('default', 'download', args=s.image)}}" class="stage-img">
</div>
{{pass}}
</div>
</div>
And this is my CSS:
.flexcontainer {
position: relative;
display: flex;
flex-flow: row wrap;
height: 100%;
width: 3000px; /* Hardcoded width for testing purposes */
}
.flexcontainer .flexitem {
flex: 1;
flex-basis: 360px;
height: 50%;
}
.flexcontainer .flexitem img {
width: 100%;
height: 100%;
}
/* Style for the active/clicked item */
.flexcontainer .flexitem.active {
flex-basis: 720px;
height: 100%;
}
I am really stuck with the css for this layout. Here is my html code :
<body>
<div id="main">
<div id="left">
menu
</div>
<div id="middle">
</div>
<div id="right">
sidebar
</div>
</div>
</body>
I want three columns left, middle and right with the width of 25%, 60%, and 15% percent width of the parent and all expand to the 100 percent height of their parent (main).
in the mean time I want the main div to have a minimum height of the browser window and maximum height of its children.
You can do it easily using CSS tables:
html, body {
height: 100%;
}
body {
margin: 0;
}
.main {
display: table;
height: 100%;
width: 100%;
}
.left, .middle, .right {
display: table-cell;
background-color: lightgray;
}
.left {
width: 25%;
}
.middle {
background-color: beige;
}
.right {
width: 15%;
}
See demo at: http://jsfiddle.net/audetwebdesign/9L8wJ/
To fill the height of the view port, you first need to set height: 100% on the html and body elements.
Apply display: table to the parent container and set the height: 100%, and since this is a table, this value acts as a minimum value, so it will fill the vertical screen unless the content is very long, and in this case, the table height will automatically increase to contain the content.
Add widths to the left and right column, the middle will fill the remainder so no need to do the math.
Finally, apply display: table-cell to the three child elements.
You may want to add a wrapper around the content in each table cell is you want better control of the white space between columns, but it depends on you layout and design.