I'm facing a strange issue that might have link with flexbox misbehaving with max-height, but so far I didn't find any pure css solution.
I made a plunker to summarize the problem. If you resize your window to reduce its height, at some point you should have a scrollbar in the first block, but if you get back to a higher height, even if there is enough space, the scrollbar won't disappear unless you put your mouse over it (which feels very bugy) : https://plnkr.co/edit/VsJ7Aw8qZdSM1iJeL7Bj?p=preview
I have a main container (in flex) containing 2 blocks (also in flex).
The main container has its height set to 100%, allowing it to resize itself following the window size.
Both children have a fixed content and an overflow-y set to auto.
The first child has a max-height in % to let more height to the second child.
The issue seems to come from this max-height rule. If you remove it, then there's no problem, but I need this max-height...
I don't want to use something like:
.max { flex: 1 1 auto; }
.all { flex: 3 1 auto; }
because it would make my first block higher than its content depending on the window size. I want the first block to have at most its content height.
So my question is: Is it an implementation issue in many browsers (maybe all, but I only tested it in Chrome, IE10 and IE11), or is something wrong in my logic ?
Thank you.
UPDATE: I used a fixed height for my content in this example, but in my project it's a list of n elements in it. So I can't really set my max-height with px value.
UPDATE2: I can't use vh in .max max-height property because it takes 100vh as 100% of viewport height (basically your browser window height). But in my context, .main is already in other containers. Those containers have already their heights defined and are smaller than my window height.
/* Styles go here */
html {
height: 100%;
}
body {
height: calc(100% - 16px);
}
.main {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
.max,
.all {
display: flex;
flex-direction: column;
width: 100%;
overflow-y: auto;
}
.max {
flex: 0 1 auto;
min-height: 103px;
max-height: 40%;
background-color: green;
}
.all {
flex: 2 1 auto;
min-height: 235px;
background-color: blue;
}
.content {
flex: 0 0 auto;
box-sizing: border-box;
height: 200px;
margin: 5px;
border: 1px dashed black;
background-color: white;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="main">
<div class="max">
<div class="content"></div>
</div>
<div class="all">
<div class="content"></div>
</div>
</div>
</body>
</html>
It is a bug, in Chrome, a test in FF and Edge, it works fine.
Since you use full viewport height, change the max-height: 40%; to max-height: 40vh;.
Another way, as in below sample, is to change the 100% in height: 100% to 100vh.
I guess this works better because viewport units like vh is a fixed unit, which percent is not.
Plnkr demo: https://plnkr.co/edit/66W4a2lOI58XLudCmkw9?p=preview
html {
height: 100vh;
}
body {
height: calc(100vh - 16px);
}
.main {
display: flex;
flex-direction: column;
height: 100vh;
width: 100%;
}
.max,
.all {
display: flex;
flex-direction: column;
width: 100%;
overflow-y: auto;
}
.max {
flex: 0 1 auto;
min-height: 103px;
max-height: 40%;
background-color: green;
}
.all {
flex: 1 1 auto;
min-height: 235px;
background-color: blue;
}
.content {
flex: 0 0 auto;
box-sizing: border-box;
height: 200px;
margin: 5px;
border: 1px dashed black;
background-color: white;
}
<div class="main">
<div class="max">
<div class="content"></div>
</div>
<div class="all">
<div class="content"></div>
</div>
</div>
Yes it feels buggy. If you increase the height of the window the height of the first box does not get updated unless:
you decrease the height again
"put your mouse over it" (did not quite get your meaning here)
IMHO this is a browser bug.
If you set flex-grow to anything greater 0 for the first box, the height gets updated correctly, if you increase the height of the window (as you would expect) But using flex-grow isn't an option as the box could potentially grow bigger than its content.
Rather than using max-height:40% you should use the exact same height as you use for .content and use flex-grow: 1 as well to circumvent the "browser bug"
Related
I have this code:
html,
body,
#container {
width: 100%;
height: 100%;
}
#container {
display: flex;
background: #ddd;
}
#width {
width: 200px;
height: 100%;
resize: horizontal;
overflow: hidden;
background: #eee;
}
#remaining {
flex-grow: 1;
overflow: scroll;
}
#resize {
width: 200px;
height: 200px;
resize: both;
overflow: hidden;
background: #ccc;
}
<!DOCTYPE html>
<html>
<body>
<div id="container">
<div id="width">Width</div>
<div id="remaining">
<div id="resize">Resize</div>
</div>
</div>
</body>
</html>
Here is what I am trying to make:
You can resize #width
You can resize #resize
The issue is that when I resize #resize, #width shrinks to make room for it.
What I am looking for is when I resize, #remaining shows a scroll bar, and doesn't resize anything else.
I believe that this is happening because #remaining doesn't have a width property, but instead flex-grow. And so it allows it to vary in width, because it doesn't have a set width.
I am looking for a pure HTML/CSS answer, but JavaScript would work too. (of course as long as it is reliable, won't break, and doesn't massively slow down execution using methods such as setInterval)
I also do want to say that I am using a flex layout on #container only for the purpose of making #remaining take up all of the remaining space, and if display: flex is removed, it would still work with the full code that I have.
If you abandon the flex:grow and instead calculate the width of remaining in the css it works.
.remaining{
width: calc(100% - 200px);
overflow-x: auto;
}
With a fiddle
I'm using the following HTML
<div className="App">
<div className="AppMenu">
Menu
</div>
<div className="AppContainer">
Test
</div>
</div>
and this CSS:
.App {
min-height: 100vh !important;
max-height: 100vh !important;
height: 100vh !important;
background-color: red;
}
.AppMenu {
background-color: blue;
position: sticky;
top: 0px;
width: 100%;
font-size: 1.3em;
}
.AppContainer {
background-color: green;
}
how can I set / calc AppContainer size to take all heigh => 100vh-(AppMenu height)
with CSS (or js) ?
You already using the full height of a screen with 100vh. There is no need to use a nuke like !important which nearly always just mask the issue instead of solving it. Also min-height: 100vh; + max-height: 100vh; can be considered as bad coding. In this case you want a definite height of 100vh which is done by height: 100vh;. So you having 3 lines of code where you actually only would need 1.
The issue that you get a scrollbar and the screen is overflowing is caused by the default body margin. The element will be 100vh tall and use the default body amrgin which will cause an document height of more then 100vh. Therefor simply reset the default body amrgin to 0 with: body { margin: 0; }
However with that soultion you will have a potencial overflow issue. So you should either set an overflow rule to the container or use min-height instead.
To have the the AppContainer fill the remaining height there are multiple ways to solve it. The easiest way to solve it would be the sue of a CSS-Grid with grid-template-rows: min-content auto;. That way, the Menu will take up as much space as needed and the remining height will be used be the AppContainer.
body {
margin: 0;
}
.App {
height: 100vh;
background-color: red;
display: grid;
grid-template-rows: min-content auto;
}
.AppMenu {
background-color: blue;
position: sticky;
top: 0px;
font-size: 1.3em;
}
.AppContainer {
background-color: green;
}
<div class="App">
<div class="AppMenu">
Menu
</div>
<div class="AppContainer">
Test
</div>
</div>
Last but not least. for HTML you have to use class not className which would be invalid HTML as this attribute doesnt exist.
These lines make no sense. This can be removed:
max-height: 100vh !important;
height: 100vh !important;
To stretch .AppContainer to the full free height, use rule flex: 1:
.AppContainer {
...
flex: 1;
}
And for the .App, set the flex rules. Like this:
.App {
...
display: flex;
flex-direction: column;
}
Flex has very good browser support.
Do you need such a result?
.App {
min-height: 100vh !important;
background-color: red;
display: flex;
flex-direction: column;
}
.AppMenu {
background-color: blue;
position: sticky;
top: 0px;
width: 100%;
font-size: 1.3em;
}
.AppContainer {
background-color: green;
flex: 1;
}
<div class="App">
<div class="AppMenu">
Menu
</div>
<div class="AppContainer">
Test
</div>
</div>
I'm trying to achieve a website design which basically has two parts. The top-part, where the menu of the site is and the content-part, with the information.
.wrap {
position: absolute;
width: 100%;
height: 100%;
}
.box {
display: flex;
flex-direction: column;
height: 100%;
}
.top {
flex: 0 1 auto;
}
.content {
flex: 1;
position: relative;
height: 100%;
}
<div class="wrap">
<div class="box">
<div class="top"></div>
<div class="content"></div>
</div>
</div>
The menu-div should be as big as needed for the menu-content to be displayed and the content-div should fill the rest of the site. Both together should fill 100% in width and 100% in height.
So, this construct works fine on desktop PCs, however - on mobile browsers for Chrome, Firefox, and Safari, the site's height gets extended by the menu's height.
The content is at 100% plus the menu. Can someone please explain to me what I'm doing wrong here?
The Basics
In order to give elements percentage heights, their parents need a defined height. What can be confusing, is that these parents include <html> and <body> Consider this example:
html,body {
height: 100%;
margin: 0;
}
div {
height: 100%;
background: lightgreen;
}
<div></div>
Here the <html>, <body> and <div> elements have both been given height: 100%. This trickles down to each child element:
<html> is 100% of the browser viewport
<body> is 100% of its <html> parent
<div> is 100% of its <body> parent
We can simplify this and give the <body> element 100% height using a viewport height unit. This reduces complexity as we no longer need to worry about <html>. Consider this example:
body {
height: 100vh;
margin: 0;
}
div {
height: 100%;
background: lightgreen;
}
<div></div>
Here the <body> takes up 100% of the viewport height and its children can be given percentage heights. We don't need to define a height for <html>.
What You Want to Achieve
With this in mind, we can strip your example down to the basics. Here is exactly what you have described using as few elements as needed:
The <body> can be the flex container. It gets:
display: flex and flex-direction: column
margin: 0 to remove the default body margin.
height: 100vh to stretch it to 100% of the viewport height.
The <div class="top"> is your header that will contain your menu. We don't need to give it a flex property as it will shrink to fit its contents with the initial flex values it is given.
The <div class="content"> is given flex: 1 to grow and fill the rest of the available space.
body {
display: flex;
flex-direction: column;
height: 100vh;
margin: 0;
}
.top {
background: pink;
}
.content {
flex: 1;
background: lightgreen;
}
<div class="top">Menu Content<br>Menu Content<br>Menu Content</div>
<div class="content"></div>
I have 2 divs that are placed on top of each other. For purposes of alignment, I am using display: flex and flex: column on the div containing these two divs. However, the first div uses the "height 0 padding" trick for videos. The problem I'm having, is that when using flex: column and change the width of the screen, the height doesn't change (and I want the height to change so that it matches the ratio for the video). What ends up happening is that the div stays the same, and the video shrinks within it and it looks ugly because there is extra background.
Plunker: https://plnkr.co/edit/TaeF5f8VufJWPU3GRZPr?p=preview
(in short, I want it such that when I change the width of the browser, the red div's height gets smaller)
CSS
/* Styles go here */
body {
height: 100%;
}
.container {
height: 80vh;
display: flex;
flex-flow: column;
}
.video {
flex: none;
height: 0;
padding-bottom: 30%;
background-color: red;
width: 80%;
}
.next-content {
flex: 1 0 auto;
width: 80%;
background-color: blue;
}
HTML:
<body>
<h1>Hello Plunker!</h1>
<div class="container">
<div class="video"></div>
<div class="next-content"></div>
</div>
I want to build a column layout with a menu, then a header, then a content container using flexboxes.
I know how to build it in other techs using fixed sizes, calc etc... But have troubles with flexboxes.
Here is a JsFiddle
I have this:
<div class="layout">
<div class="menu">
Menu
</div>
<div class="header">
Header
</div>
<div class="content">
<div class="scrollable-content">
...
</div>
</div>
</div>
.layout {
overflow: hidden;
border: solid;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.menu {
overflow: hidden;
border: solid red;
flex-grow: 0;
flex-shrink: 0;
}
.header {
overflow: hidden;
border: solid green;
flex-grow: 0;
flex-shrink: 0;
}
.content {
overflow: hidden;
border: solid blue;
flex-grow: 1;
flex-shrink: 1;
}
.scrollable-content {
overflow: auto;
height: 100%;
width: 100%;
}
As you can see on the JsFiddle, with this code, the .scrollable-content is actually never scrollable, because even while using height: 100% it becomes much larger than his parent div. How can I constrain that div's height to the parent's height?
Note: I know I could put the overflow: auto to the parent .content directly, but for reasons specific to my app I really don't want to: please only submit solutions that do not modify the html structure or change the scrollable container because I already know these solutions. I'm more interested to learn why my approach did not work and how it could be fixed (or not?)
Obviously the content that can be scrolled has a dynamic height and is not a fixed value of 450px like in my JsFiddle.
You could remove height: 100% from .scrollable-content, and then change the display of .content to flex:
Updated Example
.content {
overflow: hidden;
border: solid blue;
flex-grow: 1;
flex-shrink: 1;
display: flex;
}
.scrollable-content {
overflow: auto;
width: 100%;
}
You're missing a height: 100% on .content.
Since you're using percentage heights, you need to specify a height for all parent elements of the .scrollable-content.
For a more detailed explanation see: Working with the CSS height property and percentage values
You are almost there.
.content {
overflow: hidden;
border: solid blue;
flex-grow: 1;
flex-shrink: 1;
height:450px; //adjust accordingly.
}
The scroll activates once a height a limited height has been reached. In your case since you have the scrollable area limited to the parent's (content) height, you did right by giving it height: 100%....but....100% of what?
So, all you need is give the content class a stopping point. change the 450px to whatever is more suitable. If you are trying to cover for a gap below that content then the next item should be positioned absolute bottom. (just in case that is what you are tying to get to) I've seen this approach many times and that is usually what follows :)
Here is your updated jfiddle