I've been trying to learn something about CSS flexboxes, specifically to get a sticky footer working, based off this example.
The layout is 3 basic divs: a header, main content and footer. The main content div is supposed to expand vertically such that the footer is always at the bottom of the page. In Safari, the page loads as expected, but resizing the window vertically does not adjust the height of the layout (i.e. nothing's moving) — if I make the window taller, the extra space in the main content div doesn't change to keep the footer at the bottom, likewise . Resizing the window horizontally does reflow the page properly. Everything does work as expected in Chrome.
The example page works as I would expect, and I've followed the example CSS closely (using Autoprefixer's live demo). Comparing the pages in web inspector, the flexbox CSS appears to be consistent, and the only (seemingly) relevant difference is the live code on the example uses min-height: 100% for the flexbox container, whereas mine (and the example code given) uses min-height: 100vh (using 100% didn't work at all for me).
So my question: what is the example site doing differently that mine isn't, and why? Secondarily, why does min-height work in percentages for one, but only viewport units for another?
My code (also on jsfiddle):
<!DOCTYPE html>
<html>
<head>
<title>Flexbox Header Test</title>
<style type="text/css">
body {
font-family: Avenir, sans-serif;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
padding: 0;
margin: 0;
min-height: 100vh;
}
div {
width: 100%;
}
div p {
margin-left: 1em;
margin-right: 1em;
}
div.header {
background-color: orange;
text-align: center;
}
div.main {
background-color: grey;
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}
div.footer {
color: white;
background-color: blue;
}
</style>
</head>
<body>
<div class="header">
<h1>Header</h1>
</div>
<div class="main">
<p>Lots of text here</p>
</div>
<div class="footer">
<p>Footer text here</p>
</div>
</body>
</html>
Thanks to some help from the developer of the site I took the example from, I discovered the cause of my problems: the html element didn't have any height set, thus the min-height on body didn't have any effect. Setting html { height: 100%; } resulted in the expected behaviour.
I admittedly still don't fully understand the why of what caused the initial layout and horizontal resizing to work, but vertical resizing not to, but this at least solves the problem. There was some suggestion from the developer that Safari has some bugginess related to using vh measurements, so that may be it. If anyone can shed some light on that issue, by all means go for it.
Related
I'm wanting to fit the entire UI on the screen onLoad but my footer is not fixing to the bottom of the view on mobile.
On a desktop web browser, it works perfectly. When I view this on a mobile web browser, the footer is further down the page which makes the page scrollable. It should not scroll, instead, it should fit perfectly inside the viewport.
I've made sure to use the correct meta viewport tag. Included prefixes where I use flexbox. I tried using relative positioning but still not getting the results I want.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
html,
body {
font-family: 'Roboto', sans-serif;
}
.container {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
height: 100%;
min-height: 100vh;
flex-direction: column;
max-width: 420px;
margin: 0 auto;
padding: 1rem 1rem 0 1rem;
}
header {
margin: 2rem 0;
}
main {
-webkit-box-flex: 1;
-moz-flex: 1;
-ms-flex: 1;
-webkit-flex: 1;
flex: 1;
}
footer .btn-group {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
margin-bottom: 1rem;
margin-top: 0.5rem;
}
<head>
<meta charset="UTF-8">
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<header>
<h1 class="title">Title</h1>
</header>
<main>
<div class="list">
<input type="text">
<input type="text">
</div>
</main>
<footer>
<div class="btn-group">
<button class="btn-refresh">
Refresh
</button>
<button class="btn-add">
Add New
</button>
</div>
<button class="btn">Main Action</button>
</footer>
</div>
</body>
On mobile, I'd expect that the footer is fixed to the bottom of the browser viewport, however, the button group is a bit past and a user would need to scroll to see the full group of buttons.
When looking at my codepen version, this works fine. However, when I copy&paste the code to my server the footer does not stay at the bottom.
Is there anything that I am missing?
Note that on some mobile browsers, if an item's height is 100vh you will need to scroll down so see it in its entirety. This is intentional, and it has to do with the visible area changing as you scroll (for example in a lot of mobile browsers like Chrome, the toolbar at the top goes away when you scroll down):
This is completely intentional. It took quite a bit of work on our
part to achieve this effect. :)
The base problem is this: the visible area changes dynamically as you
scroll. If we update the CSS viewport height accordingly, we need to
update the layout during the scroll. Not only that looks like shit,
but doing that at 60 FPS is practically impossible in most pages (60
FPS is the baseline framerate on iOS).
It is hard to show you the “looks like shit” part, but imagine as you
scroll, the contents moves and what you want on screen is continuously
shifting.
Dynamically updating the height was not working, we had a few choices:
drop viewport units on iOS, match the document size like before iOS 8,
use the small view size, use the large view size.
From the data we had, using the larger view size was the best
compromise. Most website using viewport units were looking great most
of the time.
If you're looking for a way to circumvent this behavior, I suggest you read this: The trick to viewport units on mobile.
Try this
.container {
max-height: 100vh;
box-sizing: border-box;
}
Firstly, let me say that unfortunately I do have to support IE11 still and I don't believe this is a duplicate question, although I have found a few that were kinda similar.
I have a simple modal window which contains 3 flexible components in a column, header, footer and main.
The plan is that the outer box should grow as the content grows, until it is 80% of the height of the screen, at which point the middle section of the modal which is set to overflow-y:auto should get a scrollbar and the main modal will not get any taller.
Here is my markup
<div class="modal-wrapper">
<div class="modal">
<div class="modal-header">Header</div>
<div class="modal-main">
<div>Content goes here, could get very long</div>
</div>
<div class="modal-footer">Footer</div>
</div>
</div>
Fairly standard stuff. The modal is set to flex and the header and footer are fixed height. The middle section is set to grow and shrink as necessary. The main thing is that the .modal should never overflow the .modal-wrapper.
I have a jsfiddle set up and it's tested in Chrome, Firefox, Safari and iOS and it's working fine if you drag the bottom right box height up and down you'll see how it is supposed to behave. IE11 though is a mess.
https://jsfiddle.net/jonhobbs/sf6untnt/3/
Now, I have a feeling it may be related to the min-height bug here:
https://connect.microsoft.com/IE/feedback/details/802625/min-height-and-flexbox-flex-direction-column-dont-work-together-in-ie-10-11-preview
but I'm not convinced it's exactly that bug because none of the workarounds for that bug seem to work (e.g. using min-height:1px instead of 0, wrapping in another flexbox etc).
Hopefully somebody on SO can take a look at the jsfiddle and see an obvious problem
Maybe if you make it a flex child and use flex:0 1 80%; , it should fixe your trouble with IE :
example
html, body{
height: 100%;
display:flex;
flex-flow:column;
}
.modal-wrapper{
display: flex;
flex-direction: column;
width: 70%;
margin: 0 auto;
flex:0 1 80%;/* IE gets it , because the flow is column */
max-height:80%;/* others such as FF gets it */
background: white;
}
.modal{
display: flex;
flex-glow: 1;/* doesn't exist */
flex/*-shrink*/: 1; /* good enough */
flex-direction: column;
min-height: 1px;
}
.modal-main{
flex: 1;/* good enough */
min-height: 1px;
overflow-y: auto;
padding: 20px;
}
.modal-header, .modal-footer{
flex-grow: 0;
flex-shrink: 0;
height: 60px;
color: white;
line-height: 60px;
text-align: center;
background: dodgerblue;
}
<div class="modal-wrapper">
<div class="modal">
<div class="modal-header">Header</div>
<div class="modal-main">
<div>This content could get very long so I'm going to put a big long div in it</div>
<div style=" width:100px; height:1000px; background-color:red; opacity:0.1;"></div>
</div>
<div class="modal-footer">Footer</div>
</div>
</div>
https://jsfiddle.net/sf6untnt/7/
I have a problem with a simple container div not stretching to min-height:100% in my angular material project.
I have created a codepen here:
Codepen
The problem is that I have varying amounts of content within the content-holding div (in original project ng-view) and therefore need to have a min-height of 100%-footerHeight-headerHeight to fill the full screen and have a sticky footer at the bottom.
Thanks in advance.
EDIT:
Maybe I wasn't clear enough: I want the footer always to be displayed below the content and in case of very few content it should stick to the bottom. So letting the content-holding div fill up using: min-height: calc(100%-footerHeight-headerHeight) of the height is the idea.
EDIT 2:
I got it working for firefox and chrome with the answers I got here. Unfortunately with the new approach I still face the same problem in safari. Here's a new
Codepen.
DEMO
You should use flex
css
body{
display: flex;
flex-direction: column;
height: 100%;
}
in your html, I removed all styling of height and basically arrived with this structure
<body>
<md-toolbar></md-toolbar>
<div flex>your contents here</div>
<footer></footer>
</body>
angular material have a directive attribute flex which makes the applied element to flex-grow: 1 which basically takes up all the remaining space after its siblings height are placed
more info about flex
The way you presented the problem is great, keep it up.
Add this in your style sheet:
#footer {
background-color: black;
color: white;
width: 100%;
position: absolute;
bottom: 0;
}
Footer will stick at the bottom. Help this hope.
You can use js to solve your problem.
var main = document.getElementById('main');
var content = document.getElementById('content');
var footer = document.getElementById('footer');
var remainHeight = main.offsetHeight - content.offsetHeight - footer.offsetHeight;
document.getElementById('footer').style.marginTop = remainHeight + 'px';
The #main in div has height: 100%.
The #content in div has class ng-view.
You can write it in your controller also.
I finally found a solution (works for all browsers including mobile!) which seems absolutely reasonable and simple. I have the following html structure and css:
html:
<div id='nav'></div>
<md-content scroll flex layout='column'>
<div id='content' ng-view flex>
</div>
<div id='footer'>
<footer>Footer</footer>
</div>
</md-content>
css:
* {
margin: 0;
}
body {
display: flex;
min-height: 100vh;
flex-direction: column;
}
#nav {
z-index: 2;
}
#content {
-webkit-flex: 1 0 auto;
flex: 1 0 auto;
}
I am designing a webpage in which <figure> elements are dynamically added to a flexbox. These figures each contain an image which can be of any size and aspect ratio as well as a <figcaption>. The flexbox has justify-contents: space-between, and it is my intention that it should be populated with an indefinite number of horizontally arranged, evenly-spaced figures. The following code works perfectly on Firefox (at least as far as I can tell):
<html>
<head>
<style>
div {
display: flex;
justify-content: space-between;
}
figure {
background-color: teal;
}
img {
max-width: 25vmax;
max-height: 25vmax;
}
</style>
</head>
<body>
<div>
<figure>
<img src="http://placekitten.com/g/800/600">
<figcaption>
Caption goes here
</figcaption>
</figure>
</div>
</body>
</html>
There is a script to dynamically add new figures, as demonstrated here: http://codepen.io/anon/pen/jEzyyo.
The issue is that to make room for new figures, Chrome shrinks the width of all the figures in the div (though the content of the figures is unchanged, which is what I want), and so the spacing is thrown off and images end up overlapping. How can I get around this?
Instead of
div {
display: flex;
justify-content: space-between;
}
Use this CSS:
div {
display: inline-flex;
justify-content: space-between;
}
A website I'm working on now is meant to replicate a document that you could print. There is a header, a body, and a footer. All three elements use CSS to adjust the margins and height of each one.
The footer is 0.5in high and must end at least 0.5in from the bottom of the page, but cannot exceed that. Based on other word processors, if the footer is larger than 0.5in, the footer moves up on the page so that it maintains that 0.5in border.
This means that the body will shrink, so I've set it up (I think) so that a larger footer will shrink the body which is the expected behavior.
However, what I want is a way for the footer to adjust its position on the page so that it is always at least 0.5in from the bottom of the page.
Note I'd like the solution to work for any number of pages for one document, so I can't use fixed positions.
I'm including my demo code which works as long as the height is small enough.
<div style="height: 9in;
padding-left: 1in;
padding-right: 1in;
padding-top: 0.5in;
padding-bottom: 0.5in;
background-color: #eee;
margin-top: -0.08in;
margin-left: -0.08in;">
<div style="height: 0.5in"> Nick 1 </div>
<div style="max-height: 9in; height: 9in;">I love stuff.</div>
<div style="min-height: 0.5in; height: 0.5in; margin-top: 0.5in;">Footer</div>
</div>
Look into the CSS sticky footer technique.
The priciple is this:
the content has a bottom padding equal to the height of the footer
the footer uses relative positioning
the footer has a top margin equal to it's own (negated) height
The result is an overlap of the footer over the padding of the content. Since the sizes match the overlap makes the footer "stick" to where the content ends.
This is essentially a sticky footer.
The CSS
.wrap {
min-height:100%;
margin-bottom: -.4in; /* same as footer */
}
.push, #footer {
height:.4in;
}
The HTML
<div class="wrap">
<div></div>
<div></div>
<div class="push"></div>
</div>
<div id="footer">
i would suggest you use native javascript or jquery CSS is not a programming language but javascript will give you more functionality for testing for the conditions needed
I don't think what you're looking for can be done with CSS only, at least not until flexbox model is more widely supported. If you're using Chrome 24 or higher you can see the code below in action at http://jsfiddle.net/2late2die/bNJZG/1/
.page {
width:8in;
height:10.5in;
background:#fff;
position:relative;
margin:.5in auto;
box-shadow:rgba(0,0,0,.2) 0 0 .1in;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: flex;
-webkit-flex-flow: column;
-moz-flex-flow: column;
-ms-flex-flow: column;
-ms-flex-direction: column;
flex-flow: column;
}
.page .body {
-webkit-flex: 1 0 auto;
-moz-flex: 1 0 auto;
-ms-flex: 1 0 auto;
flex: 1 0 auto;
}
It basically sets the body of the page to be a flexbox item that stretches to take up the entire vertical space between header and footer. You still however would need to manage the height of the body yourself, because if it gets more than the space left between header and footer it will overflow.