I'm trying to build two column layout using flexbox css. Page should consist of header, sidebar, content area and footer.
One of the requirement is for a page to consume whole browser window space but not overflow it. Overflow could, however, happen in separate sections (like in this case - sidebar).
So I've decided to use flexbox for layout, however can't figure out how to make sidebar scrollable if it's content is bigger than place given to it by the layout engine.
I've built an example to better explain my problem. When there is not too much content (content size is smaller than the container), everything looks as expected:
html,
body {
height: 100%;
margin: 0;
}
.block {
border: 1px solid grey;
}
.container {
display: flex;
flex-flow: column;
height: 100%;
}
.container > .header {
flex: 0 1 auto;
height: 65px;
}
.container > .content {
display: flex;
flex: 1 1 auto;
flex-direction: row;
}
.container > .content > .page {
flex: 1 1 auto;
}
.container > .content > .sidebar {
flex: 0 1 auto;
width: 250px;
overflow: scroll;
}
.container > .footer {
flex: 0 1 auto;
height: 150px;
}
<body>
<div class="container">
<div class="block header">
<p>
<b>Header</b>
</p>
</div>
<div class="content">
<div class="block sidebar">
<p>
<b>Sidebar</b>
</p>
</div>
<div class="block page">
<p>
<b>Content</b>
</p>
</div>
</div>
<div class="block footer">
<p>
<b>Footer</b>
</p>
</div>
</div>
</body>
But if, for example, sidebar's content size is bigger than the sidebar itself, the footer gets pushed down and it causes the whole page to overflow the browser window size:
html,
body {
height: 100%;
margin: 0;
}
.block {
border: 1px solid grey;
}
.container {
display: flex;
flex-flow: column;
height: 100%;
}
.container > .header {
flex: 0 1 auto;
height: 65px;
}
.container > .content {
display: flex;
flex: 1 1 auto;
flex-direction: row;
}
.container > .content > .page {
flex: 1 1 auto;
}
.container > .content > .sidebar {
flex: 0 1 auto;
width: 250px;
overflow: scroll;
}
.container > .footer {
flex: 0 1 auto;
height: 150px;
}
<body>
<div class="container">
<div class="block header">
<p>
<b>Header</b>
</p>
</div>
<div class="content">
<div class="block sidebar">
<p>
<b>Sidebar</b>
</p>
<div style="background-color: blue; height: 800px;"></div>
</div>
<div class="block page">
<p>
<b>Content</b>
</p>
</div>
</div>
<div class="block footer">
<p>
<b>Footer</b>
</p>
</div>
</div>
</body>
How I could fix this problem and force sidebar to add scrolling behaviour when content doesn't fit the container rather than expand the container?
Add overflow-y: auto;, this will solve your problem.
Related
Embedded scroll bars do not work within a simple flexbox container. The browser automatically displays the horizontal scroll bar.
What am I doing wrong on this simple example?
When I remove "display: flex;" on the flexContainer, the embedded scrollbar works. Of course, my entire layout is then destroyed.
I only found the following, but the solution relates to a vertical scrollbar and does not work here:
Stackoverflow nesting-flexbox-inside-flexbox-overflow-how-to-fix-this
.flexContainer {
display: flex;
}
.sidebar {
flex: 1 0 auto;
min-width: 150px;
max-width: 190px;
color: white;
background: blue;
}
.content {
flex: 1 0 auto;
background: green;
}
.scrollableElement {
display: flex;
overflow-x: scroll;
}
.textElement {
color: white;
background: grey;
}
<html>
<body>
<div class="flexContainer">
<div class="sidebar">
<div>Sidebar</div>
</div>
<div class="content">
<div class="scrollableElement">
<div class="textElement">
<div>Content11111111111111111111111111111111111111111111111111111111111111111111111</div>
<div>Content22222222222222222222222222222222222222222222222222222222222222222222222</div>
<div>Content33333333333333333333333333333333333333333333333333333333333333333333333</div>
<div>Content44444444444444444444444444444444444444444444444444444444444444444444444</div>
<div>Content55555555555555555555555555555555555555555555555555555555555555555555555</div>
<div>Content66666666666666666666666666666666666666666666666666666666666666666666666</div>
<div>Content77777777777777777777777777777777777777777777777777777777777777777777777</div>
<div>Content88888888888888888888888888888888888888888888888888888888888888888888888</div>
</div>
</div>
</div>
</div>
</body>
</html>
You need to allow .content to shrink then add min-width:0 or overflow:hidden so its size is calculated at screen inside its parent so overflow works on the children:
.content {
flex: 1 1 auto;/* updated*/
background: green;
min-width:0;/* added */
}
.flexContainer {
display: flex;
}
.sidebar {
flex: 1 0 auto;
min-width: 150px;
max-width: 190px;
color: white;
background: blue;
}
.content {
flex: 1 1 auto;
background: green;
min-width:0;
}
.scrollableElement {
display: flex;
overflow-x: scroll;
}
.textElement {
color: white;
background: grey;
}
<html>
<body>
<div class="flexContainer">
<div class="sidebar">
<div>Sidebar</div>
</div>
<div class="content">
<div class="scrollableElement">
<div class="textElement">
<div>Content11111111111111111111111111111111111111111111111111111111111111111111111</div>
<div>Content22222222222222222222222222222222222222222222222222222222222222222222222</div>
<div>Content33333333333333333333333333333333333333333333333333333333333333333333333</div>
<div>Content44444444444444444444444444444444444444444444444444444444444444444444444</div>
<div>Content55555555555555555555555555555555555555555555555555555555555555555555555</div>
<div>Content66666666666666666666666666666666666666666666666666666666666666666666666</div>
<div>Content77777777777777777777777777777777777777777777777777777777777777777777777</div>
<div>Content88888888888888888888888888888888888888888888888888888888888888888888888</div>
</div>
</div>
</div>
</div>
</body>
</html>
Your flex container has no set width, so it is taking up the entire width of the screen.
You could try setting the width to achieve the behavior you are looking for, for example:
.flexContainer {
display: flex;
width: 500px;
}
OR you could set the width of the .scrollableElement to resize based on the screen:
.scrollableElement {
overflow-x: scroll;
width: 65%;
}
I'm using a fixed-height flex container to do the layout. In the container, there are three components: header, content, footer. I want to force the content to use the rest of the height (i.e. content height = fixed-height minus header and footer). In my content, it will include an image and some texts.
However, the image always overflows a fixed-height flex container even providing max-height: 100% to constrain the height, but I want to put header, content, and footer into a fixed flex container.
Does anyone know how to fix it?
code: https://codepen.io/mrchung402/pen/wvGPJxz
<div class="container">
<div class="header">
header
</div>
<div class="content">
<div class="my-img">
<img src="http://via.placeholder.com/274x295">
</div>
<div class="my-text">
my-text
</div>
</div>
<div class="footer">
footer
</div>
</div>
.container {
border: solid 1px red;
display: flex;
max-width: 500px;
height: 200px;
flex-direction: column;
}
.header {
flex: 0 0 auto;
background: #A7E8D3;
}
.content {
display: flex;
flex-direction: column;
}
.footer {
flex: 0 0 auto;
background: #D7E8D4;
}
.my-img {
max-height: 100%;
height: auto;
max-width: 100%;
}
img {
max-height: inherit;
height: inherit;
}
.my-text {
background: #C7A8D4;
}
Instead of styling .my-img you should style .my-img img
.my-img img{
height: 100%;
width: 100%;
}
I'm struggling with getting the overflow-y piece to function as described in the code. I have an element that will only take up as much vertical space as its contents and when overflowing has the parent scroll. The code in its entirety can be seen here: https://jsfiddle.net/bmts8L5x/3/ . I've had to include only a part of the code here to satisfy the code to non-code ratio for the linter here.
header {
background: yellow;
}
#first {
overflow: hidden;
}
container {
display: flex;
height: 100vh;
overflow: hidden;
}
#side {
display: flex;
flex-direction: column;
width: 200px;
overflow: scroll;
}
#side>div {
height: 200px;
}
html,
body {
margin: 0;
padding: 0;
}
main>div:first-child {
background: white;
height: 50px;
}
#big {
background: pink;
border: solid;
overflow: scroll;
display: flex;
flex: 1;
}
#big>div {
width: 1000px;
height: 100px;
/* I'd like to see #big take up the remaining space regardless of whether height here is 100px or 10000px */
}
<container>
<div id="side">
<div>
side nav does not scroll
</div>
<div>
item
</div>
<div>
item
</div>
<div>
item
</div>
<div>
item
</div>
<div>
item
</div>
</div>
<div id="first">
<header>
foo
</header>
<main>
<div>
this should remain visible after scrolling without needing position fixed
</div>
<header>
some other stuff
</header>
<div id="big">
<div>
this should take up the rest of the remaining viewable space and have any overflow be scrolled through.
<br /> X scrolls as expected but Y's overflow isn't contained to rest of viewable space.
</div>
</div>
</main>
</div>
</container>
You can nest your flexboxes even more - make your #first and main a column flexbox and give height: 100% to it:
#first, main {
display: flex;
flex-direction: column;
height: 100%;
}
See demo below:
header {
background: yellow;
}
#first {
overflow: hidden;
}
container {
display: flex;
height: 100vh;
overflow: hidden;
}
#side {
display: flex;
flex-direction: column;
width: 200px;
overflow: scroll;
}
#side>div {
height: 200px;
}
html,
body {
margin: 0;
padding: 0;
}
main>div:first-child {
background: white;
height: 50px;
}
#big {
background: pink;
border: solid;
overflow: scroll;
display: flex;
flex: 1;
}
#big>div {
width: 1000px;
height: 100px;
}
/* ADDED */
#first, main {
display: flex;
flex-direction: column;
height: 100%;
}
<container>
<div id="side">
<div>side nav does not scroll</div>
<div>item</div>
<div>item</div>
<div>item</div>
<div>item</div>
<div>item</div>
</div>
<div id="first">
<header>foo</header>
<main>
<div>
this should remain visible after scrolling without needing position fixed
</div>
<header>
some other stuff
</header>
<div id="big">
<div>
this should take up the rest of the remaining viewable space and have any overflow be scrolled through.
<br /> X scrolls as expected but Y's overflow isn't contained to rest of viewable space.
</div>
</div>
</main>
</div>
</container>
I have a pay layout which works how I want to when using the .slides element has a background colour and height, it flexes as expected, however when I switch to filling it with an image this behaviour breaks as the images won't resize and I can't get my head around how to make them resize.
The idea is the left column of text remains fixed size, and the right column flexes up and down, eventually snapping under the left column at small sizes.
The reason for using an <img> and not a background image is because there is a image slide show that I want to put in here.
Can anyone help fix this issue?
body {
margin: 1em;
}
p {
margin: 0;
}
.container {
display: flex;
margin-top: 1em;
width: 100%;
flex-wrap: wrap;
}
.text {
flex: 0 0 auto;
width: 15em;
margin-right: 1em;
}
.images {
flex: 1 1 auto;
min-width: 15em;
max-width: 800px;
}
.caption {
margin-top: .25em;
}
<div class="header">
Title
</div>
<div class="container">
<div class="text">
<p>Something about this project is really interesting.</p>
</div>
<div class="images">
<div class="slides">
<img src="https://via.placeholder.com/800x800">
</div>
<div class="caption">
<p>Text about this project</p>
</div>
</div>
</div>
Changes made:
Enabled responsiveness for img elements
Commented out the flex-wrap: wrap
Set #media queries to define when the wrapping inside the .container div takes place
body {
margin: 1em;
}
p {
margin: 0;
}
img {
display: block; /* removes bottom margin/whitespace */
max-width: 100%; /* horizontally responsive */
max-height: 100vh; /* vertically responsive */
}
.container {
display: flex;
margin-top: 1em;
width: 100%;
/*flex-wrap: wrap;*/
}
.text {
flex: 0 0 auto;
width: 15em;
margin-right: 1em;
}
.images {
flex: 1 1 auto;
min-width: 15em;
max-width: 800px;
}
.caption {
margin-top: .25em;
}
#media (max-width: 33em) { /* 2 x 15em (.text & .images) + 2em (left & right margin of the body element) + 1em (.text margin-right) */
.container {flex-wrap: wrap}
}
<div class="header">
Title
</div>
<div class="container">
<div class="text">
<p>Something about this project is really interesting.</p>
</div>
<div class="images">
<div class="slides">
<img src="https://via.placeholder.com/800x800">
</div>
<div class="caption">
<p>Text about this project</p>
</div>
</div>
</div>
Do you mean something like this ?
body {
margin: 1em;
}
p {
margin: 0;
}
.container {
display: flex;
margin-top: 1em;
width: 100%;
flex-flow:row wrap;
}
.text {
flex: 0 0 auto;
width: 15em;
margin-right: 1em;
}
.images {
flex:1 0 15em;
min-width: 15em;
max-width:800px;
}
.slides {
display:flex;
}
.caption {
margin-top: .25em;
}
<div class="header">
Title
</div>
<div class="container">
<div class="text">
<p>Something about this project is really interesting.</p>
</div>
<div class="images">
<div class="slides">
<img src="https://via.placeholder.com/800x800" />
</div>
<div class="caption">
<p>Text about this project</p>
</div>
</div>
</div>
I am trying to divide my page into 2 columns. I want content on the left with a padding on it together with a border. On the right I want my sidebar, which has a fixed width.
https://jsfiddle.net/mortenmoulder/04fkrkpp/
#container {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 100%;
}
I have tried doing that, but I'm not sure if I should use space-between or something else. I have basically achieved what I want, but the padding should be equal on all the sides. How do I achieve that?
You can use flex-grow:1; instead of width:100%;, and you need to change of few other things as well
Use border directly on #left-container and add margin instead of padding, this will make the space equal to all sides.
See updated fiddle
body,
html {
height: 100%;
margin: 0;
}
#container {
display: flex;
flex-direction: row;
height: 100%;
}
#left-container {
flex-grow: 1;
border: 20px solid black;
margin: 50px;
}
#left {
height: 100%;
}
#right {
width: 300px;
border-left: 1px solid black;
}
<div id="container">
<div id="left-container">
<div id="left">
<p>
Some content here
</p>
<p>
Some content here
</p>
<p>
Some content here
</p>
</div>
</div>
<div id="right">
<p>
Right sidebar
</p>
</div>
</div>
check below code I just added flex: 1 and remove some unnecessary code from your demo
body,
html {
height: 100%;
margin: 0;
}
#container {
display: flex;
/*flex-direction: row;
justify-content: space-between;*/
height: 100%;
}
#left-container {
padding: 50px;
width: 100%;
flex: 1;
}
#left {
border: 20px solid black;
height: 100%;
/*width: 100%;*/
}
#right {
width: 300px;
border-left: 1px solid black;
}
<div id="container">
<div id="left-container">
<div id="left">
<p>
Some content here
</p>
<p>
Some content here
</p>
<p>
Some content here
</p>
</div>
</div>
<div id="right">
<p>
Right sidebar
</p>
</div>
</div>
https://jsfiddle.net/04fkrkpp/3/