In the code below, how do I make the article container auto grow to consume the remaining vertical space below it, but the scroll bar to remain only for that element.
In other words, I want only the inside of article to scroll and not the entire browser window.
Is there a pure css solution? Or do I need javascript to detect the size of the browser window and adjust the height property of article dynamically?
html, body {
//height: 100%;
}
#outer_container {
display: flex;
flex-direction: row;
}
#outer2 {
flex: 1 0 auto;
}
#outer2 {
flex: 1 0 auto;
}
#container {
display: flex;
flex-direction: column;
height: 100%;
width: 50%;
background-color: red;
}
#container header {
background-color: gray;
}
#container article {
flex: 1 1 auto;
overflow-y: auto;
height: 0px;
}
#container footer {
background-color: gray;
}
<div id="outer_container">
<div id="outer1">
<h2>Outer 1</h2>
</div>
<section id="container">
<header id="header">This is a header</header>
<article id="content">
This is the content that
<br />With a lot of lines.
<br />With a lot of lines.
<br />This is the content that
<br />With a lot of lines.
<br />
<br />This is the content that
<br />With a lot of lines.
<br />
<br />This is the content that
<br />With a lot of lines.
<br />
</article>
<footer id="footer">This is a footer</footer>
</section>
<div id="outer2">
<h2>Outer 2</h2>
</div>
</div>
http://jsfiddle.net/ch7n6/907/
It was originally based on the answer to this question:
Flexbox and vertical scroll in a full-height app using NEWER flexbox api
You can try setting position:fixed to your outer container (http://jsfiddle.net/ch7n6/909/):
#outer_container{
display:flex;
flex-direction:row;
top:0;
bottom:0;
position:fixed;
}
If it doesn't work for your design, you can change the container dimensions using window.onresize event.
In your code you commented out:
html, body {
//height: 100%;
}
But I think you were on the right track.
By uncommenting that rule, and adding height: 100% to .outer_container, your layout may be complete.
Try this:
html, body {
height: 100%; /* uncommented */
margin: 0; /* removes default margin */
}
#outer_container {
height: 100%; /* new; see details below */
display: flex;
flex-direction: row;
}
#outer2 {
flex: 1 0 auto;
background-color: lightblue; /* just for demo */
}
#outer1 { /* correction to duplicate ID */
flex: 1 0 auto;
background-color: lightgreen; /* just for demo */
}
#container {
display: flex;
flex-direction: column;
height: 100%;
width: 50%;
background-color: red;
}
#container header {
background-color: gray;
}
#container article {
flex: 1 1 auto;
overflow-y: auto;
height: 0px;
}
#container footer {
background-color: gray;
}
<div id="outer_container">
<div id="outer1">
<h2>Outer 1</h2>
</div>
<section id="container">
<header id="header">This is a header</header>
<article id="content">
This is the content that
<br />With a lot of lines.
<br />With a lot of lines.
<br />This is the content that
<br />With a lot of lines.
<br />
<br />This is the content that
<br />With a lot of lines.
<br />
<br />This is the content that
<br />With a lot of lines.
<br />
</article>
<footer id="footer">This is a footer</footer>
</section>
<div id="outer2">
<h2>Outer 2</h2>
</div>
</div>
jsFiddle
To understand how this solution works, and what may have held you up, take a look at these posts:
Working with the CSS height property and percentage values
Chrome / Safari not filling 100% height of flex parent
Related
I am trying to build a web app that uses full-height and full-width for layout, and I've solved some issues, but this last issue has me stumped and I think it's because I could have done this much more elegantly. I do not care about responsive design for this app.
Essentially this is what I'm looking for: A single page that has two columns, where the left column is narrow and fixed-width, and the right column resizes with the viewport. At the top and bottom of both columns are areas that resize to the content in them, which can change. The content in middle of the columns aligns to the top of the container, and scrolls when it overflows the container.
In this diagram, boxes A and D resize to the content, but are fixed at the top of the page. Boxes C and F likewise resize to what's in them, be stay fixed to the bottom of the page. The content in B and E aligns to the top of those containers, but causes a scrollbar to appear if the content exceeds the height of the box. B and E are the only boxes that should ever scroll. D, E, and F resize horizontally when the window size changes horizontally, but A, B, and C do not. The scrollbars appear in the diagram for explanation purposes, but should only appear in the output if the content exceeds the size of the container (ala overflow: auto).
What I'm looking for in terms of markup is something akin to this, which I haven't been able to get to work the way I want:
html,
body {
height: 100%;
margin: 0px;
}
#page {
display: flex;
height: 100%;
}
#sidebar {
flex: 0 1 250px;
display: flex;
flex-direction: column;
}
#main {
flex: 1;
display: flex;
flex-direction: column;
}
#B,
#E {
flex: 1 0 auto;
display: flex;
flex-direction: column;
overflow: auto;
min-height: min-content;
}
#Bscroll,
#Escroll {
flex: 0 1 auto;
}
<div id="page">
<div id="sidebar">
<div id="A"> A </div>
<div id="B">
<div id="Bscroll">
<p>B</p>
<br><br><br><br><br><br><br><br><br><br><br><br>
<p>B</p>
</div>
</div>
<div id="C"> C </div>
</div>
<div id="main">
<div id="D"> D </div>
<div id="E">
<div id="Escroll">
<p>E</p>
<br><br><br><br><br><br><br><br><br><br><br><br>
<p>E</p>
</div>
</div>
<div id="F"> F </div>
</div>
</div>
What's the magic incantation that will get this to scroll vertically and independently in the B and E areas?
The secret sauce for an element to scroll independently, is give it a fixed height then apply overflow : auto or overflow-y : scroll
header {
height :20vh;
background: red;
}
footer {
height :20vh;
background: green;
}
/*
This is where it happen
Fixed height + overflow : auto
*/
article {
height: 60vh;
overflow: auto;
}
p {
height: 80vh;
}
<header> D </header>
<article>
<p>
( E ) start the scroll
<p/>
<h1>TA DA</h1>
</article>
<footer> F </footer>
You need to add this to A,D,C,F:
#A,#D {
position: sticky;
top: 0;
}
#C, #F {
position: sticky;
bottom: 0;
}
Check out the code snippet here
html,
body {
height: 100%;
margin: 0px;
}
#page {
display: flex;
height: 100%;
}
#sidebar {
flex: 0 1 250px;
display: flex;
flex-direction: column;
}
#main {
flex: 1;
display: flex;
flex-direction: column;
}
#B,
#E {
flex: 1 0 auto;
display: flex;
flex-direction: column;
overflow: auto;
min-height: min-content;
}
#Bscroll,
#Escroll {
flex: 0 1 auto;
}
#A,#D {
position: sticky;
top: 0;
}
#C, #F {
position: sticky;
bottom: 0;
}
<div id="page">
<div id="sidebar">
<div id="A"> A </div>
<div id="B">
<div id="Bscroll">
<p>B</p>
<br><br><br><br><br><br><br><br><br><br><br><br>
<p>B</p>
</div>
</div>
<div id="C"> C </div>
</div>
<div id="main">
<div id="D"> D </div>
<div id="E">
<div id="Escroll">
<p>E</p>
<br><br><br><br><br><br><br><br><br><br><br><br>
<p>E</p>
</div>
</div>
<div id="F"> F </div>
</div>
</div>
So lets say I have 3 components: Header, Intro, and MainContent
if I have something like:
<div className='homepage'>
<div id='top'>
<Header />
<Intro />
</div>
<div id='bottom'>
<MainContent />
</div>
</div>
How would I be able to style this so that the header and the intro take up the entirety of the screen on load, and then you have to scroll to reach the MainContent component?
I could I just set bottom padding of the #top to a percentage but that doesn't work for every device, correct?
We can use vh units with Flexbox to easily achieve this. The basic idea is to give the #top a height of 100vh (the full height of the viewport), and then use Flexbox to have the <Intro /> fill the remaining space not taken up by the <Header />. Like this:
#top {
height: 100vh;
display: flex;
flex-direction: column;
}
.intro {
flex-grow: 1;
}
/* Styling CSS - not relevant to solving the issue */
html,
body {
margin: 0;
font-family: Arial;
}
.header {
background-color: black;
color: white;
}
.intro {
background-color: lightgray;
}
.header,
.intro,
.main {
padding: 0.5rem;
}
#bottom {
min-height: 400px;
}
<div className='homepage'>
<div id='top'>
<div class="header">Header</div>
<div class="intro">Intro</div>
</div>
<div id='bottom'>
<div class="main">Main Content</div>
</div>
</div>
I need the element cnt-right to be height 100% of its sibling.
It doesn't have a parent element, only siblings.
Is it possible to accomplish this with CSS? Or do I have to use javascript?
I have this estructure: jsFiddle
.column {
display: block;
min-height: 50px;
background-color: #ccc;
text-align: center;
float: left;
}
.decktop-12 {
width: 100%;
}
.decktop-8 {
width: 66%;
}
.decktop-4 {
width: 33%;
}
.cnt {
background-color: #995595;
}
.cnt-right {
background-color: #559959;
}
<div class="mobile-12 decktop-12 cnt-top column">
Content top
</div>
<div class="mobile-12 decktop-8 cnt column">
Content - main
<br /> <br />
Content - main
<br /> <br />
Content - main
<br /> <br />
Content - main
<br /> <br />
Content - main
</div>
<div class="mobile-12 decktop-4 cnt-right column">
Content - right
</div>
<div class="mobile-12 decktop-12 cnt-bottom column">
Content bottom
</div>
You can use only CSS creating a grid layout, javascript is not necessary: https://css-tricks.com/snippets/css/complete-guide-grid/
This is an example of what you could do:
.grid{
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-areas:
"header header"
"content right"
"footer footer"
}
.header {
grid-area: header;
}
.content {
grid-area: content;
background-color: #995595;
}
.right {
grid-area: right;
background-color: #559959;
}
.footer {
grid-area: footer;
}
.header, .footer{
min-height: 50px;
background-color: #ccc;
}
.grid > * {
text-align: center;
}
<div class="grid">
<div class="header">
Content top
</div>
<div class="content">
Content - main
<br /> <br />
Content - main
<br /> <br />
Content - main
<br /> <br />
Content - main
<br /> <br />
Content - main
</div>
<div class="right">
Content - right
</div>
<div class="footer">
Content bottom
</div>
</div>
You can use css grid or flex displays.
I recommand you to have a look at :
https://css-tricks.com/snippets/css/complete-guide-grid/
https://css-tricks.com/snippets/css/a-guide-to-flexbox
And also at how Bootstrap 4 implemented their grid using flex :
https://getbootstrap.com/docs/4.0/layout/grid/
You will have more control over how your grid behaves and possibilities than with float.
I made you an example with using flex. In this example flex evens the columns height by default and looks similar to code written with float :
<div class="row">
<div class="mobile-12 desktop-12 column c1">
Content top
</div>
<div class="mobile-12 desktop-8 column c2">
Content - main
<br><br><br>
</div>
<div class="mobile-12 desktop-4 column c3">
Content - right
</div>
<div class="mobile-12 desktop-12 column c1">
Content bottom
</div>
</div>
<style>
.row {
display: flex;
flex-wrap: wrap; /* Allow multi-line */
}
.column {
flex-grow: 0; /* Prevents column from auto growing */
flex-shrink: 0; /* Prevents column from auto shrinking */
}
.mobile-12 {
flex-basis: 100%;
}
.desktop-8 {
flex-basis: 66.66666%;
}
.desktop-4 {
flex-basis: 33.33333%;
}
.c1 { background-color: grey; }
.c2 { background-color: purple; }
.c3 { background-color: green; }
</style>
So I was trying to get a header and some content to fit into the screen by having a div #main with height: 100% as a flexbox, just like this:
#main {
height: 150px; /* Using a fixed height here, otherwise the snippet wouldn't work */
}
.flexbox {
display: flex;
flex-direction: column;
}
.header {
flex: 0 1 auto;
border: 2px solid #aa0000;
}
.content {
flex: 1 1 auto;
border: 2px solid #00aa00;
}
.scrollable {
overflow-y: scroll;
}
<html>
<body>
<div id="main" class="flexbox">
<div class="header">
HEADER
</div>
<div class="content scrollable">
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
</div>
</div>
</body>
</html>
So now if #content overflows the height of #main, #content's scrollbar will take over, and the header stays visible. Works like a charm so far.
My problem is now that I need to nest another combination of header and screen fitting content into the outer content, which I tried to solve with another nested flexbox:
#main {
height: 150px; /* Using a fixed height here, otherwise the snippet wouldn't work */
}
.flexbox {
display: flex;
flex-direction: column;
}
.header {
flex: 0 1 auto;
border: 2px solid #aa0000;
}
.content {
flex: 1 1 auto;
border: 2px solid #00aa00;
}
.scrollable {
overflow-y: scroll;
}
<html>
<body>
<div id="main" class="flexbox">
<div class="header">
HEADER
</div>
<div class="content flexbox">
<div class="header">
HEADER
</div>
<div class="content scrollable">
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
</div>
</div>
</div>
</body>
</html>
So basically I want both headers to stay up top now, and have only the inner content box scroll once it overflows. But when it does, the content stretches beyond (?!) #main's height, triggering the browser pages's scrollbar instead of its own one. I suppose the problem may be caused by the outer content box, whose height is only defined by the outer flexbox.
I already had tried a solution where the headers would have absolute positions, but this doesn't quite work out for what I need it. Flexboxes would be just perfect if it wasn't for this problem.
Can anyone help me fix this?
What you ask for is already happening in Chrome. Which makes me think you're developing with FF.
As a side-note, I believe that's a mistake, simply because you're developing for less than 15% of your target audience to only fix browser differences for another 65% of your audience. Luckily for you, they both keep tight to standards and differences are quite few these days.
Another reason why you might prefer Chrome over FF as a development tool is that FF has consistently been 6 months behind regarding dev tools for at least 4 years now. Don't get me wrong, I'm not a big Chrome fan and I fully welcome using FF as browsing device of choice. But, as a development tool, it's just not the best available. And they're both free.
Back to your question, adding overflow-y:auto to .flexbox seems to fix it in FF, too:
#main {
height: 150px; /* Using a fixed height here, otherwise the snippet wouldn't work */
}
.flexbox {
display: flex;
flex-direction: column;
overflow-y: auto;
}
.header {
flex: 0 1 auto;
border: 2px solid #aa0000;
}
.content {
flex: 1 1 auto;
border: 2px solid #00aa00;
}
.scrollable {
overflow-y: scroll;
}
<html>
<body>
<div id="main" class="flexbox">
<div class="header">
HEADER
</div>
<div class="content flexbox">
<div class="header">
HEADER
</div>
<div class="content scrollable">
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br>
</div>
</div>
</div>
</body>
</html>
Note: of course, you'd need to run your code through a prefixer for a wider browser coverage. Mind the "filter" box below it. Set to > 0% for maximum cross-browser compatibility.
This issue affects not only Firefox, also Edge and IE11 overflow the parent.
It's caused by the fact that flex item's min-height* defaults to auto, and as such can't be smaller than its content. (Chrome tries to fix this by itself, hence it works on it, though, IMHO, it shouldn't)
* Very well explained here: The Implied Minimum Size of Flex Items
The affected element is the <div class="content flexbox">, which will overflow because if this.
The solution is to change its min-height to 0, and with that will allow it to shrink past content.
For IE11, see notes/sample below.
Stack snippet
#main {
height: 150px; /* Using a fixed height here, otherwise the snippet wouldn't work */
}
.flexbox {
display: flex;
flex-direction: column;
}
.header {
/*flex: 0 1 auto; default, so not needed */
border: 2px solid #aa0000;
}
.content {
flex: 1 1 auto;
border: 2px solid #00aa00;
min-height: 0; /* Firefox, Edge */
}
.scrollable {
overflow-y: scroll;
}
<div id="main" class="flexbox">
<div class="header">
HEADER
</div>
<div class="content flexbox">
<div class="header">
HEADER
</div>
<div class="content scrollable">
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br> CONTENT
<br>CONTENT<br>CONTENT<br>CONTENT<br> CONTENT
<br>CONTENT<br>CONTENT<br>CONTENT<br> CONTENT
<br>CONTENT<br>CONTENT<br>CONTENT<br>
</div>
</div>
</div>
As IE11 being a lot buggier, the above isn't enough, and there is 2 ways to fix it:
Using flex: 1 1 0%, which will make IE11 believe there is no content, hence will only grow as big as the available space in its parent.
#main {
height: 150px; /* Using a fixed height here, otherwise the snippet wouldn't work */
}
.flexbox {
display: flex;
flex-direction: column;
}
.header {
/*flex: 0 1 auto; default, so not needed */
border: 2px solid #aa0000;
}
.content {
flex: 1 1 0%; /* IE11, changed from "auto" to "0%" */
border: 2px solid #00aa00;
min-height: 0; /* Firefox, Edge */
}
.scrollable {
overflow-y: scroll;
}
<div id="main" class="flexbox">
<div class="header">
HEADER
</div>
<div class="content flexbox">
<div class="header">
HEADER
</div>
<div class="content scrollable">
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br> CONTENT
<br>CONTENT<br>CONTENT<br>CONTENT<br> CONTENT
<br>CONTENT<br>CONTENT<br>CONTENT<br> CONTENT
<br>CONTENT<br>CONTENT<br>CONTENT<br>
</div>
</div>
</div>
Using overflow: hidden (see note at the end)
#main {
height: 150px; /* Using a fixed height here, otherwise the snippet wouldn't work */
}
.flexbox {
display: flex;
flex-direction: column;
}
.header {
/*flex: 0 1 auto; default, so not needed */
border: 2px solid #aa0000;
}
.content {
flex: 1 1 auto;
border: 2px solid #00aa00;
/*min-height: 0; not needed, as overflow has same effect */
overflow: hidden; /* Firefox, Edge, IE11 */
}
.scrollable {
overflow-y: scroll;
}
<div id="main" class="flexbox">
<div class="header">
HEADER
</div>
<div class="content flexbox">
<div class="header">
HEADER
</div>
<div class="content scrollable">
CONTENT<br>CONTENT<br>CONTENT<br>CONTENT<br> CONTENT
<br>CONTENT<br>CONTENT<br>CONTENT<br> CONTENT
<br>CONTENT<br>CONTENT<br>CONTENT<br> CONTENT
<br>CONTENT<br>CONTENT<br>CONTENT<br>
</div>
</div>
</div>
Note, using overflow with a value other than visible (its default), will have the same effect as min-height, where hidden is considered more safe than auto, avoiding future change in behavior to render a scrollbar.
You can fix this by using two height: 0 on the main box and the content box.
html,
body {
height: 100%;
}
.topheader {
background: orange;
width: 90%;
}
#container {
display: flex;
flex-direction: column;
height: 100%;
width: 50%;
background: red;
}
.subcontainer {
display: flex;
flex-direction: column;
flex: 1 1 auto;
height: 0;
width: 90%;
background: blue;
}
#container header {
background-color: gray;
}
#container article {
flex: 1 1 auto;
overflow-y: auto;
height: 0;
opacity: 0.5;
}
#container footer {
background-color: gray;
}
<section id="container">
<div class="topheader">
Top Header
</div>
<div class="subcontainer">
<header id="header">This is a header</header>
<article id="content">
This is the content that
<br />
With a lot of lines.
<br />
With a lot of lines.
<br />
This is the content that
<br />
With a lot of lines.
<br />
<br />
This is the content that
<br />
With a lot of lines.<br />
With a lot of lines.
<br />
This is the content that
<br />
With a lot of lines.
<br />
<br />
This is the content that
<br />
With a lot of lines<br />
With a lot of lines.
<br />
This is the content that
<br />
With a lot of lines.
<br />
<br />
This is the content that
<br />
With a lot of lines
<br />
<br />
This is the content that
<br />
With a lot of lines.
<br />
</article>
<footer id="footer">This is a footer</footer>
</div>
</section>
I have an HTML toolbar with some arbitrary height (which I am not explicitly controlling) and main content div (inside a container div) displayed below the toolbar. The quantity of content inside the main content can vary.
I want if the content's available isn't enough to cover the whole screen then the main content div should cover remaining height available on screen below toolbar. If the content is more than the screen size then it should display a proper vertical scrollbar to display complete content.
my structure is like:
<html>
<body>
<toolbar></toolbar>
<container>
<main div>...</main div>
</container>
</body>
</html>
currently my css for main body and html looks like:
* {
margin: 0;
}
html,
body {
height: 100%;
}
#container{
height: 100%
width:100%
}
#main-div{
// how to make it full screen when there isn't enough content
}
Use Flexbox, where you make the body a flex container with column direction, give the container flex: 1 to fill the remaining height and make that one also a flex container, with row direction, and finally give the main flex: 1 to fill the remain horizontally.
* {
margin: 0;
}
html, body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
}
.container {
flex: 1;
display: flex;
}
main {
flex: 1;
background: lightblue;
}
<div class="toolbar">
toolbar
</div>
<div class="container">
<main>main</main>
</div>
You can use flex with column direction to achieve the desired result
* {
margin: 0;
}
html,
body {
display: flex;
flex-flow: column nowrap;
height: 100%;
}
#container {
height: 100%;
width:100%;
}
#main-div {
flex: 1 1 auto;
background-color: green;
}
<html>
<body>
<toolbar>
Content of toolbar with unknow height and you have no control of it
</toolbar>
<main id="main-div">
Some content <br />
Some content <br />
Some content <br />
Some content <br />
Some content <br />
Some content <br />
Some content <br />
Some content <br />
Some content <br />
Some content <br />
Some content <br />
</main>
</body>
</html>