I have a div that is position: fixed; within the viewport. Within this are a series of child elements that use display: flex; and I need a scrollable element to fill 100% of the height of the flexed element. The problem I am having is that because done of the parent elements of the scrollable element have a fixed height, so the scrollable element just pushed the bottom of the flexed element rather than scroll.
Please see the following JSBin example. In this example, the blue block needs to extend to 100% the height of the red block, with the contents of the blue block still being scrollable. Needs to work in IE10+, latest Firefox and Chrome:
https://jsbin.com/terimim/edit?html,css,output
There are two primary issues causing the layout problem. They are each explained here:
Why doesn't flex item shrink past content size?
Chrome / Safari not filling 100% height of flex parent
revised demo
* {
box-sizing: border-box;
min-height: 0;
}
body {
background-color: #eaeaea;
}
#menu {
background-color: #fff;
position: fixed;
top: 20px;
right: 20px;
left: 20px;
bottom: 20px;
padding: 0;
z-index: 12;
height: calc(100vh - 40px);
}
#menu-contents {
display: flex;
flex-direction: column;
height: 100%;
}
#menu-pane-wrapper {
display: flex;
flex: 1;
background-color: #eeffcc;
}
#menu-panes {
flex: 1;
display: flex;
}
.menu-pane {
box-sizing: border-box;
background-color: #ff0000;
width: 20%;
padding: 10px;
display: flex;
}
.menu-pane-overflow {
flex: 1;
overflow-x: hidden;
overflow-y: scroll;
background-color: aqua;
}
.menu-item {
padding: 5px;
}
<div id="menu">
<div id="menu-contents">
<div id="menu-header">HEADER</div>
<div id="menu-pane-wrapper">
<div id="menu-panes">
<div class="menu-pane">
<div class="menu-pane-overflow">
<div class="menu-pane-scroll">
<div class="menu-item">1</div>
<div class="menu-item">2</div>
<div class="menu-item">3</div>
<div class="menu-item">4</div>
<div class="menu-item">5</div>
<div class="menu-item">6</div>
<div class="menu-item">7</div>
<div class="menu-item">8</div>
<div class="menu-item">9</div>
<div class="menu-item">10</div>
<div class="menu-item">11</div>
<div class="menu-item">12</div>
<div class="menu-item">13</div>
<div class="menu-item">14</div>
<div class="menu-item">15</div>
<div class="menu-item">16</div>
<div class="menu-item">17</div>
<div class="menu-item">18</div>
<div class="menu-item">19</div>
<div class="menu-item">20</div>
<div class="menu-item">21</div>
<div class="menu-item">22</div>
<div class="menu-item">23</div>
<div class="menu-item">24</div>
<div class="menu-item">25</div>
<div class="menu-item">26</div>
<div class="menu-item">27</div>
<div class="menu-item">28</div>
<div class="menu-item">29</div>
<div class="menu-item">30</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Related
I have a page I'm trying fill some content with and then the remainder of the page fill with a background color. I've kind of been able to achieve this using min-height: 100vh but the problem is now my page scroll get's extended significantly. Is it possible just to color the visible space on the screen without increasing scrollable area on the page.
Here's a simple example with a jsfiddle:
If you remove the min-height: 100vh from .footer notice that the colored square gets much smaller and now the scroll area isn't very large either. How do I only fill that area that's visible when not using the min-height style.
.body {
margin-left: 50px;
}
.footer {
background-color: grey;
min-height: 100vh;
z-index: -100;
margin-top: -150px;
}
img {
z-index: 100;
margin-left: 200px;
}
h1 {
text-align: center;
}
<div class="body">
<div class="row justify-content-center text-centerr">
<h1>
This is my page heading
</h1>
</div>
<div class="row justify-content-center text-center">
<p>
This is some information about this page.
</p>
</div>
<div class="row justify-content-center text-centerr">
<div class="justify-content-center">
<img src="https://cdn.vox-cdn.com/thumbor/RkBHz5tPuCNQOG0a6FooNwiqQyw=/0x0:939x704/1820x1213/filters:focal(0x0:939x704):format(webp)/cdn.vox-cdn.com/uploads/chorus_image/image/49610677/homersimpson.0.0.jpg"
width="300px"
height="300px"
</div>
</div>
<div class="footer">
<br />
</div>
</div>
This is what I came up with, using flexbox and flex-grow: 1 to force the element to grow and take up the remaining space and flex-shrink: 0 to prevent the img and other elements from shrinking.
I had to add a new class to he footer's parent element, to add the flexbox class to it. note the footer-parent class.
<div class="body">
<div class="row justify-content-center text-center">
<h1>
This is my page heading
</h1>
</div>
<div class="row justify-content-center text-center">
<p>
This is some information about this page.
</p>
</div>
<div class="row footer-parent justify-content-center text-center">
<div class="justify-content-center">
<img src="https://cdn.vox-cdn.com/thumbor/RkBHz5tPuCNQOG0a6FooNwiqQyw=/0x0:939x704/1820x1213/filters:focal(0x0:939x704):format(webp)/cdn.vox-cdn.com/uploads/chorus_image/image/49610677/homersimpson.0.0.jpg" width="300px" height="300px" />
</div>
<div class="footer">
<br />
</div>
</div>
</div>
Here's the CSS
body {
margin: 0;
}
.body {
display: flex;
flex-flow: column nowrap;
margin-left: 50px;
height: 100%;
min-height: 100vh;
}
.footer {
background-color: grey;
flex-grow: 1;
z-index: -100;
margin-top: -150px;
}
.footer-parent {
display: flex;
flex-grow: 1;
flex-flow: column nowrap;
}
img {
z-index: 100;
flex-shrink: 0;
margin-left: 200px;
}
h1 {
flex-shrink: 0;
text-align: center;
}
I noticed that when div has position: fixed and display: flex, it doesn't occupy the full available width like normal divs do.
.container {
display: flex;
background-color: #ddd;
margin-top: 50px;
}
.fixed {
position: fixed;
}
.content {
background-color: #bbb;
flex-grow: 1;
}
<div class="container">
<div>Title</div>
<div class="content">Content</div>
</div>
<div class="container fixed">
<div>Title</div>
<div class="content">Content</div>
</div>
How could I change my CSS so that the second container occupy the full available width like that first one does?
Why? is already answered by Michael_B
... it is out-of-flow ...
What you can also do is to size the fixed element from left and right coordonates instead width:100%; that is more often a trouble maker than helpfull.
If it is a direct-child of body, it can also inherits margins .
.container {
display: flex;
background-color: #ddd;
margin-top: 50px;
}
.fixed {
position: fixed;
left:0;
right:0;
margin-left:inherit;
margin-right:inherit;
}
.content {
background-color: #bbb;
flex-grow: 1;
}
<div class="container">
<div>Title</div>
<div class="content">Content</div>
</div>
<div class="container fixed">
<div>Title</div>
<div class="content">Content</div>
</div>
The first container represents an in-flow block-level element. Such elements are designed to stack vertically. This means they occupy the full width of their parent container.
The second container represents an absolutely-positioned element (fixed positioning is a form of absolute positioning). This means the element is out-of-flow and doesn't take up any space.
Unlike in-flow block-level elements, absolutely-positioned elements are not designed to stack vertically. So there's no automatic full width. The default width and height of an absolutely-positioned element is based on its content. To override default sizing, set your own lengths.
.container {
display: flex;
background-color: #ddd;
margin-top: 50px;
}
.fixed {
position: fixed;
width: 100%; /* new */
/* alternatively, you can use left: 0 and right: 0 */
}
.content {
background-color: #bbb;
flex-grow: 1;
}
<div class="container">
<div>Title</div>
<div class="content">Content</div>
</div>
<div class="container fixed">
<div>Title</div>
<div class="content">Content</div>
</div>
You have to add width: 100%; , otherwise the width will be just as wide as the contents of the element.
Also, you should add html, body { margin: 0; } to avoid the default margins.
BTW: That has nothing to do with display: flex, but only with position: fixed...
html, body {
margin: 0;
}
.container {
display: flex;
background-color: #ddd;
margin-top: 50px;
}
.fixed {
position: fixed;
width: 100%;
}
.content {
background-color: #bbb;
flex-grow: 1;
}
<div class="container">
<div>Title</div>
<div class="content">Content</div>
</div>
<div class="container fixed">
<div>Title</div>
<div class="content">Content</div>
</div>
I have an React application and having a slightly bigger problem with some CSS stuff.
I have an view which is divided in 2 parts. But those two parts are lying in one bigger component. The left part is displaying some contacts and on the right I want to display details of those contacts. Now I want to make the left part scrollable like a list, but the right part just stay fixed on its position. Also the height of the left part should always stay as high as the current screen size. I am using Bulma CSS as my base CSS framework.
This is my HTML:
<div class="pane main-content" id="mainPane">
<div class="contacts-view">
<h1 class="title">My Title</h1>
<div class="">Other Stuff</div>
<div class="columns">
<div class="column is-3">
<div class="columns is-multiline">
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
</div>
</div>
<div class="column is-9"></div>
</div>
</div>
</div>
This is a quick sketch of how it looks:
Current relevant CSS:
.main-content {
background-color: #fff;
padding: 20px;
}
.pane {
position: relative;
overflow-y: auto;
flex: 1;
}
.columns {
margin-left: -0.75rem;
margin-right: -0.75rem;
margin-top: -0.75rem;
}
.column {
display: block;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
-ms-flex-negative: 1;
flex-shrink: 1;
padding: 0.75rem;
}
For better explanation. The component with class column is-3 should be scrollable but all other parts should stay fixed with no scroll.
I tried:
.is-3
overflow:hidden;
overflow-y:scroll;
But I found out that I have to set the height of is-3 because otherwise my screen is just expanded to the bottom. But I can not set a fixed height to it, because my screen size is dynamic and depended on the size of #mainPane. But I can also not set it to 100% because then the screen is also expanded at the bottom. Do you have any suggestions how I can solve this with CSS ?
Thanks in advance :)
You can use flexbox layout.
jsFiddle
body {
margin: 0;
}
.container {
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
background: lightblue;
}
.content {
flex: 1;
display: flex;
min-height: 0; /*ADDED 2021*/
}
.sidebar {
background: lightgreen;
overflow: auto;
}
.main {
flex: 1;
background: pink;
overflow: auto;
}
<div class="container">
<div class="header">header</div>
<div class="content">
<div class="sidebar">
<div style="height:200vh;">sidebar</div>
</div>
<div class="main">
<div style="height:200vh;">main</div>
</div>
</div>
</div>
I've read many posts on flexbox but still have an issue that bugs me.
I want to have a sticky footer using flexbox as per this guide.
But then, inside my page content I would like to have as many nested divs I like and have them taking the same height of the parent.
The problem is, setting height: 100% on each child (as I would do in a non-flexbox scenario) works differently when flexbox is enabled. This results in the children getting more height (overflow the parent).
To make this more clear here's a codepen without flexbox
and a codepen with flexbox
You can see in the flexbox scenario the footer gets the green bakground even if I don't want that.
HTML:
<div class="sticky-footer-container">
<div class="sticky-footer-content">
<div class="page-container">
<div class="main-menu">
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sticky-footer">
Some footer content
</div>
</div>
SCSS:
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
background: silver;
padding: 0;
margin: 0;
}
.sticky-footer-container {
height: 100%;
display: flex;
flex-direction: column;
.sticky-footer-content {
height: 100%;
background: blue;
flex: 1;
div {
height: 100%;
}
.main-menu-selection {
height: 50%;
}
}
}
.some-other-class {
background: green;
}
In order to solve this, ANY nested div has to become a flex-container ?
In other words, is there any way to "stop the flex propagation" at some point of the tree, so all the divs gets the parent height without overflow?
display:flexbox is not really a valid value :)
you need to set height as well and eventually inherit it from html :
.sticky-footer-container {
display: flex;
flex-direction: column;
}
.sticky-footer-content {
flex: 1;
}
/* let's inherit some height to pull the footer down */
html,
body,
.sticky-footer-container {
height: 100%;
margin: 0;
}
.sticky-footer {
display: flex;/* flex item can be flexboxes as well */
background: turquoise;
align-items: center;
justify-content: center;
min-height: 3em;
}
<div class="sticky-footer-container">
<div class="sticky-footer-content">
<div class="page-container">
<div class="main-menu">
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sticky-footer">
Here my footer
</div>
</div>
This question already has answers here:
Absolutely positioned flex item is not removed from the normal flow in IE11
(4 answers)
Closed 6 years ago.
This http://jsfiddle.net/7ra5oL77/ should line up the orange dots horizontally with the text underneath.
The relevant items are:
<div class="draggable ui-widget-content"></div>
and
<div class="item">60°C</div>
This works in Chrome and Edge, but Firefox seem to not use the full width and there is a too big white space on the right side.
Can anyone help me?
The issue that I see is that firefox is recognizing your div.lines as items within the flexbox even though the are position absolute. If you pull them outside of the container or delete them altogether (I don't see their purpose), then you should be fine.
The absolute positioned .lines mess up with the space-around alignment:
#graph-containment-wrapper {
justify-content: space-around;
}
This seems a bug, because the spec says
An absolutely-positioned child of a flex container does not
participate in flex layout.
The justify-content property aligns flex items along the
main axis of the current line of the flex container.
As a workaround, you can use auto margins to achieve the same effect without the interference of absolutely positioned elements:
.draggable {
margin: 0 auto;
}
.lines {
padding: 0px;
margin: 0px;
height: 1px;
background-color: orange;
position: absolute;
}
.draggable {
width: 30px;
height: 30px;
background: orange;
border-radius: 30px;
cursor: n-resize;
top: 200px;
z-index: 1;
border: 0px;
display: flex;
justify-content: center;
align-items: center;
color: white;
margin: 0 auto;
}
.x-axis {
display: flex;
justify-content: space-around;
width: 100%
}
#graph-containment-wrapper {
display: flex;
height: 20rem;
background-color: white;
}
.graph {
-webkit-user-select: none;
}
.draw-area{
width: 100%
}
.hlines{
background-color: lightgray;
width:100%;
height: 1px;
display: flex;
}
.hlines-container{
display:flex;
min-height: 100%;
justify-content: space-between;
flex-direction: column;
padding: 15px;
height: 20rem;
margin-top: -20rem
}
<div class="graph">
<div class="draw-area">
<div id="graph-containment-wrapper">
<div class="draggable ui-widget-content"></div>
<div class="draggable ui-widget-content"> </div>
<div class="draggable ui-widget-content"> </div>
<div class="draggable ui-widget-content"> </div>
<div class="draggable ui-widget-content"> </div>
<div class="lines" id="myline0"></div>
<div class="lines" id="myline1"></div>
<div class="lines" id="myline2"></div>
<div class="lines" id="myline3"></div>
</div>
<div class="hlines-container">
<div class="hlines"></div>
<div class="hlines"></div>
<div class="hlines"></div>
<div class="hlines"></div>
<div class="hlines"></div>
<div class="hlines"></div>
</div>
</div>
<div class="x-axis">
<div class="item">20°C</div>
<div class="item">30°C</div>
<div class="item">40°C</div>
<div class="item">50°C</div>
<div class="item">60°C</div>
</div>
</div>