I'm building a panel where I have a right menu area with some command buttons, scrolled vertically, and a main left area covering the remaining space, scrolled horizontally.
Repair that items must be full available height (up to 100% of the viewport).
In the example code, left area flex item is is "pushing" the right side to move to right... I'm also not getting the scrollbars to appear correctly.
Below the result I'm looking for:
Here is my template code:
.panel-container {
width: 100%;
height: 100vh;
display: flex;
flex-direction: row;
padding: 0px;
}
.panel-container-left {
flex-grow: 1;
flex-shrink: 0;
background-color: grey;
display: flex;
flex-direction: column;
}
.panel-container-right {
margin-left: 3px;
background-color: green;
}
.panel-right-data {
display: flex;
flex-direction: column;
overflow-y: scroll;
}
.panel-right-data-item {
background-color: green;
color: white;
padding: 5px;
margin: 2px;
width: 20px;
}
.panel-left-data {
display: flex;
flex-direction: row;
overflow-x: scroll;
}
.panel-left-data-item {
background-color: blue;
color: white;
padding: 5px;
margin: 2px;
width: 80px;
height: 100%;
}
<div class="panel-container">
<div class="panel-container-left">
<div>LEFT AREA</div>
<div class="panel-left-data">
<div class="panel-left-data-item">
ITEM 1
</div>
<div class="panel-left-data-item">
ITEM 2
</div>
<div class="panel-left-data-item">
ITEM 3
</div>
<div class="panel-left-data-item">
ITEM 4
</div>
<div class="panel-left-data-item">
ITEM 5
</div>
</div>
</div>
<div class="panel-container-right">
<div>RIGHT AREA</div>
<div class="panel-right-data">
<div class="panel-right-data-item">
COMMAND 1
</div>
<div class="panel-right-data-item">
COMMAND 2
</div>
<div class="panel-right-data-item">
COMMAND 3
</div>
<div class="panel-right-data-item">
COMMAND 4
</div>
<div class="panel-right-data-item">
COMMAND 5
</div>
<div class="panel-right-data-item">
COMMAND 6
</div>
<div class="panel-right-data-item">
COMMAND 7
</div>
<div class="panel-right-data-item">
COMMAND 8
</div>
<div class="panel-right-data-item">
COMMAND 9
</div>
</div>
</div>
</div>
For the height : height: 100%; only work when the immediat parent height is defined. So you have to add a specific height size to .panel-left-data, it can be 100% but in turn you have to add a specific height to it's parent node .panel-container-left, it also can be 100% and since .panel-container does have a height defined (100vh), all is good !
For the rest, I commented directly some adjustements I made, there may be better solutions for some of them but it work.
In practice :
.panel-container {
width: 100%;
height: 100vh;
display: flex;
flex-direction: row;
padding: 0px;
}
.panel-container-left {
flex-grow: 1;
flex-shrink: 0;
background-color: grey;
display: flex;
flex-direction: column;
height: 100%; /*added a height*/
overflow-x: scroll; /*moved the scroll here*/
overflow-y:hidden; /*just to be sure*/
}
.panel-container-right {
margin-left: 3px;
background-color: green;
position:absolute; /*added a position absolute*/
right:0px; /*the position let me use the right/left/top/bottom positionning*/
z-index:10; /*let me put this element on top of those with lower z-index*/
width:200px; /*and a width to make it good-looking*/
/*moved the scroll here with some height to restrict it*/
height: calc( 100% - 17px );
overflow-y:scroll;
}
.panel-right-data {
display: flex;
flex-direction: column;
/*overflow-y: scroll; moved on the parent element*/
}
.panel-right-data-item {
background-color: green;
color: white;
padding: 5px;
margin: 2px;
width: 20px;
}
.panel-left-data {
display: flex;
flex-direction: row;
/*overflow-x: scroll; moved on the parent element*/
height: calc( 100% - 40px ); /*added a height, cut it a little to account for the scrollbar and your example*/
}
.panel-left-data-item {
background-color: blue;
color: white;
padding: 5px;
margin: 2px;
width: 80px;
height: 100%;
}
<div class="panel-container">
<div class="panel-container-left">
<div>LEFT AREA</div>
<div class="panel-left-data">
<div class="panel-left-data-item">
ITEM 1
</div>
<div class="panel-left-data-item">
ITEM 2
</div>
<div class="panel-left-data-item">
ITEM 3
</div>
<div class="panel-left-data-item">
ITEM 4
</div>
<div class="panel-left-data-item">
ITEM 5
</div>
</div>
</div>
<div class="panel-container-right">
<div>RIGHT AREA</div>
<div class="panel-right-data">
<div class="panel-right-data-item">
COMMAND 1
</div>
<div class="panel-right-data-item">
COMMAND 2
</div>
<div class="panel-right-data-item">
COMMAND 3
</div>
<div class="panel-right-data-item">
COMMAND 4
</div>
<div class="panel-right-data-item">
COMMAND 5
</div>
<div class="panel-right-data-item">
COMMAND 6
</div>
<div class="panel-right-data-item">
COMMAND 7
</div>
<div class="panel-right-data-item">
COMMAND 8
</div>
<div class="panel-right-data-item">
COMMAND 9
</div>
</div>
</div>
</div>
Looking over the code, you seem to be missing a lot of align-items, justify-content, and flex properties. Also make sure you are using class="" and not className="" in your html unless you are working in JSX. Here's some code that is a little closer to what you seem to want.
.panel-container {
height: 100vh;
display: flex;
flex-direction: row;
justify-content: space-between; /* Added */
align-items: stretch; /* Added */
padding: 0px;
}
.panel-container-left {
flex: 1 1 auto; /* Replace flex-grow flex-shrink*/
background-color: grey;
display: flex;
flex-direction: column;
justify-content: stretch; /* Added */
max-width: calc(100vw - 200px); /* Added - For Horizontal scrolling */
}
.panel-container-right {
margin-left: 3px;
background-color: green;
flex: 0 0 200px; /* Added */
align-items: space-between; /* Added */
justify-content: stretch; /* Added */
display: flex; /* Added */
flex-direction: column; /* Added */
}
.panel-container-right>div:first-child {
flex: 0 0 30px; /* Added */
}
.panel-right-data {
display: flex;
flex: 1 1 80%; /* Added */
flex-direction: column;
overflow-y: scroll;
}
.panel-right-data-item {
background-color: green;
color: white;
padding: 5px;
margin: 2px;
width: 20px;
}
/* Added */
.panel-container-left > div:first-child {
flex: 0 0 30px;
}
.panel-left-data {
flex: 1 1 80%; /* Added */
display: flex;
flex-direction: row;
overflow-x: scroll;
align-items: stretch; /* Added */
justify-content: flex-start; /* Added */
}
.panel-left-data-item {
background-color: blue;
color: white;
padding: 5px;
margin: 2px;
width: 80px;
}
And here's a fiddle: https://jsfiddle.net/wfL8q051/21/
Related
I have a list of messages (which is a flex child) in a container with unknown height and want to make them scrollable. But I cannot find a proper combination of flex-grow: 1, min-height: 0 and other flex tricks to make it working - message list is still bigger than its parent.
When I add overflow-y: auto to its parent - it works but this parent besides messages list includes some content which should not scroll.
Here's my example for this case: https://jsfiddle.net/ecbtrn58/2/
<div class="page">
<div class="messages-section">
<div class="header">Your messages</div>
<div class="content">
<img src="https://http.cat/100" width="70" height="50"/>
<div class="messages-list">
<div class="message">Hi.</div>
<div class="message">Hello.</div>
<div class="message">Good morning.</div>
<div class="message">Yo!</div>
</div>
</div>
</div>
</div>
.page {
background-color: #ddd;
width: 300px;
height: 300px;
.messages-section {
display: flex;
flex-direction: column;
width: 50%;
height: 100%;
background-color: #ccc;
.header {
background: #bbb;
padding: 5px;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
padding: 5px;
.messages-list {
display: flex;
flex-direction: column;
overflow-y: auto;
/* What to add here to make it scrollable? */
.message {
height: 50px;
margin: 10px;
padding: 10px;
background: #1dc497;
}
}
}
}
}
How can I make messages list to scroll?
You have to set the height of .content to 100% and make it scrollable:
.page {
background-color: #ddd;
width: 300px;
height: 300px;
}
.page .messages-section {
display: flex;
flex-direction: column;
width: 50%;
height: 100%;
background-color: #ccc;
}
.page .messages-section .header {
background: #bbb;
padding: 5px;
}
.page .messages-section .content {
display: flex;
flex-direction: column;
align-items: center;
padding: 5px;
height: 100%;
overflow-x: scroll;
}
.page .messages-section .content .messages-list {
display: flex;
flex-direction: column;
overflow-y: auto;
/* What to add here to make it scrollable? */
}
.page .messages-section .content .messages-list .message {
height: 50px;
margin: 10px;
padding: 10px;
background: #1dc497;
}
<div class="page">
<div class="messages-section">
<div class="header">Your messages</div>
<div class="content">
<img src="https://http.cat/100" width="70" height="50" />
<div class="messages-list">
<div class="message">Hi.</div>
<div class="message">Hello.</div>
<div class="message">Good morning.</div>
<div class="message">Yo!</div>
</div>
</div>
</div>
</div>
I am trying to create a scrollable file tree. Minimal code can be found below.
https://jsfiddle.net/3kLmchot/1/
Problem is when I try to add overflow-y: scroll;, to the filebrowse-outer div, the first few items are not visible at all. This problem gets worse when I add more divs.
It seems like items are added about the center of the filebrowse-outer div, so the items that are added at the bottom can be found via scrolling, but the items that are added at the top are invisible. (see the visual aid below)
item 1
item 2
center of the div
item 3
item 4
Scroll bar forms at around item 2, which makes item 1 invisible. Does anyone know why this is happening, and potential solutions?
I got it to work with the following styles, specifically removing justify-content: center; from your .flex-container that is being used by multiple divs and only applying it to the one that is for .flex-container.filebrowse-inner
.side-bar {
position: fixed;
width: 20%;
height: 200px;
display: flex;
flex-direction: column;
}
.flex-container {
display: flex;
/* justify-content: center; <-- THIS LINE IS CAUSING THE ISSUE */
align-items: center;
}
.flex-container.filebrowse-outer {
flex-direction: column;
border: 1px solid #f00;
overflow-y: scroll;
align-items: stretch;
}
.flex-container.filebrowse-inner {
flex-direction: row;
justify-content: center;
width: 100%;
padding-bottom: 15px;
text-align: left;
position: relative;
}
/* .display-container {
width: 70%;
overflow: auto;
} */
I think that you meant to have scroll bar in the external div with class 'side-bar', if yes:
.side-bar {
position: fixed;
width: 20%;
height: 200px;
display: flex;
flex-direction: column;
overflow-y:scroll;
}
.flex-container {
display: flex;
justify-content: center;
align-items: center;
}
.flex-container.filebrowse-outer {
flex-direction: column;
border: solid;
min-height: max-content; /* For safari*/
/* overflow-y: scroll; */
align-items: stretch;
}
.flex-container.filebrowse-inner {
flex-direction: row;
width: 100%;
min-height: max-content; /* For safari*/
padding-bottom: 15px;
text-align: left;
position: relative;
}
.display-container {
width: 70%;
overflow: auto;
}
<div class="side-bar">
<div class="flex-container filebrowse-outer">
<div class="flex-container filebrowse-inner">
<div class="display">
<p>Click Me 1!</p>
</div>
</div>
<div class="flex-container filebrowse-inner">
<div class="display">
<p>Click Me 2!</p>
</div>
</div>
<div class="flex-container filebrowse-inner">
<div class="display">
<p>Click Me 3!</p>
</div>
</div>
<div class="flex-container filebrowse-inner">
<div class="display">
<p>Click Me 4!</p>
</div>
</div>
</div>
</div>
You can then move the border to 'side-bar' class.
How do I stretch the divs with a yellow background to full height? It should cover up the green but it is not working. I tried adding height: 100% on it but then it adds up the height from the search bar?
https://jsfiddle.net/nuy20j1h/
.block {
width: 80%;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
.sidebar {
height: 600px;
width: 25%;
background: red;
}
.home {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
width: 75%;
background: green;
}
.search-bar {
width: 100%;
padding: 25px;
background: blue;
}
.content-wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
align-items: flex-stretch;
}
.content,
.single {
width: 50%;
background: yellow;
}
<div class="block">
<div class="sidebar">sidebar</div>
<div class="home">
<div class="search-bar">search bar</div>
<div class="content-wrap">
<div class="content">lorem ipsum</div>
<div class="single">test</div>
</div>
</div>
</div>
First you should add a style reset, I'm using this now * {} as you can se below. The trick here is to run flex-direction: column; on .home and you can tell .content-wrap to take up the rest of that space after the search with flex-grow: 1;
box-sizing: border-box; is, if you add let's say width: 200px; to a element, and add padding: 20px;, the element will stay 200px with the padding included. If you don't have that, it will take up 200px + 40px.
if you want the fiddle, here it is
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.block {
width: 80%;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
.sidebar {
height: 600px;
width: 25%;
background: red;
}
.home {
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-items: flex-start;
width: 75%;
background: green;
}
.search-bar {
width: 100%;
padding: 25px;
background: blue;
}
.content-wrap {
display: flex;
flex-grow: 1;
flex-wrap: wrap;
width: 100%;
align-items: flex-stretch;
}
.content,
.single {
width: 50%;
background: yellow;
}
<div class="block">
<div class="sidebar">sidebar</div>
<div class="home">
<div class="search-bar">search bar</div>
<div class="content-wrap">
<div class="content">lorem ipsum</div>
<div class="single">test</div>
</div>
</div>
</div>
As mentioned in other answers, there is one main issue here:
flex-direction: column;, which I added to home, to enable the usage of flex properties instead of height, to make the .content-wrap fill the available space left in home
That will make the .search-bar and .content-wrap stack vertical, and enable the use of flex: 1 on .content-wrap, which will make it fill the remaining space/height.
So even if you got answers already, and since there are some properties with wrong value, or not needed, I decided to post an answer to clarify the changes made.
See my notes made in the CSS for further clarifications and what I changed.
Stack snippet
.block {
width: 80%;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
.sidebar {
height: 600px;
width: 25%;
background: red;
}
.home {
display: flex;
flex-direction: column; /* added */
/*flex-wrap: wrap; removed, not needed */
/*align-items: flex-start; removed, items should fill parent's,
in this changed case, width */
width: 75%;
background: green;
}
.search-bar {
/*width: 100%; not needed, default for column
item is to fill parent width as
its "align-items" is "stretch" */
padding: 25px;
background: blue;
}
.content-wrap {
flex: 1; /* added, take the remaining space left
left of its parent (height in this case) */
display: flex;
flex-wrap: wrap;
/*width: 100%; not needed, default for column
item is to fill parent width as
its "align-items" is "stretch" */
/*align-items: flex-stretch; wrong value, should be "stretch",
though since that is the default,
it is not needed */
}
.content,
.single {
width: 50%;
background: yellow;
}
<div class="block">
<div class="sidebar">sidebar</div>
<div class="home">
<div class="search-bar">search bar</div>
<div class="content-wrap">
<div class="content">lorem ipsum</div>
<div class="single">test</div>
</div>
</div>
</div>
flex-direction: column; is your friend. Here is a reworked fiddle of your code: https://jsfiddle.net/vsjktmms/1/
Using the same HTML structure you provided:
.block {
display: flex;
width: 80%;
margin: 0 auto;
background-color: gray;
align-items: stretch;
}
.sidebar {
width: 25%;
height: 600px;
background-color: red;
}
.home {
display: flex;
flex-direction: column;
align-items: stretch;
width: 75%;
background-color: green;
}
.search-bar {
padding: 25px;
background-color: blue;
}
.content-wrap {
flex: 1 1 auto;
display: flex;
flex-wrap: wrap;
width: 100%;
background-color: pink;
}
.content,
.single {
width: 50%;
background: yellow;
}
Consider the following fiddle: https://jsfiddle.net/7naxprzd/1/
Requirements are:
two columns with header and contents
tops of columns should align
bottom of columns should align
on top of each column there should be a horizontally centered arrow
The code is working properly if the arrows are eliminated by deleting the div with class .arrow-wrapper, but I need the arrows.
A solution could be to absolute position the arrow, but is there a way to solve this layout issue with flex without absolute positioning the arrow?
Should work for modern browsers and IE11.
.row-wrapper {
display: flex;
}
.col-wrapper-outer {
display: flex;
flex-wrap: wrap;
}
.arrow-wrapper {
width: 100%;
text-align: center;
font-size: 30px;
}
.col-wrapper {
width: 100%;
display: flex;
flex-direction: column;
border: 2px solid red;
color: white;
}
.col-wrapper .header {
background: blue;
}
.col-wrapper .contents {
flex: 1 0 auto;
background: green;
}
<div class="row-wrapper">
<div class="col-wrapper-outer">
<div class="arrow-wrapper">
↓
</div>
<div class="col-wrapper">
<div class="header">Please align tops.</div>
<div class="contents">Let me grow.</div>
</div>
</div>
<div class="col-wrapper-outer">
<div class="arrow-wrapper">
↓
</div>
<div class="col-wrapper">
<div class="header">please align tops.</div>
<div class="contents">Let me grow.<br>Please<br>align<br>bottoms.</div>
</div>
</div>
</div>
In your div with class col-wrapper-outer, instead of this:
.col-wrapper-outer {
display: flex;
flex-wrap: wrap;
}
Use this:
.col-wrapper-outer {
display: flex;
flex-direction: column;
}
Then add flex: 1 to .col-wrapper so it takes the full height of the container.
revised fiddle
.row-wrapper {
display: flex;
}
.col-wrapper-outer {
display: flex;
/* flex-wrap: wrap; */
flex-direction: column; /* NEW */
}
.arrow-wrapper {
width: 100%;
text-align: center;
font-size: 30px;
}
.col-wrapper {
flex: 1; /* NEW */
width: 100%;
display: flex;
flex-direction: column;
border: 2px solid red;
color: white;
}
.col-wrapper .header {
background: blue;
}
.col-wrapper .contents {
flex: 1 0 auto;
background: green;
}
<div class="row-wrapper">
<div class="col-wrapper-outer">
<div class="arrow-wrapper">
↓
</div>
<div class="col-wrapper">
<div class="header">Please align tops.</div>
<div class="contents">Let me grow.</div>
</div>
</div>
<div class="col-wrapper-outer">
<div class="arrow-wrapper">
↓
</div>
<div class="col-wrapper">
<div class="header">please align tops.</div>
<div class="contents">Let me grow.
<br>Please
<br>align
<br>bottoms.</div>
</div>
</div>
</div>
I'm trying to create a visual layout using Flexbox.
In this layout, controls are arranged in rows. Some of the rows will have a predefined height, and some of the rows will be anchored to both the top and bottom of the screen, which means they'll stretch their height to occupy all available space.
I've got a working layout that will achieve this, but there seems to be an issue when the rows with predefined height need stretch because their contents no longer fit. They seem to not actually be stretching, which causes them to overlap with one another.
Anyone know how to get the rows to resize in height, properly?
You can have a look at the current status here:
https://jsfiddle.net/cgledezma1101/o9zwa7na/
I'm using the following CSS for my containers:
.main-container {
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
height: 100vh;
}
.row {
flex: 1 1 auto;
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
width: 100%;
}
.row2 {
height: 200px;
min-height: 200px;
}
.row1 {
height: 100px;
min-height: 100px;
}
.not-anchored {
height: 100px;
}
.anchored {
height: 100%;
}
A fixed height on the container means it cannot expand to accommodate a taller layout. Hence, flex items are forced to overlap on smaller screens.
Instead of height: 100vh, use min-height: 100vh.
Also, remove fixed heights on flex items. They override align-items: stretch.
revised fiddle
.main-container {
display: flex;
flex-flow: column nowrap;
min-height: 100vh;
}
.row {
display: flex;
flex-flow: row wrap;
}
.row.anchored { flex: 1; }
body { margin: 0; }
.item12 {
flex: 1 1 100px;
height: 200px;
min-width: 100px;
background: tomato;
}
.item21 {
flex: 1 1 200px;
height: 100px;
min-width: 100px;
background: deepskyblue;
}
.item {
text-align: center;
color: white;
font-weight: bold;
font-size: 3em;
border: 1px dashed black;
line-height: 100px;
margin-left: auto;
margin-right: auto;
}
.item.anchored {
flex: 1;
/* height: 100%; */
min-height: 150px;
background: hotpink;
}
<body>
<div class="main-container">
<div class="row row2 not-anchored">
<div class="item item12">
1.1
</div>
<div class="item item12">
1.2
</div>
<div class="item item12">
1.3
</div>
</div>
<div class="row anchored">
<div class="item anchored">
A.1
</div>
</div>
<div class="row row1 not-anchored">
<div class="item item21">
2.1
</div>
<div class="item item21">
2.2
</div>
</div>
<div class="row anchored">
<div class="item anchored">
A.2
</div>
</div>
</div>
</body>
It seems the issue arises from giving the .main-container element a height: 100vh;. Changing that to height: 100%; seems to fix it.
.main-container {
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
height: 100%;
}
.main-container {
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
height: 100%;
}
.row {
flex: 1 1 auto;
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
width: 100%;
}
.row2 {
height: 200px;
min-height: 200px;
}
.row1 {
height: 100px;
min-height: 100px;
}
.not-anchored {
height: 100px;
}
.anchored {
height: 100%;
}
.item12 {
flex: 1 1 100px;
height: 200px;
min-width: 100px;
background: tomato;
}
.item21 {
flex: 1 1 200px;
height: 100px;
min-width: 100px;
background: deepskyblue;
}
.item {
text-align: center;
color: white;
font-weight: bold;
font-size: 3em;
border: 1px dashed black;
line-height: 100px;
margin-left: auto;
margin-right: auto;
}
.item.anchored {
flex: 1 1 100%;
height: 100%;
min-height: 150px;
background: hotpink;
}
<body>
<div class="main-container">
<div class="row row2 not-anchored">
<div class="item item12">
1.1
</div>
<div class="item item12">
1.2
</div>
<div class="item item12">
1.3
</div>
</div>
<div class="row anchored">
<div class="item anchored">
A.1
</div>
</div>
<div class="row row1 not-anchored">
<div class="item item21">
2.1
</div>
<div class="item item21">
2.2
</div>
</div>
<div class="row anchored">
<div class="item anchored">
A.2
</div>
</div>
</div>
</body>
The following produces: