Nested Flexbox with horizontal overflow - html

I am using a nested flexbox layout.
I would like a left nav to always be 1/3rd of the page, and the right side always be 2/3rds.
The left nav should always stay in view.
The right side (an image carousel in my case) should always take up 2/3rds and have a horizontal scrollbar on the boxes.
In the code below, it simply stretches and ignores the overflow.
<div>
Top Header (should stay in view)
</div>
<div style="display: flex">
<div style="flex: 1 0 auto">
LeftNav
</div>
<div style="flex: 2 0 auto">
<div style="display: flex; flex-direction: row; overflow-x: scroll">
<div style="background-color: blue; min-width: 400px; height: 500px">
</div>
<div style="background-color: red; min-width: 400px; height: 500px">
</div>
<div style="background-color: green; min-width: 400px; height: 500px">
</div>
</div>
</div>

Instead of flex-grow, which simply distributes free space in the container, use flex-basis, which explicitly sizes your items 1/3 and 2/3.
Then, because the default minimum width of flex items is min-width: auto, meaning they cannot be smaller than the size of their content, use min-width: 0 to override that default on the carousel.
<div>
Top Header (should stay in view)
</div>
<div style="display: flex">
<div style="flex: 0 0 33%">LeftNav</div>
<div style="flex: 0 0 67%; min-width: 0;">
<div style="display: flex; flex-direction: row; overflow-x: scroll">
<div style="background-color: blue; min-width: 400px; height: 500px">
</div>
<div style="background-color: red; min-width: 400px; height: 500px">
</div>
<div style="background-color: green; min-width: 400px; height: 500px">
</div>
</div>
</div>

First, I've moved your styles to classes. Don't use inline CSS.
flex CSS property is shorthand for setting flex: [flex-grow] [flex-shrink] [flex-basis].
You can set fixed percentage to your flex-basis values and zeros to flex-grow and flex-shrink to avoid flex items growing and shrinking.
Also you show move scroll CSS to your right nav block.
*,
*:before,
*:after {
box-sizing: border-box;
}
.main-container {
display: flex;
}
.left-nav {
flex: 0 0 calc(100% / 3); /* One third width */
}
.right-nav {
flex: 0 0 calc(200% / 3); /* Two third width */
overflow-x: scroll;
}
.right-nav-container {
display: flex;
}
.right-nav-item {
min-width: 400px;
height: 500px
}
.right-nav-item:nth-child(1) {
background-color: blue;
}
.right-nav-item:nth-child(2) {
background-color: red;
}
.right-nav-item:nth-child(3) {
background-color: green;
}
<div>
Top Header (should stay in view)
</div>
<div class="main-container">
<div class="left-nav">
LeftNav
</div>
<div class="right-nav">
<div class="right-nav-container">
<div class="right-nav-item">
</div>
<div class="right-nav-item">
</div>
<div class="right-nav-item">
</div>
</div>
</div>
</div>

Related

Have flex children only use space if they need it to not scroll, but otherwise share space equally and scroll

I have two flex children that may either each be small or large, and I'm defining small as < 50% of the container's height and large as > 50% the container's height. The sum of the heights of the children may be larger than 100% of the container's height, in which case I'd want one or both to scroll.
If one child is small and the other is large, I'd like the small element to use exactly the space it needs: it should not shrink to accommodate the large element, nor grow to 50%, and it should not scroll its contents. I'd like the large element to use the rest of the space, and scroll its contents if necessary.
If both are large, I'd like them to each use 50% of the container's height and scroll their contents.
I have this Codepen started as an example to help illustrate what I'm trying to achieve, but unfortunately it currently does no amount of scrolling or resizing: https://codepen.io/joeysilva/pen/wvmPqLK. It has both a small-large and a large-large case.
.flex-container {
height: 100px;
width: 100px;
display: flex;
flex-direction: column;
display: inline-block;
overflow: hidden;
}
.child {
flex: 50%;
overflow: auto;
}
.small {
background: red;
height: 30px;
}
.large {
background: blue;
height: 110px;
}
<div class="flex-container">
<div class="child">
<div class="small">Small</div>
</div>
<div class="child">
<div class="large">Large</div>
</div>
</div>
<div class="flex-container">
<div class="child">
<div class="large">Large 1</div>
<div class="large">Large 2</div>
</div>
</div>
Note 1: Not use disply:inline-block and display:flex the same time. Simply add another wrapper to show elements inside a row or column.
Note 2: flex: 50%; is equivalent to flex: 1 1 50%; and this is the shorthand form of flex-grow: 1; flex-shrink: 1; flex-basis: 50%;. Here in your code no need to use them because you have strictly defined the height of elements and also the basis of 50% height is wrong since you'd like the small element to use exactly the space it needs; no grow & no shrink, so it should be omitted.
.wrapper {
display: flex;
flex-direction: row;
}
.flex-container {
height: 100px;
width: 100px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.child {
overflow: auto;
}
.small {
background: red;
height: 30px;
}
.large {
background: blue;
height: 110px;
}
<div class="wrapper">
<div class="flex-container">
<div class="child">
<div class="small">Small</div>
</div>
<div class="child">
<div class="large">Large</div>
</div>
</div>
<div class="flex-container">
<div class="child">
<div class="large">Large 1</div>
</div>
<div class="child">
<div class="large">Large 2</div>
</div>
</div>
</div>

How to fix reducing the width of the left div element when increasing the size of the right div's child elements?

I arranged the following UI as left, right panels using flex box.
the right panel element's child elements are arranged vertically using white-space: nowrap; css property.
when I increasing the right panel child elements ("comps") widths, the left panel width is reduced instead of showing a vertical scroll bar in the right panel.
how can I fix this?
(added two buttons for increase the child element width ans reset)
code pen snippet
$(function(){
$('#inc-width').click(function(){
$('#inner-div').width($('#inner-div').width() * 2);
});
$('#reset-width').click(function () {
$('#inner-div').width(1000);
})
})
.parent {
display: flex;
flex-direction: row;
}
.left {
width: 20em;
height: 40em;
border: 1px solid;
}
.right {
flex: 1;
display: flex;
flex-direction: column;
}
.inner-wrap {
white-space: nowrap;
padding: 10px 0;
background: green;
width: 100%;
flex: 1;
height: 100%;
overflow: auto;
}
.inner {
display: inline-block;
width: 1000px;
height: 250px;
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<button id="inc-width">Increase child element width</button>
<button id="reset-width">RESET child element width</button>
</div>
<div class="parent">
<div class="left">
LEFT PANAL
</div>
<div class="right">
<div style="flex: 1;">
<div class="inner-wrap">
<div class="inner" id="inner-div"></div>
<!-- <div class="inner"></div>
<div class="inner"></div> -->
</div>
</div>
</div>
</div>
You could use flex-basis with a specific width and you can do other container flex-basis auto.
https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis

Why is my first div outside of the window?

I'm just trying the FlexLayout for different screen sizes.
The 3 boxes/divs below should be side to side on a large display, if it shrinks they should be above each other. But my top div is outside of my window and I don't want that.. How can I fix that?
<div class="container" fxLayout="row" fxLayout.lt-md="column" fxLayoutAlign="space-around center">
<div class="asd" [style.background-color]="'black'"></div>
<div class="asd" [style.background-color]="'green'"></div>
<div class="asd" [style.background-color]="'blue'"></div>
</div>
.asd {
min-height: 500px;
min-width: 400px;
}
.container {
height: 100%;
}
Flex elements won't stack unless you use flex-wrap: wrap along with a min-width or flex-basis declaration.
Basically, if the number of flex elements in the row would need to be smaller than their min-width they'll wrap to the next line.
.flexContainer {
display:flex;
max-width: 80%;
margin: 20px;
justify-content: space-between;
flex-wrap: wrap;
}
.flexItem {
background: #dddddd;
padding: 20px;
min-width: 200px;
margin: 0 10px 10px 0;
}
<div class="flexContainer">
<div class="flexItem">Flex</div>
<div class="flexItem">Flex</div>
<div class="flexItem">Flex</div>
<div class="flexItem">Flex</div>
</div>

Control width of flex items arranged vertically in a flex container

I'm trying to achieve the effect where the boxes labeled "HALF", take up only 50% of the width (aka they share the first row evenly).
The base requirement is that they remain in a single container. Is this possible to achieve using flexbox?
I've tried playing around with flex-grow, flex-shrink, and flex-basis but I'm afraid I'm not understanding how to make it work, or if it's even possible, given the single container requirement.
Consider this fiddle: http://jsfiddle.net/GyXxT/270/
div {
border: 1px solid;
}
.container {
width: 400px;
display: flex;
flex-direction: column;
}
.child {
height: 200px;
}
.child.half {
flex: 1 1 10em;
color: green;
}
.child:not(.half) {
flex-shrink: 2;
flex-basis: 50%;
color: purple;
}
<div class="container">
<div class="child half">
HALF
</div>
<div class="child half">
HALF
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
</div>
Instead of flex-direction: column, you can try a wrapping flexbox using flex-wrap: wrap; and you can set:
flex-basis: 50% for the half width divs
flex-basis: 100% for the full width divs
See that I have thrown in box-sizing: border-box to adjust for the widths when using flex-basis.
See demo below:
div {
border: 1px solid;
box-sizing: border-box;
}
.container {
width: 400px;
display: flex;
flex-wrap: wrap;
}
.child {
height: 200px;
}
.child.half {
flex-basis: 50%;
color: green;
}
.child:not(.half) {
flex-basis: 100%;
color: purple;
}
<div class="container">
<div class="child half">
HALF
</div>
<div class="child half">
HALF
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
</div>
The flex sizing properties -- flex-grow, flex-shrink, flex-basis and flex -- work only along the main axis of the flex container.
Since your container is flex-direction: column, the main axis is vertical, and these properties are controlling height, not width.
For sizing flex items horizontally in a column-direction container you'll need the width property.
(Here's a more detailed explanation: What are the differences between flex-basis and width?)
To achieve your layout with a single container, see another answer to this question.
If you want to stay in column-direction, you'll need to wrap the .half elements in their own container.
.container {
display: flex;
flex-direction: column;
width: 400px;
}
.container > div:first-child {
display: flex;
}
.child.half {
flex: 1 1 10em;
color: green;
width: 50%;
}
.child {
height: 200px;
width: 100%;
border: 1px solid;
}
* {
box-sizing: border-box;
}
<div class="container">
<div><!-- nested flex container for half elements -->
<div class="child half">HALF</div>
<div class="child half">HALF</div>
</div>
<div class="child">FULL</div>
<div class="child">FULL</div>
<div class="child">FULL</div>
<div class="child">FULL</div>
</div>
The base requirement is that they remain in a single container.
That can also be done without flexbox, by simply float the 2 half elements
div {
border: 1px solid;
box-sizing: border-box;
}
.container {
width: 400px;
}
.child {
height: 200px;
}
.child.half {
float: left;
width: 50%;
color: green;
}
.child:not(.half) {
width: 100%;
color: purple;
}
<div class="container">
<div class="child half">
HALF
</div>
<div class="child half">
HALF
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
</div>
If the purpose is to hardcode the size in CSS units, or in percentages (which was mentioned the question), #kukkuz's solution is good as it is.
If you want to size element widths according to their own individual contents, then align-tems: flex-start or similar could do the job. It's possible to deal with the dimension perpendicular to that of the flex layout itself. See a tester on the bottom of the doc page
(Old question, but previous answers were incomplete, some are misleading)

How to make a flexbox container to scroll?

I have a vertical flexbox container on which I set a specific height and set it to scroll vertically when overflows. The problem is that the flex container won't scroll if its content overflows. Here is a plunker that demonstrate what i'm talking about: http://plnkr.co/edit/3t4cuxMSGuNr88u0Whdl?p=preview.
.flex-container {
display: flex;
flex-direction: column;
overflow-y: scroll;
height: 600px;
width: 400px;
}
.block-container {
overflow-y: scroll;
height: 600px;
width: 400px;
margin-left: 50px;
}
.item1 {
height: 200px;
background-color: red;
margin-bottom: 1px;
}
.item2 {
height: 200px;
background-color: green;
margin-bottom: 1px;
}
.item3 {
height: 200px;
background-color: blue;
margin-bottom: 1px;
}
<div style="display: flex">
<div class="flex-container">
<p>Flex Container</p>
<div class="item1">Text</div>
<div class="item2">Text</div>
<div class="item3">Text</div>
<div class="item1">Text</div>
<div class="item2">Text</div>
<div class="item3">Text</div>
<div class="item1">Text</div>
<div class="item2">Text</div>
<div class="item3">Text</div>
</div>
<div class="block-container">
<p>Block Container</p>
<div class="item1">Text</div>
<div class="item2">Text</div>
<div class="item3">Text</div>
<div class="item1">Text</div>
<div class="item2">Text</div>
<div class="item3">Text</div>
<div class="item1">Text</div>
<div class="item2">Text</div>
<div class="item3">Text</div>
</div>
</div>
As you can see, I have there two identical boxes - the first one is a flex-box (display: flex) and the other one is a block-box (display: block). I set the height for both of them, but the flexbox will shrink its items to fit its contents inside the height boundaries, while the block-box will just scroll. How can I force the flexbox not to shrink its items and to behave like the block-box in that sense?
Thanks.
Try, set a flex-basis value, and make it to not grow or shrink:
.item1, .item2, .item3 {
flex: 0 0 200px;
}
Or, flex: 1 0 200px; if you do need them to grow as needed.
jsFiddle
You can always provide min-height and flex will respect that. See the updated Plunkr
http://plnkr.co/edit/7rgo7BpWWtXsQqYbJvdU?p=preview