Make child div fill parent div with scroll - css

I am having problems with flexbox layout parenting a child control.
html, body, .frame{
margin: 0;
height: 100%;
}
* {
box-sizing: border-box;
}
.frame{
display: flex;
flex-flow: column;
}
.header{
background-color: yellow;
height: 40px;
}
.body-outer{
background-color: green;
flex: 1;
display: flex;
flex-flow: column;
}
.body-inner{
border: 1px solid red;
flex: 1;
}
.big-text{
height: 2000px;
border: 1px solid lightblue;
overflow: auto;
margin: 5px;
}
<div class="frame">
<div class="header">header</div>
<div class="body-outer">
<div>subheader</div>
<div class="body-inner>">
<div class="big-text">big text</div>
</div>
</div>
</div>
The 'body-inner' div is meant to fill the remaining space with flex: 1 and the 'big-text' is supposed to fill the whole space of 'body-inner' without expanding it but showing scroll bars.

You have the overflow applied to the content. It should be applied to the container that will be overflowed.
Also, you need a fixed height, so that the overflow property has something to overflow.
Try this:
.frame {
display: flex;
flex-flow: column;
height: 100vh;
}
.header {
background-color: yellow;
height: 40px;
}
.body-outer {
height: calc(100vh - 40px); /* new */
background-color: green;
/* flex: 1; */
display: flex;
flex-flow: column;
}
.body-inner {
border: 1px solid red;
flex: 1;
overflow: auto; /* moved here */
}
.big-text {
height: 2000px;
border: 1px solid lightblue;
/* overflow: auto; */
margin: 5px;
}
body {
margin: 0;
}
* {
box-sizing: border-box;
}
<div class="frame">
<div class="header">header</div>
<div class="body-outer">
<div>subheader</div>
<div class="body-inner">
<div class="big-text">big text</div>
</div>
</div>
</div>

Related

How to remove the empty space between elements?

I have made a calculator using one parent div and plenty of child divs, the children are in html. After that I styled it using flex-box and it is almost done; nevertheless there is an empty space between first div (.result) and the rest of the divs (.btn).
I want to remove that empty space which is shown in picture below:
I tried to use flex-box method to arrange these div elements like blocks.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
h1 {
margin: 0 auto 0 auto;
background-color: gray;
text-align: center;
margin-bottom: 5vh;
}
.kalkulator {
display: flex;
flex-wrap: wrap;
height: 50vh;
width: 30vw;
margin: 0 auto 0 auto;
}
.kalkulator .result {
flex-basis: 100%;
height: 10vh;
background-color: #333;
}
.kalkulator div {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
flex-basis: 33%;
background-color: #666;
border: 1px solid black;
}
.btn:nth-last-child(2),
.btn:nth-last-child(1) {
flex-basis: 50%;
}
<h1>kalkulator</h1>
<div class="kalkulator">
<div class="result">wynik</div>
<div class="btn">1</div>
<div class="btn">2</div>
<div class="btn">3</div>
<div class="btn">4</div>
<div class="btn">5</div>
<div class="btn">6</div>
<div class="btn">7</div>
<div class="btn">8</div>
<div class="btn">9</div>
<div class="btn">+</div>
<div class="btn">0</div>
<div class="btn">-</div>
<div class="btn">/</div>
<div class="btn">.</div>
<div class="btn">*</div>
<div class="btn">C</div>
<div class="btn">=</div>
</div>
Apply align-content: flex-start to the flex container.
The default setting is align-content: stretch, which will spread the items across the container. With flex-start, they'll be packed together at the top.
Your code:
.kalkulator {
display: flex;
flex-wrap: wrap;
height: 50vh;
width: 30vw;
margin: 0 auto 0 auto;
border: 2px dashed red;
background-color: yellow;
}
.kalkulator .result {
flex-basis: 100%;
height: 10vh;
background-color: #333;
}
.kalkulator div {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
flex-basis: 33%;
background-color: #666;
border: 1px solid black;
}
.btn:nth-last-child(2),
.btn:nth-last-child(1) {
flex-basis: 50%;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
h1 {
margin: 0 auto 0 auto;
background-color: gray;
text-align: center;
margin-bottom: 5vh;
}
<h1>kalkulator</h1>
<div class="kalkulator">
<div class="result">wynik</div>
<div class="btn">1</div>
<div class="btn">2</div>
<div class="btn">3</div>
<div class="btn">4</div>
<div class="btn">5</div>
<div class="btn">6</div>
<div class="btn">7</div>
<div class="btn">8</div>
<div class="btn">9</div>
<div class="btn">+</div>
<div class="btn">0</div>
<div class="btn">-</div>
<div class="btn">/</div>
<div class="btn">.</div>
<div class="btn">*</div>
<div class="btn">C</div>
<div class="btn">=</div>
</div>
Modified code:
.kalkulator {
display: flex;
flex-wrap: wrap;
height: 50vh;
width: 30vw;
margin: 0 auto 0 auto;
border: 2px dashed red;
background-color: yellow;
align-content: flex-start;
}
.kalkulator .result {
flex-basis: 100%;
height: 10vh;
background-color: #333;
}
.kalkulator div {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
flex-basis: 33%;
background-color: #666;
border: 1px solid black;
}
.btn:nth-last-child(2),
.btn:nth-last-child(1) {
flex-basis: 50%;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
h1 {
margin: 0 auto 0 auto;
background-color: gray;
text-align: center;
margin-bottom: 5vh;
}
<h1>kalkulator</h1>
<div class="kalkulator">
<div class="result">wynik</div>
<div class="btn">1</div>
<div class="btn">2</div>
<div class="btn">3</div>
<div class="btn">4</div>
<div class="btn">5</div>
<div class="btn">6</div>
<div class="btn">7</div>
<div class="btn">8</div>
<div class="btn">9</div>
<div class="btn">+</div>
<div class="btn">0</div>
<div class="btn">-</div>
<div class="btn">/</div>
<div class="btn">.</div>
<div class="btn">*</div>
<div class="btn">C</div>
<div class="btn">=</div>
</div>
It seems too much* for one flexbox. Create the layout with two nested ones: one for the vertical partition of the calculator to the result and the buttons, and another one for the fluid positioning of the buttons within the buttons div:
<div class="kalkulator">
<div class="result">wynik</div>
<div class="buttons">[...]</div>
</div>
.kalkulator {
display: flex;
flex-direction: column;
}
.result {
flex-basis: 10vh;
}
.buttons {
flex-grow: 1; /* Fill the rest */
display: flex;
flex-wrap: wrap;
}
.btn {
flex-grow: 1;
flex-basis: 33%;
justify-content: center;
align-items: center;
display: flex;
}
For placing the buttons under the result box you need a flexbox with a vertical main axis (flex-direction: column). For placing the buttons in a row, a flexbox with a horizontal main axis (the default flex-direction: row).
See the following code, here I removed height: 50vh; property from .kalkulator class:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
h1 {
margin: 0 auto 0 auto;
background-color: gray;
text-align: center;
margin-bottom: 5vh;
}
.kalkulator {
display: flex;
flex-wrap: wrap;
/* height: 50vh; */
width: 30vw;
margin: 0 auto 0 auto;
}
.kalkulator .result {
flex-basis: 100%;
height: 10vh;
background-color: #333;
}
.kalkulator div {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
flex-basis: 33%;
background-color: #666;
border: 1px solid black;
}
.btn:nth-last-child(2),
.btn:nth-last-child(1) {
flex-basis: 50%;
}
<h1>kalkulator</h1>
<div class="kalkulator">
<div class="result">wynik</div>
<div class="btn">1</div>
<div class="btn">2</div>
<div class="btn">3</div>
<div class="btn">4</div>
<div class="btn">5</div>
<div class="btn">6</div>
<div class="btn">7</div>
<div class="btn">8</div>
<div class="btn">9</div>
<div class="btn">+</div>
<div class="btn">0</div>
<div class="btn">-</div>
<div class="btn">/</div>
<div class="btn">.</div>
<div class="btn">*</div>
<div class="btn">C</div>
<div class="btn">=</div>
</div>
Viewport Height (vh): This unit is based on the height of the viewport. A value of 1vh is equal to 1% of the viewport height.
Height of container is 50vh and height of result is 10vh. This leaves 40vh for button panel, or 6.67vh per row. If you want to preserve container height, you can just add height: 6.67vh; to .kalkulator div. This will set button height to fixed value, so there won't be any empty space.

How to force a div to top/bottom of viewport while not taking it out of document flow?

I'm wondering how I can make the blue div 'stick' to the top and bottom of the page (so you can't scroll beyond it) without breaking the document flow (I don't want it to overlap the content div). A crude version is here in the code snippet. If I set 'absolute' on it, it breaks flow and the content goes under the menu. If I leave it relative, you can scroll beyond it (I want it to stay at top: 0, bottom: 0 for a full 100vh with its own scrolling).
Is there something that I'm missing?
* {
box-sizing: border-box;
}
.main {
display: flex;
flex-direction: row;
}
.sideNav {
width: 100px;
height: 100vh;
border: 5px solid red;
}
.sidePanel {
width: 50px;
height: 100vh;
border: 5px solid blue;
}
.content {
display: flex;
flex-direction: column;
flex-grow: 1;
height: 200vh;
margin: auto;
width: auto;
border: 5px solid green;
}
<div class="main">
<div class="sideNav">Side Nav</div>
<div class="content">This is the content area</div>
<div class="sidePanel">Side Panel</div>
</div>
You really can't do it without removing it from the document flow.
But if you know the width of the side panel, you can apply it as a right margin to the content div.
.main {
display: flex;
flex-direction: row;
}
.sideNav {
width: 100px;
height: 100vh;
border: 5px solid red;
}
.sidePanel {
width: 50px;
height: 100vh;
border: 5px solid blue;
position: fixed; /* new */
right: 0; /* new */
}
.content {
display: flex;
flex-direction: column;
flex-grow: 1;
height: 200vh;
margin: auto;
width: auto;
border: 5px solid green;
margin-right: 50px; /* new */
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
<div class="main">
<div class="sideNav">Side Nav</div>
<div class="content">This is the content area</div>
<div class="sidePanel">Side Panel</div>
</div>

How create proper flexbox to make one column inside of content scrollable and another one static?

I want to create a layout where we have a header (responsive, with any height), footer (responsive, with any height), and content that fills the rest of space. Content should have two columns - first(right) that fits the content and second(left) that is very long and should have overflow with y-axis scrolling.
Detailed snipped with HTML and CSS attached.
I have problem with making them work inside of flexible height. I know how to make it work when I have only two columns, but with a responsive footer and header, I have problems.
I also have a code snippet inside of codepen
Thanks in advance for any help :)
html,
body {
height: 100%;
width: 100%;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
}
.column {
background-color: white;
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
color: black;
border: 5px purple solid;
}
.column-with-overflow {
overflow: auto;
max-height: 100%;
flex-grow: 1;
}
.column-with-overflow-content {
height: 1000px;
background-color: blue;
display: flex;
}
.columns {
display: flex;
flex-direction: row;
background-color: yellow;
width: 100%;
max-height: 100%;
}
.content {
background-color: blue;
flex-grow: 1;
}
.box {
text-align: center;
color: white;
display: flex;
justify-content: center;
}
.header {
background-color: green;
height: 60px; // assume that It's not known - any height
}
.footer {
background-color: red;
height: 60px; // assume that It's not known - any height
}
<div class="container">
<div class="box header">Header</div>
<div class="box content">
<div class="columns">
<div class='column column-with-overflow'>
<div class='column-with-overflow-content'>
box 1
</div>
</div>
<div class='column'>box 2</div>
</div>
</div>
<div class="box footer">Footer</div>
</div>
Set a fixed height to your .box.content div element.
And use min-height in .column-with-overflow-content insted of height
html,
body {
height: 100%;
width: 100%;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
}
.column {
background-color: white;
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
color: black;
border: 5px purple solid;
}
.column-with-overflow {
overflow: auto;
max-height: 100%;
flex-grow: 1;
}
.column-with-overflow-content {
min-height: 1000px; /* use min-height */
background-color: blue;
display: flex;
}
.columns {
display: flex;
flex-direction: row;
background-color: yellow;
width: 100%;
max-height: 100%;
}
.content {
background-color: blue;
flex-grow: 1;
}
.box.content { height: 100px; } /* set height to columns container */
.box {
text-align: center;
color: white;
display: flex;
justify-content: center;
}
.header {
background-color: green;
height: 60px; // assume that It's not known - any height
}
.footer {
background-color: red;
height: 60px; // assume that It's not known - any height
}
<div class="container">
<div class="box header">Header</div>
<div class="box content">
<div class="columns">
<div class='column column-with-overflow'>
<div class='column-with-overflow-content'>
box 1
</div>
</div>
<div class='column'>box 2</div>
</div>
</div>
<div class="box footer">Footer</div>
</div>

Centering flexbox content after a linebreak

I am trying to center text inside a parent element of limited width. However the text is set in a large font, which might cause a line-break. However the element line-break does not decrease the width of the element. Is there a way to center a text inside a parent wrapper if the text does not fit?
You can find a failing example in the stack-overflow code sample. The top box has a line-break and should still be centered.
.wrapper {
width: 900px;
margin: 0 auto;
background: lightgrey;
}
.box {
display: flex;
align-items: center;
justify-content: center;
width: 300px;
height: 200px;
border: 1px solid green;
}
.box:nth-child(1) {
background: green;
font-size: 45px;
}
.box:nth-child(2) {
background: orange;
}
<div class="wrapper">
<div class="box"><h3>Lorem Ipsum</h3></div>
<div class="box"><h3>Lorem Ipsum</h3></div>
</div>
Just add the text-align: center;
.wrapper {
width: 900px;
margin: 0 auto;
background: lightgrey;
}
.box {
display: flex;
align-items: center;
justify-content: center;
/* text-align: center; */
width: 300px;
height: 200px;
border: 1px solid green;
}
.box > * {
flex: 0 0 50%;
}
.box:nth-child(1) {
background: green;
font-size: 45px;
}
.box:nth-child(2) {
background: orange;
}
<div class="wrapper">
<div class="box"><h3>Lorem Ipsum</h3></div>
<div class="box"><h3>Lorem Ipsum</h3></div>
</div>
You can use width:min-content; with the first child (https://caniuse.com/#feat=intrinsic-width)
.wrapper {
width: 900px;
margin: 0 auto;
background: lightgrey;
}
.box {
display: flex;
align-items: center;
justify-content: center;
width: 300px;
height: 200px;
border: 1px solid green;
}
.box:nth-child(1) h3 {
width:-webkit-min-content;
width:-moz-min-content;
width:min-content;
border:1px solid;
}
.box:nth-child(1) {
background: green;
font-size: 45px;
}
.box:nth-child(2) {
background: orange;
}
<div class="wrapper">
<div class="box">
<h3>Loreme Ipsum</h3>
</div>
<div class="box">
<h3>Lorem Ipsum</h3>
</div>
</div>

Flexbox body and main min-height

https://jsfiddle.net/vz7cLmxy/
I'm trying to have the body to expand but the min-height does not work. I've read other related topics but can't get my head around it.
CSS and html
body,
html {
padding: 0;
margin: 0;
min-height: 100%;
}
body {
display: flex;
background: #eee;
flex-direction: column;
}
.menu {
background: red;
color: #fff;
padding: 10px;
}
.wrap {
display: flex;
}
.sidebar {
background: #ddd;
width: 300px;
}
.main {
background: #ccc;
flex: 1;
}
.footer {
background: #000;
color: #fff;
padding: 10px;
}
<div class="menu">Menu</div>
<div class="wrap">
<div class="sidebar">Sidebar</div>
<div class="main">Main</div>
</div>
<div class="footer">Footer</div>
Expected result is that main is streched to fill the height if it's less than 100%.
Use flex: 1 on the centered element:
.Site {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.Site-content {
flex: 1;
background-color:#bbb;
}
<body class="Site">
<header>This is the header text ☺</header>
<main class="Site-content">…</main>
<footer>This is the footer text ☻</footer>
</body>
To get min-height with relative units working even in IE11 it needs just a tiny trick.
The nature of min-height is to overwrite the height when height is smaller then min-height. Very clear! But the pitfall is when min-height has a realitve unit (% or vh) and height is not set. Since it is relative it has no basis to relay on.
For all major browsers except Internet Explorer one possibility is to change the unit from % to vh:
body {
min-height: 100vh;
}
For Internet Explorer it needs a height (will be overwritten from min-height):
body {
height: 1px;
min-height: 100vh;
}
or to keep % the rules has to be applied to html too:
html, body {
height: 1px;
min-height: 100%;
}
A cross browser solution for the OP needs height: 1px on body and of course flex-grow: 1 for .wrap to let it grow faster then menu and footer:
body,
html {
padding: 0;
margin: 0;
height: 1px; /* added */
min-height: 100%;
}
body {
display: flex;
background: #eee;
flex-direction: column;
}
.menu {
background: red;
color: #fff;
padding: 10px;
}
.wrap {
display: flex;
flex-grow: 1; /* added */
}
.sidebar {
background: #ddd;
width: 300px;
}
.main {
background: #ccc;
flex: 1;
}
.footer {
background: #000;
color: #fff;
padding: 10px;
}
<div class="menu">Menu</div>
<div class="wrap">
<div class="sidebar">Sidebar</div>
<div class="main">Main</div>
</div>
<div class="footer">Footer</div>

Resources