Make content scroll horizontally within nested flex containers with position sticky - html

I have the following layout (see snippet below).
This is the expected behavior.
The problem is:
Once the extra-large-content is simulated (by removing the comment on the extra-large-content CSS rule), it breaks the layout.
I would like the extra-large-content to scroll horizontally while staying inside column-3.
Is this even possible?
(the code is also available here https://codepen.io/Ploddy/pen/NWXOgMG?editors=1100)
body {
height: 1920px;
margin: 0;
}
.container {
display: flex;
border: 1px solid #ccc;
margin: 1rem;
}
.container > * {
border: 1px solid #ccc;
position: sticky;
top: 0;
align-self: flex-start;
flex-grow: 1;
margin: 1rem;
}
#column-3 {
height: 300px;
}
#extra-large-content {
background-color: lightgreen;
/*width: 3000px;*/
}
<div class="container">
<div>
column-1
</div>
<div class="container">
<div>
column-2
</div>
<div id="column-3">
column-3
<div id="extra-large-content">
extra-large content
</div>
</div>
</div>
</div>

This should work nicely for you. Essentially, I just specified width's on the .container elements. In theory, you could put overflow-x: scroll; on the .container, however, this would break your sticky positioning.
Edit ~ OP wants the extra-large content to scroll horizontally, not the entire column-3.
Set overflow-x: scroll; on the new parent wrapper of the div that has the 3000px static width.
body {
height: 1920px;
margin: 0;
}
.container:first-child {
max-width: 100%;
}
.container:first-child > div:first-child {
width: 40%;
}
.container:nth-child(2) {
width: 60%;
}
.container:nth-child(2) > div:first-child {
margin: 1em 0em 1em 1em;
}
.container {
display: flex;
border: 1px solid #ccc;
margin: 1rem;
}
.container>* {
border: 1px solid #ccc;
position: sticky;
top: 0;
align-self: flex-start;
flex-grow: 1;
margin: 1rem;
}
.wrapper {
display: flex;
flex-direction: column;
width: 40%;
}
#column-3 {
background-color: salmon;
}
#extra-large-content {
height: 300px;
width: 3000px;
background-color: lightgreen;
}
.xl-content-wrapper {
overflow-x: scroll;
}
<div class="container">
<div>column-1</div>
<div class="container">
<div>column-2</div>
<div class="wrapper">
<div id="column-3">column-3</div>
<div class="xl-content-wrapper">
<div id="extra-large-content">extra-large content</div>
</div>
</div>
</div>
</div>

The issue comes from using flexbox.
Switching to grid fixes the problem.
body {
height: 1920px;
margin: 0;
}
#primary-container {
position: relative;
display: flex;
margin: 1rem;
}
#secondary-container {
position: relative;
display: grid;
grid-template-columns: max-content 1fr;
align-items: start;
}
#column-3 {
display: grid;
grid-auto-rows: min-content;
height: 200px;
}
#content-wrapper {
overflow: auto;
}
#extra-large-content {
width: 3000px;
background-color: lightgreen;
}
.sticky {
position: sticky;
top: 0;
align-self: flex-start;
}
.border {
border: 1px solid #ccc;
}
<div id="primary-container" class="border">
<div class="sticky">
column1
</div>
<div id="secondary-container" class="border">
<div class="sticky">
column2
</div>
<div id="column-3" class="sticky border">
column3
<div id="content-wrapper">
<div id="extra-large-content">
extra-large content
</div>
</div>
...
</div>
</div>
</div>

Related

Container not fitting to screen and flex-direction: row not working properly

I'm starting out an application in angular and really struggling getting a basic layout setup; I have experience with angular but actual html/css design is completely new to me
Nothing I've tried seems to allow this container to take up the entirety of the screen. I have tried using multiple different settings on the html and container css classes and nothing will actually fit the container to the screen with width; but the height always seems to fit properly.
Aside from this flex-direction: row does not seem to consistently work. For example, I am trying to get the div "side" and the div "main" inside of the header div to fit next to each-other. Instead of this, those div's act like columns; despite the fact I have nowrap on; I have also tried display: inline-block and that also does not work. I have decreased the width of side and main in hopes that they would then fit next to eachother and that also does not work.
Screenshot:
Full View
html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
}
.container {
position: relative;
top: 0;
left: 0;
bottom: 0;
right: 0;
border: 1px solid black;
display: flex;
flex-direction: column;
}
.header {
margin-top: 15px;
border: 1px solid red;
height: 15vh;
flex-direction: row;
flex-wrap: nowrap;
}
.body {
border;
1px solid green;
height: 80vh;
}
.side {
width: 15vw;
border: 1px solid yellow;
}
.main {
width: 50vw;
border: 1px solid blue;
}
<div class="container">
<div class="header">
<div class="side">
<p>HI</p>
<div class="main">
<p>HI2</p>
</div>
</div>
<div class="body">
<p>I am the body</p>
</div>
</div>
</div>
Firstly - there are quite a few typos in your code. You haven't closed the side class or the main class and there is no closing div for the side div.
Secondly - After I'd tidied up your code, I noticed that you were making the .container display: flex; when in fact you needed to make the .header display: flex; as this is the parent of the side and main divs.
This is a great guide for flexbox: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
This should work for you:
html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
}
.container {
position: relative;
top: 0;
left: 0;
bottom: 0;
right: 0;
border: 1px solid black;
display: flex;
flex-direction: column;
}
.header {
margin-top: 15px;
border: 1px solid red;
height: 15vh;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
}
.side {
width: 15vw;
border: 1px solid yellow;
}
.main {
width: 50vw;
border: 1px solid blue;
}
.body {
border: 1px solid green;
height: 80vh;
}
<div class="container">
<div class="header">
<div class="side">
<p>HI</p>
</div>
<div class="main">
<p>HI2</p>
</div>
</div>
<div class="body">
<p>I am the body</p>
</div>
</div>
main is inside side. if you want them to be beside each other, you will need to arrange them as siblings within the flexbox.
you also forgot to add display: flex on the header css.
try this
html {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
}
.container {
position: relative;
top: 0;
left: 0;
bottom: 0;
right: 0;
border: 1px solid black;
display: flex;
flex-direction: column;
}
.header {
margin-top: 15px;
border: 1px solid red;
height: 15vh;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
.body {
border: 1px solid green;
height: 80vh;
}
.side {
width: 15vw;
border: 1px solid yellow;
}
.main {
width: 50vw;
border: 1px solid blue;
}
<div class="container">
<div class="header">
<div class="side">
<p>HI</p>
</div>
<div class="main">
<p>HI2</p>
</div>
</div>
<div class="body">
<p>I am the body</p>
</div>
</div>

larger flex child causing previous sibling's padding to be ignored

So I have a flexbox but I'm having trouble understanding why the first child's padding gets ignored when the second child's content overflows.
here's an example when the second child's content aren't overflowing.
body {
padding: 0;
margin: 0;
}
.flex {
display: flex;
flex-direction: column;
width: 100vw;
height: 100vh;
}
.title {
background-color: green;
border-bottom: 10px solid black;
display: flex;
height: 50px;
padding-bottom: 40px;
}
.body {
background-color: blue;
flex: 1;
}
.content {
background-color: red;
height: 10vh;
}
<div class="flex">
<div class="title">
</div>
<div class="body">
<div class="content">
</div>
</div>
</div>
Here's an example when the child's content are overflowing
body {
padding: 0;
margin: 0;
}
.flex {
display: flex;
flex-direction: column;
width: 100vw;
height: 100vh;
}
.title {
background-color: green;
border-bottom: 10px solid black;
display: flex;
height: 50px;
padding-bottom: 40px;
}
.body {
background-color: blue;
flex: 1;
}
.content {
background-color: red;
height: 100vh;
}
<div class="flex">
<div class="title">
</div>
<div class="body">
<div class="content">
</div>
</div>
</div>
you can see in the second example that the title's height has greatly reduced.
It's because you're using flex css, which tries to accommodate all the children. If the title is supposed to not change in size no matter what, you need to set its flex-shrink to 0.
So try changing the css to:
.title {
background-color: green;
border-bottom: 10px solid black;
display: flex;
height: 50px;
padding-bottom: 40px;
flex-shrink: 0;
}

Flexbox element height 100% going outside of parent?

So because of design reasons I had to use flexbox here and I needed the btn p elements to act like display block, which I managed to through another stack post, but now when I make the "other divs" class 100%, it goes out of the main parent, I cannot figure out why?
#outterWrapper {
display: inline-block;
height: 200px;
border: 1px solid red;
}
#container {
display: flex;
height: 200px;
flex-wrap: wrap;
}
#menu {
display: flex;
flex-basis: 100%;
}
#menu p {
margin: 0;
padding: 8px;
padding-bottom: 0;
}
.otherDivs {
height: 100%;
width: 25%;
background-color: grey;
margin-right: 5px;
}
<div id="outterWrapper">
<div id="container">
<div id="menu">
<p>Btn</p>
<p>Btn</p>
<p>Btn</p>
</div>
<div class="otherDivs"></div>
</div>
</div>
As from the example above the grey box goes outside of the red border?
You can switch to column direction and have something like this :
#outterWrapper {
display: inline-block;
height: 200px;
border: 1px solid red;
}
#container {
display: flex;
height: 200px;
flex-direction:column;
}
#menu {
display: flex;
}
#menu p {
margin: 0;
padding: 8px;
padding-bottom: 0;
}
.otherDivs {
height: 100%;
width: 25%;
background-color: grey;
margin-right: 5px;
}
<div id="outterWrapper">
<div id="container">
<div id="menu">
<p>Btn</p>
<p>Btn</p>
<p>Btn</p>
</div>
<div class="otherDivs"></div>
</div>
</div>

canvas having odd behaviour with width and height

So I'm having some issues using <canvas>. It's taking up too much room when at 100% height and width and when it's set at only 100% height, it still causes and overflow for some reason.
Examples
With width and height at 100%, canvas takes up way too much room
.flex {
display: flex;
flex-direction: column;
height: 100vh;
}
.upper {
background-color: blue;
height: 10%;
}
.lower {
flex: 1;
background-color: orange;
}
html, body {
padding: 0;
margin: 0;
}
canvas {
height: 100%;
width: 100%;
background-color: red;
padding: 0;
margin: 0;
}
.inner {
width: 100%;
height: 100%;
background-color: yellow;
position: relative;
}
<div class="flex">
<div class="upper">
</div>
<div class="lower">
<div class='inner'>
<canvas></canvas>
</div>
</div>
</div>
Here, canvas is set at 100% height, yet it causes an overflow for some reason.
.flex {
display: flex;
flex-direction: column;
height: 100vh;
}
.upper {
background-color: blue;
height: 10%;
}
.lower {
flex: 1;
background-color: orange;
}
html, body {
padding: 0;
margin: 0;
}
canvas {
height: 100%;
background-color: red;
padding: 0;
margin: 0;
}
.inner {
width: 100%;
height: 100%;
background-color: yellow;
}
<div class="flex">
<div class="upper">
</div>
<div class="lower">
<div class='inner'>
<canvas></canvas>
</div>
</div>
</div>

Flexbox: scrollable content with sticky footer

I want to make a box (flex-item in this case) which always stays in the middle of it's container. In that box, there is a header, footer and content section. If the size of the content grows too big in height, I want the content section to be scrollable. The header and footer should always be visible and the box should always stay in it's container.
Here is what I have been able to write:
HTML
<div class="flex-container">
<div class="flex-item">
<header>Header</header>
<div class="content">
A
<br>B
<br>C
<br>D
<br>E
<br>F
<br>G
<br>H
<br>I
<br>J
<br>K
</div>
<footer>Footer</footer>
</div>
</div>
CSS
body {
margin: 120px;
}
.flex-container {
display: flex;
width: 200px;
height: 200px; /* We can assume that the container's height is hardcoded in this example, but the end solution should work even if this value is changed*/
border: 1px solid black;
justify-content: center;
}
.flex-item {
box-sizing: border-box;
width: 150px;
border: 5px solid blue;
align-self: center;
background-color: red;
display: flex;
flex-flow: column;
max-height: 100%;
}
.content {
/* It should be possible to scroll this element when it get too big in height*/
background-color: grey;
flex: 1;
}
The code is hosted on JSFiddle: https://jsfiddle.net/9fduhpev/3/
To explain the same thing visually, here is the current situation:
Here is what I want:
Use overflow-y: auto;.
Read this: http://www.w3schools.com/cssref/css3_pr_overflow-y.asp
body {
margin: 120px;
}
.flex-container {
display: flex;
width: 200px;
height: 200px;
border: 1px solid black;
justify-content: center;
}
.flex-item {
box-sizing: border-box;
width: 150px;
border: 5px solid blue;
align-self: center;
background-color: red;
display: flex;
flex-flow: column;
max-height: 100%;
}
.content {
background-color: grey;
flex: 1;
overflow-y: auto;
}
<div class="flex-container">
<div class="flex-item">
<header>Header</header>
<div class="content">
A
<br>B
<br>C
<br>D
<br>E
<br>F
<br>G
<br>H
<br>I
<br>J
<br>K
<br>L
</div>
<footer>Footer</footer>
</div>
</div>
I suggest you give it overflow: auto. With that it will be scrollable when needed.
body {
margin: 20px;
}
.flex-container {
display: flex;
width: 200px;
height: 200px;
border: 1px solid black;
justify-content: center;
}
.flex-item {
box-sizing: border-box;
width: 150px;
border: 5px solid blue;
align-self: center;
background-color: red;
display: flex;
flex-flow: column;
max-height: 100%;
}
.content {
background-color: grey;
flex: 1;
overflow: auto;
}
<div class="flex-container">
<div class="flex-item">
<header>Header</header>
<div class="content">
A
<br>B
<br>C
<br>D
<br>E
<br>F
<br>G
<br>H
<br>I
<br>J
<br>K
<br>L
</div>
<footer>Footer</footer>
</div>
</div>
I would do something like this:
.content {
height: 100%;
overflow:auto;
background-color: grey;
flex: 1;
}
https://jsfiddle.net/9fduhpev/4/