This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 2 years ago.
I want to make a website with a list using bootstrap + css's flexbox, where the item list should have a height up to the screen's bottom not overflowing it.
I was able to get a working solution like this:
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
}
body {
background-color: black;
}
.wrapper .content-wrapper .content {
flex: 1 1 1px;
}
.wrapper .content-wrapper .content {
display: flex;
flex-direction: column;
}
.wrapper .content-wrapper {
width: 100%;
}
.wrapper {
display: flex;
height: 100%;
}
.side {
background-color: blue;
display: flex;
flex-direction: column;
width: 224px;
}
.content-wrapper {
display: flex;
flex-direction: column;
}
.topbar {
height: 100px;
background-color: aqua;
}
.main {
flex: 1 1 1px;
background-color: pink;
overflow-y: scroll;
}
.item {
background-color: white;
border-style: solid;
height: 200px;
}
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="wrapper">
<div class="side"></div>
<div class="content-wrapper">
<div class="content">
<div class="topbar"></div>
<div class="main">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
</div>
</div>
</div>
</div>
</body>
</html>
With the help from this link:
Prevent flex item from exceeding parent height and make scroll bar work
As you can see the scroll bar's bottom arrow is at the end of the screen. (Expected behaviour)
However, when I try to expand my main div into 2 more columns (using bootstrap + flex):
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
}
body {
background-color: black;
}
.wrapper .content-wrapper .content {
flex: 1 1 1px;
}
.wrapper .content-wrapper .content {
display: flex;
flex-direction: column;
}
.wrapper .content-wrapper {
width: 100%;
}
.wrapper {
display: flex;
height: 100%;
}
.side {
background-color: blue;
display: flex;
flex-direction: column;
width: 224px;
}
.content-wrapper {
display: flex;
flex-direction: column;
}
.topbar {
height: 100px;
background-color: aqua;
}
.main {
flex: 1 1 1px;
background-color: pink;
display: flex;
}
.header {
background-color: yellow;
overflow-y: scroll;
height: 100%;
}
.details {
background-color: crimson;
}
.item {
background-color: white;
border-style: solid;
height: 200px;
}
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="wrapper">
<div class="side"></div>
<div class="content-wrapper">
<div class="content">
<div class="topbar"></div>
<div class="main">
<div class="header col-lg-4">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
</div>
<div class="details col-lg-8"></div>
</div>
</div>
</div>
</div>
</body>
</html>
Now the item list overflow below the bottom of the screen. (see the bottom arrow of the scrollbar is missing)
Any help would be appreciated.
You have a couple of fixed lengths in your code, including:
.side {
width: 224px;
}
.topbar {
height: 100px;
}
These hard limits make the solution to overflow problems relatively simple, since the easiest way to trigger a scrollbar is to create an overflow condition, which is best accomplished with a fixed length.
In this case, the .topbar { height: 100px } is the key to the scrollbar on the sibling element.
(Note that you need to disable flex-shrink on these lengths for the values to always be respected.)
Here's a revised version of your code, with various adjustments for greater performance and efficiency.
body {
margin: 0;
background-color: black;
}
.wrapper {
display: flex;
height: 100vh;
}
.side {
/* width: 224px; */ /* will not be respected without adding `flex-shrink: 0` */
flex: 0 0 224px; /* new; flex-grow, flex-shrink, flex-basis */
background-color: blue;
display: flex;
flex-direction: column;
}
.content-wrapper {
flex: 1; /* consume remaining space */
display: flex;
flex-direction: column;
}
.wrapper .content-wrapper .content {
display: flex;
flex-direction: column;
}
.topbar {
flex: 0 0 100px;
/* height: 100px; */
background-color: aqua;
}
.main {
height: calc(100vh - 100px); /* new; sets overflow condition */
background-color: pink;
display: flex;
}
.header {
background-color: yellow;
overflow-y: scroll;
/* height: 100%; */
}
.details {
background-color: crimson;
}
.item {
background-color: white;
border-style: solid;
height: 200px; /* not a flex item, so no need to disable flex-shrink */
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"/>
<div class="wrapper">
<div class="side"></div>
<div class="content-wrapper">
<div class="content">
<div class="topbar"></div>
<div class="main">
<div class="header col-lg-4">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
</div>
<div class="details col-lg-8"></div>
</div>
</div>
</div>
</div>
jsFiddle demo
Related
I want to have a container that doesn't exceed a certain height, with a 2 column layout: a large main section which sticks at the top while the user scrolls through the items in the sidebar. I tried setting a fixed height and overflow onto the container but this has broken the position: sticky. Is this possible without having lots of space at the bottom, when there's lots of items in the sidebar? I would like for these items to not overflow the height of the container (i.e. the height of the column 1 section).
.container {
padding: 10px;
}
.header,
.footer {
display: flex;
align-items: center;
justify-content: center;
height: 120px;
background: #e1e1e1;
}
.wrapper {
display: flex;
padding: 15px 0;
max-height:400px;
overflow:scroll;
}
.col-1 {
flex: 1 0 auto;
}
.col-inner {
background: purple;
color: #fff;
height: 300px;
margin-right: 10px;
display: flex;
align-items: center;
justify-content: center;
}
.col-inner {
position: sticky;
position: -webkit-sticky;
top: 0;
}
.item {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 200px;
color: #fff;
background: blue;
margin-bottom:10px
}
<div class="container">
<header class="header">Header</header>
<div class="wrapper">
<div class="col-1">
<div class='col-inner'>Column 1</div>
</div>
<div class="col-2">
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
</div>
</div>
<footer class="footer">Footer</footer>
</div>
I think I understand what you're trying to accomplish. Hopefully this helps: I took your code as you listed above and added:
.col-2{
overflow-y: scroll;
height: 300px;
}
This allowed me to scroll on your col-2 element while maintaining a fixed height.
This is sort of a two in problem.
I have a body with height: 100vh similar to how my example is in the jsFiddle (except in there I put 20vh.
I have a similar structure as this, where the innerRight container can be quite large compared to the rest of the content, and only that conatiner is to obtain it's own scroll bar. I sort of got this working in my main project, but the outer container (similar to how I displayed outer in the example) still expands past the the parents height container main. Be it 100vh, or 20vh it doesn't matter it doesn't stay within with display:flex.
.main {
height: 20vh;
}
.outer {
display: flex;
overflow: hidden;
}
.innerLeft {
height: 200px;
width: 50px;
display: flex;
flex-direction: column;
flex-grow: 1;
background-color: green;
}
.innerRight {
overflow: auto;
height: 500px;
background-color: red;
width: 100%;
}
<div class="main">
<div class="header">
some random text
</div>
<div class="outer">
<div class="innerLeft">
</div>
<div class="innerRight">
</div>
</div>
</div>
Can you please check the below code? Hope it will work for you.
You have to set height:100vh; in .main and set width:calc(100% - 50px); to .innerRight.
Remove height from innerleft and innerright element.
Please refer to this link: https://jsfiddle.net/yudizsolutions/9Lsyzg64/1/
body {
margin: 0;
}
.main {
height: 100vh;
}
.outer {
display: flex;
height: calc(100vh - 19px);
overflow: hidden;
}
.innerLeft {
width: 50px;
background-color: green;
}
.innerRight {
overflow: auto;
background-color: red;
width: calc(100% - 50px);
}
<div class="main">
<div class="header">
some random text
</div>
<div class="outer">
<div class="innerLeft">
</div>
<div class="innerRight">
</div>
</div>
</div>
You need to set height to outer class.
.main {
height: 20vh;
}
.outer {
display: flex;
height: 200px;
overflow:hidden;
}
.innerLeft {
width: 50px;
display: flex;
flex-direction: column;
flex-grow: 1;
background-color: green;
}
.innerRight {
overflow: auto;
height: 500px;
background-color: red;
width:100%;
}
<div class="main">
<div class="header">
some random text
</div>
<div class="outer">
<div class="innerLeft">
</div>
<div class="innerRight">
</div>
</div>
</div>
I have a 2-cell flexbox with a fixed-height (mobile screen), and one cell stacked on top of the other. I need all of the content of the top-cell to be displayed.. the bottom-cell should yield as much space as possible to allow this. This part was easy.
.main-container {
height: 400px;
width: 200px;
display: flex;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background-color: lightgrey;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
... with that the content-container will grow as needed (in this example it's 100px) and the rest is taken up by the remaining-space cell.
What I need to do is fill the remaining-space cell with a circle that is as big as it can be, but doesn't force the remaining-space cell to grow in height/width... and I need to do it with just html/css.
The only way I've seen to enforce a 1:1 ratio (square/circle) is by using the padding-bottom trick where the padding is calculated using the element's width. This doesn't work for me because remaining-space cell might have a larger width than it's height.. which will cause the cell to grow in height. This is especially difficult in that the container is responsive so the actual width in pixels is never known.
A simple gradient can do it:
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background:
radial-gradient(circle closest-side, red 98%, transparent)
lightgrey;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
Clip-path can also do it:
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background: lightgrey;
}
.remaining-space>div {
height: 100%;
background: red;
clip-path: circle(closest-side)
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div></div>
</div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div></div>
</div>
</div>
Where you can also have content inside
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background: lightgrey;
}
.remaining-space>div {
height: 100%;
background: red;
clip-path: circle(closest-side);
display:flex;
align-items:center;
justify-content:center;
font-size:30px;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div> text </div>
</div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div> text </div>
</div>
</div>
I'm currently making a simple html page with two sections with content inside of each of them but the last content of the second div .right is going on the bottom of the page and make the page scrollable.
I tried making another div and put a flex-direction: column but it doesn't work:
body {
margin: 0;
}
.main-container {
display: flex;
flex-direction: column;
}
.left {
background: #ecece9;
width: 50%;
height: 100vh;
}
.right {
background: #ffffff;
width: 50%;
height: 100vh;
}
<div class="main-container">
<div class="left">
<h2>content</h2>
</div>
<div class="right">
<h2>content should be on top</h2>
</div>
</div>
How can I put two <div> that has the same width and height next to each other without having to scroll?
You need to use flex-direction: row and not flex-direction: column.
To avoid repeating width: 50%; height: 100vh; for both .left and .right, I would also create another class, such as .box, which is applied to both and contains these properties.
body {
margin: 0;
}
.main-container {
display: flex;
flex-direction: row;
}
.box {
width: 50%;
height: 100vh;
}
.left {
background: #ecece9;
}
.right {
background: #ffffff;
}
<div class="main-container">
<div class="left box">
<h2>content</h2>
</div>
<div class="right box">
<h2>content should be on top</h2>
</div>
</div>
Change the flex direction from column to row
body {
margin: 0;
}
.main-container {
display: flex;
flex-direction: row;
}
.left {
background: #ecece9;
width: 50%;
height: 100vh;
}
.right {
background: #ffffff;
width: 50%;
height: 100vh;
}
<div class="main-container">
<div class="left">
<h2>content</h2>
</div>
<div class="right">
<h2>content should be on top</h2>
</div>
</div>
Use CSS Grid to build Layouts it is very powerful. See I changed only two lines and the layout is ready.
.main-container {
display: grid;
grid-template-columns: 50% 50%
}
body {
margin: 0;
}
.main-container {
display: grid;
grid-template-columns: 50% 50%
}
.left {
background: #ecece9;
height: 100vh;
}
.right {
background: #ffffff;
height: 100vh;
}
<div class="main-container">
<div class="left">
<h2>content</h2>
</div>
<div class="right">
<h2>content should be on top</h2>
</div>
</div>
Try only display flex on large screen and and block on mobile
body {
margin: 0;
}
.main-container {
display: flex;
}
.left {
background: #ecece9;
width: 50%;
height: 100vh;
padding:20px;
}
.right {
background: #ddd;
width: 50%;
height: 100vh;
padding:20px;
}
/* For mobile screen
#media only screen and (max-width: 768px) {
.main-container{
display: block;
}
.left, .right{
width: 100%;
}
}
*/
<div class="main-container">
<div class="left">
<h2>content</h2>
</div>
<div class="right">
<h2>content should be on top</h2>
</div>
</div>
I have found the following links... but it still doesn't help me...
how to make nested flexboxes work
Height 100% on flexbox column child
How to make flexbox children 100% height of their parent?
I need a full page that is responsive, like the following image:
With header and footer and the middle 5 columns filling the height equally in the remaining space, and then when I do media queries, fill the screen of the mobile device like so:
Here's the code I have so far...
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style type="text/css">
html,
body {
height: 100%;
margin: 0
}
.box {
display: flex;
flex-flow: column;
height: 100%;
}
.box .row {
border: 1px dotted grey;
}
.box .row.header {
flex: 0 1 auto;
/* The above is shorthand for:
flex-grow: 0,
flex-shrink: 1,
flex-basis: auto
*/
}
.box .row.content {
flex: 1 1 auto;
}
.box .row.footer {
flex: 0 1 40px;
}
.yellow-back {
background: #ffe001;
}
.red-back {
background: #e31e25;
}
.green-back {
background: #66af45;
}
.purple-back {
background: #954294;
}
.containerFull { position: relative; width: 100%; margin: 0 auto; padding: 0;}
.containerFull .column,
.containerFull .columns { float: left; display: inline; margin-left: 0px; margin-right: 0px; }
.containerFull .one-fifth.column { width: 20%; }
</style>
</head>
<body>
<div class="box">
<div class="row header">
<p><b>header</b>
<br />
<br />(sized to content)</p>
</div>
<div class="row content">
<div class="containerFull">
<div class="one-fifth column green-back">Here</div>
<div class="one-fifth column red-back">Here</div>
<div class="one-fifth column">Here</div>
<div class="one-fifth column yellow-back">Here</div>
<div class="one-fifth column purple-back">Here</div>
</div><!-- ContainerFull -->
</div>
<div class="row footer">
<p><b>footer</b> (fixed height)</p>
</div>
</div>
</body>
</html>
html,
body {
height: 100%;
margin: 0
}
.box {
display: flex;
flex-flow: column;
height: 100%;
}
.box .row {
border: 1px dotted grey;
}
.box .row.header {
flex: 0 1 auto;
/* The above is shorthand for:
flex-grow: 0,
flex-shrink: 1,
flex-basis: auto
*/
}
.box .row.content {
flex: 1 1 auto;
}
.box .row.footer {
flex: 0 1 40px;
}
.yellow-back {
background: #ffe001;
}
.red-back {
background: #e31e25;
}
.green-back {
background: #66af45;
}
.purple-back {
background: #954294;
}
.containerFull {
position: relative;
width: 100%;
margin: 0 auto;
padding: 0;
}
.containerFull .column,
.containerFull .columns {
float: left;
display: inline;
margin-left: 0px;
margin-right: 0px;
}
.containerFull .one-fifth.column {
width: 20%;
}
<div class="box">
<div class="row header">
<p><b>header</b>
<br />
<br />(sized to content)</p>
</div>
<div class="row content">
<div class="containerFull">
<div class="one-fifth column green-back">Here</div>
<div class="one-fifth column red-back">Here</div>
<div class="one-fifth column">Here</div>
<div class="one-fifth column yellow-back">Here</div>
<div class="one-fifth column purple-back">Here</div>
</div>
<!-- ContainerFull -->
</div>
<div class="row footer">
<p><b>footer</b> (fixed height)</p>
</div>
</div>
In addition to Michael Coker's answer, if you go all the way with Flexbox, you can cut down both your markup and CSS quite much and get this amazing result.
I also included the background image and media query you commented/asked about just to show how simple this can be done.
Made some notes in the CSS. When it comes to the header and footer, you can give them a height if you want, but is not needed for this to work, so I left them out so one can see how Flexbox excel in distributing the content...wish I had this technique 20 years ago :)
html, body {
margin: 0;
}
.box {
display: flex;
flex-direction: column;
height: 100vh; /* instead of using 100% all over, use viewport units once */
background-size: cover;
background: black url(http://lorempixel.com/500/500/nature/4/) no-repeat center;
}
.box .row.content,
.content .one-fifth.column {
flex: 1; /* fill the space equal, no matter row or column direction */
display: flex;
}
.box .row.header,
.box .row.footer { color: white; }
.box .row.content { background: #fff; }
.yellow-back { background: #ffe001; }
.red-back { background: #e31e25; }
.green-back { background: #66af45; }
.purple-back { background: #954294; }
#media screen and (max-width: 600px) {
/* smaller screens */
.box .row.content {
flex-direction: column; /* by simply swap direction it work on smaller screen */
}
}
<div class="box">
<div class="row header">
<p><b>header</b><br /><br />(sized to content)</p>
</div>
<div class="row content">
<div class="one-fifth column green-back">Here</div>
<div class="one-fifth column red-back">Here</div>
<div class="one-fifth column">Here</div>
<div class="one-fifth column yellow-back">Here</div>
<div class="one-fifth column purple-back">Here</div>
</div>
<div class="row footer">
<p><b>footer</b> (fixed height)</p>
</div>
</div>
I would make the column section a flex layout, too. You can set .content and .containerFull to display: flex, then .containerFull will "stretch" to fill the height of .content, and then you can use flex-basis on the columns to control the width.
html,
body {
height: 100%;
margin: 0
}
.box {
display: flex;
flex-flow: column;
height: 100%;
}
.box .row {
border: 1px dotted grey;
}
.box .row.header {
flex: 0 1 auto;
/* The above is shorthand for:
flex-grow: 0,
flex-shrink: 1,
flex-basis: auto
*/
}
.box .row.content {
display: flex;
}
.box .row.content {
flex: 1 1 auto;
}
.containerFull {
display: flex;
}
.box .row.footer {
flex: 0 1 40px;
}
.yellow-back {
background: #ffe001;
}
.red-back {
background: #e31e25;
}
.green-back {
background: #66af45;
}
.purple-back {
background: #954294;
}
.containerFull {
position: relative;
width: 100%;
margin: 0 auto;
padding: 0;
}
.containerFull .column,
.containerFull .columns {
margin-left: 0px;
margin-right: 0px;
}
.containerFull .one-fifth.column {
flex-basis: 20%;
}
<div class="box">
<div class="row header">
<p><b>header</b>
<br />
<br />(sized to content)</p>
</div>
<div class="row content">
<div class="containerFull">
<div class="one-fifth column green-back">Here</div>
<div class="one-fifth column red-back">Here</div>
<div class="one-fifth column">Here</div>
<div class="one-fifth column yellow-back">Here</div>
<div class="one-fifth column purple-back">Here</div>
</div><!-- ContainerFull -->
</div>
<div class="row footer">
<p><b>footer</b> (fixed height)</p>
</div>
</div>