how to correctly make flex-box children to scroll - css

I'm stuck and can't make content to correctly scroll while facing a few of nested flex-boxes. Here is my css:
html,body,#root{
width:100%;
height:100%;
padding:0;
margin:0;
}
.flex-fill{
height:100%;
width:100%;
display:flex;
align-items:stretch;
}
.flex-fill>div:last-child{
flex-grow:1;
}
.flex-col{
flex-direction:column;
}
<div id='root'>
<div class='flex-fill flex-col'><!--actually scrolling div-->
<div style="flex:0 0 35px"><h1>main title</h1></div>
<div>
<div class='flex-fill flex-col'>
<div style="flex:0 0 30px"><h2>subtitle</h2></div>
<div class='flex-fill'>
<div style="flex:0 0 30%">...left side nav list...</div>
<div class='flex-fill flex-col'>
<div style="flex:0 0 25px">...data header...</div>
<!--I hope the content of this div is scroll-able-->
<div style="overflow-y:scroll">...data list...</div>
</div>
</div>
</div>
</div>
</div>
</div>
The data list contained in the inner most div is very long and I want to make it scrollable. But in the fact the above codes make whole content of the root div scrolling. Have I misunderstanding about flex or overflow? How can I fix the other parts and just scroll the data list?

Answer updated to keep your HTML structure the same. Inline styles removed and added as classes:
html,body{
height:100%;
padding:0;
margin:0;
}
#root {
height: 100%;
display: flex;
}
.flex-fill{
height:100%;
display:flex;
align-items:stretch;
}
.flex-col{
flex-direction:column;
display: flex;
flex: 1 0 0;
height: 100%;
}
.flex-row{
flex-direction:row;
display: flex;
height: 100%;
}
.scrolling-div {
height: 100%;
overflow-y: scroll;
}
<div id='root'>
<div class='flex-fill flex-col'>
<div><h1>main title</h1></div>
<div class="flex-col">
<div class='flex-col'>
<div><h2>subtitle</h2></div>
<div class="flex-row">
<div>...left side nav list...</div>
<div class='flex-col'>
<div>...data header...</div>
<!--Now Scrolls-->
<div class="scrolling-div">
...scrolling data list...<br />
...scrolling data list...<br />
...scrolling data list...<br />
...scrolling data list...<br />
</div>
</div>
</div>
</div>
</div>
</div>
</div>

#Welson Zhong, please have a look at the below working snippet, please look it in Full page view, hope it helps now :)
note: too much flex kills flex ;) that was the issue with your code.
html, body {
height: 100%;
margin: 0;
padding: 0;
}
body {
display: flex;
flex-direction: column;
font-family: sans-serif;
font-size: 18px;
}
.main {
display: flex;
flex-direction: row;
flex: 1 0 auto;
}
.sidebar {
flex: 1 auto;
}
.content {
display: flex;
flex-flow: column nowrap;
flex: 3 0px;
}
h1,h2,.data-header {
flex: none;
}
/* below css is for visual purpose only */
.main *:not(.content) {
box-shadow: inset 0 0 0 1px #ccc;
padding: 10px;
}
<h1>main title</h1>
<h2>sub title</h2>
<div class="main">
<div class="sidebar">
...left side nav list...
</div>
<div class="content">
<div class="data-header">...data header...</div>
<div style="overflow-y:scroll; flex: auto">...data list...</div>
</div>
</div>

Related

Sticky Header/Footer With 3 columns. Divs that scroll within the columns

I have a JS Fiddle here.
https://jsfiddle.net/h3c6jqfy/
Basically, i am trying to make a UI that has a sticky header and footer. The middle content will have three columns. Each columns will have DIVs in them. These DIVs should have 100% height and not be cut off from the footer. Within the DIV, they will have scrollable divs.
The very basic layout I created has this in it...
d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>this is the end!!
The part where it says this is the end!! is never reached.
You can use flexbox without the need to calculate heights;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
::before,
::after {
box-sizing: inherit;
}
body {
display: flex;
flex-direction: column;
height: 100vh;
}
header {
height: 75px;
background: red;
}
main {
flex: 1;
background: lightgreen;
display: flex;
}
.scrolly {
flex: 1 0 33%;
overflow-y: auto;
}
.content {
height: 1000px;
}
footer {
height: 50px;
background: blue;
}
<header></header>
<main>
<div class="scrolly">
<div class="content"></div>
</div>
<div class="scrolly">
<div class="content"></div>
</div>
</div>
<div class="scrolly">
<div class="content"></div>
</div>
</div>
</main>
<footer></footer>
NOTE: See Fiddle in Full Screen
You can try using flexbox instead of defining every unit, calculate the height to avoid using the space where the footer sits, and let the children div inherit its height
<style>
body, head {overflow: hidden;}
#header,#footer,#content { position:absolute; right:0;left:0;}
#header{
height:100px; top:0; background: #4A4A4A;
}
#footer{
height:100px; bottom:0; background: #4A4A4A;
}
#content{
top:100px;
height: calc(100% - 100px);
background:#fff;
display: flex;
align-items: stretch;
}
</style>
<div>
<div id="header">HEADER</div>
<div id="content">
<div style="background-color: #ff0000; min-width: 33%; height: inherit; overflow-y: scroll;">
<div style="background-color: blue;min-height: inherit;max-width: 99%;padding: 20px 40px;">
<div style="overflow: auto; max-height: inherit; padding: 10px;">
<br>d<br>d<br>d<br>d<br>d<br>d<br>d
<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>
d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>
d<br>d<br>d<br>d<br><br>d<br>d<br>d<br>d<br>
d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>
d<br>d<br>d
<br>d<br>this is the end!!
</div>
</div>
</div>
<div style="background-color: #ff0000; min-height: 100%; min-width: 33%; max-width: 33%;float: left;">
<div style="background-color: red;min-height: 100%;max-width: 99%;padding: 20px 40px;">
middle
</div>
</div>
<div style="background-color: #ff0000; min-height: 100%; min-width: 33%; max-width: 33%;float: left;">
<div style="background-color: pink;min-height: 100%;max-width: 99%;padding: 20px 40px;">
right
</div>
</div>
</div>
<div id="footer">FOOTER</div>
</div>

Float second div to right only when its fits next to the first

I have the following (simplified) html & css:
<div class="container">
<div class="one">Some text for div 1</div>
<div class="two">Some text for div 2</div>
</div>
<style>
.two {float: right}
</style>
When both elements fit together in their container, I want it to look like;
Some text for div 1 Some text for div 2
However when they do not fit next to each other I want the second div's float to be removed, like;
Some text for div 1
Some text for div 2
How can I achieve this?
Flexbox can do that;
.parent {
border: 1px solid red;
margin: 1em auto;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.skinny {
width: 60%;
}
.left {
height: 50px;
background: green;
flex: 0 0 250px
}
.right {
height: 50px;
background: pink;
flex: 0 0 250px;
}
<div class="parent">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="parent skinny">
<div class="left"></div>
<div class="right"></div>
</div>
my variant without flexbox and more cross-browser
.container{
font-size: 0;
text-align: justify;
}
.container::after{
content: "";
display: inline-block;
width: 100%;
height: 0;
visibility: hidden;
}
.class-1, .class-2{
display: inline-block;
font-size: 14px;
text-align: left;
}
<div class="container">
<div class="class-1">Some text for div 1</div>
<div class="class-2">Some text for div 2</div>
</div>

flexbox vertical align child top, center another

I've got the following markup:
.row {
display: flex;
align-items: stretch;
margin: -16px;
background: #ddd;
}
.row .col {
display: flex;
flex-direction: column;
justify-content: center;
flex: 1;
margin: 16px;
background: #fff;
}
.header, .content, .footer {
padding: 16px;
background: red;
}
<div class="row">
<div class="col">
<div class="header">Header #1</div>
<div class="content">Lorem Ipsum<br />Dolor<br />Sit Amet</div>
<div class="footer">Footer</div>
</div>
<div class="col">
<div class="header">Header #2</div>
<div class="content">Lorem Ipsum<br />Dolor</div>
</div>
</div>
Unfortunatly the second header isn't align vertically to the top. Is there a way to archive this with flexbox? I need the ".header" to be aligned the the top and the ".content" to be centered within the rest of the box.
Greetings!
No, not really, not without another wrapper which is a flex-container.
As flexbox is, to a certain extent based on manipulting margins, there is no method (AFAIK, although I'd be interested to find out if there is) to justify-content: center and then align-self a child element to somewhere else other than center.
I'd go with something like this: Add a wrapper to the "content" div, give it flex:1 to fill the remaining space below the header, then make that wrapper display:flex with justify-content:center.
This seems to be the most logical method
.col {
height: 150px;
width: 80%;
margin: 1em auto;
border: 1px solid grey;
display: flex;
flex-direction: column;
}
.header {
background: lightblue;
}
.content {
background: orange;
}
.flexy {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
background: plum;
}
<div class="col">
<div class="header">Header #2</div>
<div class="flexy">
<div class="content">Lorem Ipsum
<br />Dolor</div>
</div>
</div>
Codepen Demo
Flexbox opens up all sorts of opportunities with margin: auto; this is one of them. Setting margin to auto along the flex axis (vertical in this case) will absorb any extra space before dividing it up between the flex items. Finally it's possible to vertically center stuff without creating a div soup.
.row {
display: flex;
align-items: stretch;
margin: -16px;
background: #ddd;
}
.row .col {
display: flex;
flex-direction: column;
flex: 1;
margin: 16px;
background: #fff;
}
.header, .content, .footer {
padding: 16px;
background: red;
}
.content {
margin-top: auto;
margin-bottom: auto;
}
<div class="row">
<div class="col">
<div class="header">Header #1</div>
<div class="content">Lorem Ipsum<br />Dolor<br />Sit Amet</div>
<div class="footer">Footer</div>
</div>
<div class="col">
<div class="header">Header #2</div>
<div class="content">Lorem Ipsum<br />Dolor</div>
</div>
</div>

Reorder columns in reverse order

I have a list of flex items within a flexbox. The order of the items matter, and for accessibility purposes, the items need to show up in the correct order in the dom.
[[itema][itemb][itemc]]
When the flexbox shrinks I would like to have the items wrap in reverse order, e.g. itema wraps first, etc. Is there any way to have the itema wrap first? Thanks!
Edit:
Here is the code
<div class="flex">
<div class="container">
<div class="item">item1</div>
<div class="item orange">item2</div>
<div class="item blue">item3</div>
</div>
<div class="last-item green">menu</div>
</div>
.flex {
display: flex;
background-color: yellow;
height: 80px;
overflow: hidden;
color: #fff;
}
.container {
display: flex;
flex: 1 1 auto;
flex-wrap: wrap;
}
.item {
flex: 0 0 auto;
background-color: red;
height: 80px;
padding: 0 40px;
}
.last-item {
width: 40px;
flex: 0 0 auto;
height: 80px;
}
JSFiddle
All the behavior is as desired except I want the first item to wrap first. Any ideas? Thanks!
You can use the flex-direction: column-reverse to get your solution.
#media (max-width: 768px) {
.flex-box {
display: flex;
flex-direction: column-reverse;
}
}
.first,
.second,
.third {
display: inline-block;
}
<div class="flex-box">
<div class="first">
<p>First Box</p>
<img src="http://placehold.it/300x300" />
</div>
<div class="second">
<p>Second Box</p>
<img src="http://placehold.it/300x300" />
</div>
<div class="third">
<p>Third Box</p>
<img src="http://placehold.it/300x300" />
</div>
</div>
JSfiddle Demo
To make item1 wrap first, you can use flex-wrap: wrap-reverse on your flex container.
Try this simplified version of you code:
<div class="container">
<div class="item">item1</div>
<div class="item orange">item2</div>
<div class="item blue">item3</div>
</div>
.container {
display: flex;
flex: 0 1 auto;
flex-wrap: wrap-reverse;
}
.item {
background-color: red;
height: 80px;
padding: 0 40px;
}
.orange {
background-color: orange;
}
.blue {
background-color: blue
}
See the MDN reference for browser support.

Align <div> elements side by side

I know this is a rather simple question, but I can't figure it out for the life of me. I have two links which I've applied a background image to. Here's what it currently looks like (apologies for the shadow, just a rough sketch of a button):
However, I want those two buttons to be side by side. I can't really figure out what needs to be done with the alignment.
Here's the HTML
<div id="dB"}>
Download
</div>
<div id="gB">
Gallery
</div>
Here's the CSS
#buyButton {
background: url("assets/buy.png") 0 0 no-repeat;
display:block;
height:80px;
width:232px;
text-indent:-9999px;
}
#buyButton:hover{
width: 232px;
height: 80px;
background-position: -232px 0;
}
#buyButton:active {
width: 232px;
height: 80px;
background-position: -464px 0;
}
#galleryButton {
background: url("images/galleryButton.png") 0 0 no-repeat;
display:block;
height:80px;
width:230px;
text-indent:-9999px;
}
#galleryButton:hover{
width: 230px;
height: 80px;
background-position: -230px 0;
}
#galleryButton:active {
width: 230px;
height: 80px;
background-position: -460px 0;
}
Beware float: left… 🤔
…there are many ways to align elements side-by-side.
Below are the most common ways to achieve two elements side-by-side…
Demo: View/edit all the below examples on Codepen
Basic styles for all examples below…
Some basic css styles for parent and child elements in these examples:
.parent {
background: mediumpurple;
padding: 1rem;
}
.child {
border: 1px solid indigo;
padding: 1rem;
}
Using the float solution my have unintended affect on other elements. (Hint: You may need to use a clearfix.)
html
<div class='parent'>
<div class='child float-left-child'>A</div>
<div class='child float-left-child'>B</div>
</div>
css
.float-left-child {
float: left;
}
html
<div class='parent'>
<div class='child inline-block-child'>A</div>
<div class='child inline-block-child'>B</div>
</div>
css
.inline-block-child {
display: inline-block;
}
Note: the space between these two child elements can be removed, by removing the space between the div tags:
html
<div class='parent'>
<div class='child inline-block-child'>A</div><div class='child inline-block-child'>B</div>
</div>
css
.inline-block-child {
display: inline-block;
}
html
<div class='parent flex-parent'>
<div class='child flex-child'>A</div>
<div class='child flex-child'>B</div>
</div>
css
.flex-parent {
display: flex;
}
.flex-child {
flex: 1;
}
html
<div class='parent inline-flex-parent'>
<div class='child'>A</div>
<div class='child'>B</div>
</div>
css
.inline-flex-parent {
display: inline-flex;
}
html
<div class='parent grid-parent'>
<div class='child'>A</div>
<div class='child'>B</div>
</div>
css
.grid-parent {
display: grid;
grid-template-columns: 1fr 1fr
}
Apply float:left; to both of your divs should make them stand side by side.
keep it simple
<div align="center">
<div style="display: inline-block"> <img src="img1.png"> </div>
<div style="display: inline-block"> <img src="img2.png"> </div>
</div>
.section {
display: flex;
}
.element-left {
width: 94%;
}
.element-right {
flex-grow: 1;
}
<div class="section">
<div id="dB" class="element-left" }>
Download
</div>
<div id="gB" class="element-right">
Gallery
</div>
</div>
or
.section {
display: flex;
flex-wrap: wrap;
}
.element-left {
flex: 2;
}
.element-right {
width: 100px;
}
<div class="section">
<div id="dB" class="element-left" }>
Download
</div>
<div id="gB" class="element-right">
Gallery
</div>
</div>

Resources