Adjust top while maintaining bottom position with CSS - css

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.

Related

Max-width not working on Flexbox item (item is shrinking to width of content)

I have a full viewport width, full viewport height "hero image" on a homepage. I've made this a Flex container. Inside the flex container is one child div (containing a heading). This flex item should be aligned to the bottom of the flex container. It has a max-width and should be horizontally centered inside the parent.
However, the max-width is being ignored. The div is taking the width of its content - the heading. Please see JS Fiddle: https://jsfiddle.net/4h7q6d5x/
As you can see the .main div inside the hero image is taking the width of its content - unlike the .main div below the hero image.
I have looked at various questions, including this one max-width not working on flex item
But adding width:100% to the flex item doesn't work. At smaller viewport sizes the the width and padding don't play nicely and the heading is cropped off the right hand edge.
How do I get max-width to work with Flexbox?
.hero_image {
min-height: 100vh;
background-color:yellow;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.main {
max-width:500px;
margin:0 auto;
padding:0 50px;
background-color:pink;
}
<div class="hero_image">
<div class="main">
<h1>Heading <br>couple of words</h1>
</div>
</div>
<div class="main">
<p>Lots of content</p>
</div>
The default "width" (actually flex-basis) inside flex-containers is auto which makes it only as wide as it's content.
But adding width:100% to the flex item doesn't work. At smaller viewport sizes the the width and padding don't play nicely and the heading is cropped off the right hand edge.
Then I'd suggest a couple of changes. Don't use a flex-column but position your .main div using align-items:flex-end.
Then set the default "width" (actually flex-grow) with flex: 1.
.hero_image {
min-height: 50vh;
/* for example */
background-color: yellow;
display: flex;
align-items: flex-end;
justify-content: center;
}
.main {
flex: 1;
max-width: 50%;
/* for example */
margin: 0 auto;
padding: 0 50px;
background-color: pink;
}
<div class="hero_image">
<div class="main">
<h1>Heading <br>couple of words</h1>
</div>
</div>
<div class="main">
<p>Lots of text</p>
</div>

How set full screen width background on fixed width element?

I have simple structure of element container of dynamic height and fixed width (Markup below). On one hand the element's background should span the whole window width, on the other the children's size must be limited by the container (Desired layout below). The number of children and their sizes (which are equal on the image only for simplicity) are dynamic.
Is that possible without adding extra container? I want to avoid achieving the desired element content width by setting width on the children, because their number is dynamic and the size relationships become complicated to write unless their total width is already limited by container's width.
Here's a pen to experiment;
Markup
<div class="container">
<div class="child">
<div class="child">
...
</div>
.container {
width: <fixed-width>px;
}
Desired layout (the whitespace between children and container is irrelevant)
One route we can take to solve this is by using viewport width on the parent container padding, to force the children into a box that is only 500px wide (as per your codepen).
The important thing to remember when doing this is that box-sizing:border-box; will need to be set on the container, otherwise the padding goes ballistic.
We do this by using calc, vw and padding.
padding: 20px calc(50vw - /*half of container width*/);
Here's the full expanded code of your container on the linked codepen:
.container {
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin-left: auto;
margin-right: auto;
height: 300px;
width: 100%;
padding: 20px calc(50vw - 250px);
background-color: #acffac;
background-size: 100vw auto;
background-position: center top;
box-sizing: border-box;
}
html {
overflow-y:scroll; /* fixes potential calculation errors caused by scroll bar - thanks to Roberts comment */
}
Here's a working version of the codepen, and for the sake of keeping all my eggs in one basket, here's an expandable code snippet:
.container {
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin-left: auto;
margin-right: auto;
height: 300px;
width: 100%;
padding: 20px calc(50vw - 250px);
background-color: #acffac;
background-size: 100vw auto;
background-position: center top;
box-sizing: border-box;
}
.child {
flex: 1 0 auto;
width: 100px;
height: 100%;
background-color: #ff4444;
}
.child+.child {
margin-left: 20px;
}
<div class="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
I will finish off by pointing out that if someone else has a better solution, you may want to look at that for time being instead as there is some issues with using vw inside calc on older versions of Chrome and Safari.
EDIT:
As noted in the comments by Vadim and Robert there are a few things that can cause some snags.
Firstly, assuming you are working with a bare minimum template (i.e. no normalize/reset.css), your body will most probably still have the inherent margins that would mess with this kind of layout. You can fix this with:
body {
margin:0;
}
Secondly, depending on your OS (Yes I'm looking at you Microsoft!) your scrollbars can push your content to the side whilst simultaneously still being included in the calculation for vw.
We can fix this one of two way. The first being an adjustment on the padding calculation to include the scrollbar side, but you would have to write a script to ensure that scrollbar is actually present, and scrollbars differ in sizes (I.E -> 17px, Edge -> 12px).
The other alternative would be to use a custom content scroller, which would do a full overflow:hidden; over the content, thereby removing the scroll bar, before implementing it's own version of a scrollbar (which generally lies on top of the content with a position:fixed;) it.
Using vw and flex we can center the child elements and achieve exactly what you require. I have written a JSfiddle where you can check it out.
Basically what I have done is created a container with display set to flex. Using margin property of the first child element, I have centered all of the other child divs and then the regular properties were added to other divs.
Here's the code
body{
margin: 0;
padding: 0;
}
#container{
display: flex;
width: 100vw;
height: 40vw;
background-color: #333333;
align-items: center;
}
.child{
width: 4vw;
height: 80%;
background-color: red;
margin-right: 10vw;
}
.child:first-child{
margin-left: 28vw;
}
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>

Flexbox overflowing container height in IE11

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/

Why Does My Flexbox Sticky Footer Not Work in Safari?

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.

Prevent CSS3 flex-shrink from crushing content

I'm trying to create a flexible layout in CSS3 with 3 boxes stacked on each other. The boxes are siblings and thus have the same parent element. The height of the first box must fit its content. The height of the following two boxes shall grow to fit their respective content until they're about to overflow their parent. In that case, they shall shrink so that they don't overflow.
The problem is that I can't figure out how to prevent one of the shrinking boxes from becoming crushed if its content is small in relation to the other shrinking box. I want those boxes to shrink down to a certain point where they won't shrink anymore – let's say the equivalent of two rows of text for example. Setting min-width isn't an option because I don't want the boxes to be taller than their content in case the content is only one row for example. If any of the boxes has come to the point where it shall not shrink anymore and the parent can't hold them without overflowing, the parent shall get a scrollbar.
I don't know the content in advance so the layout has to be dynamic. I want to solve this only with CSS, if possible.
Here's an example of the problem where box3 is too small:
p {
margin: 0;
}
.container, .box {
border: 1px solid black;
}
.box {
background-color: white;
margin: 1em;
overflow: auto;
}
#container {
background-color: yellow;
display: flex;
flex-direction: column;
height: 15em;
overflow: auto;
}
#box1 {
flex: 0 0 auto;
}
#box2 {
}
#box3 {
}
<div id="container" class="container">
<div id="box1" class="box">
<p>◼</p>
</div>
<div id="box2" class="box">
<p>◼◻◻◻◻◻◻◻◻◻◻◻◻◻◻◻◻◻</p>
<p>◼◼◻◻◻◻◻◻◻◻◻◻◻◻◻◻◻◻</p>
<p>◼◼◼◻◻◻◻◻◻◻◻◻◻◻◻◻◻◻</p>
<p>◼◼◼◼◻◻◻◻◻◻◻◻◻◻◻◻◻◻</p>
<p>◼◼◼◼◼◻◻◻◻◻◻◻◻◻◻◻◻◻</p>
<p>◼◼◼◼◼◼◻◻◻◻◻◻◻◻◻◻◻◻</p>
<p>◼◼◼◼◼◼◼◻◻◻◻◻◻◻◻◻◻◻</p>
<p>◼◼◼◼◼◼◼◼◻◻◻◻◻◻◻◻◻◻</p>
<p>◼◼◼◼◼◼◼◼◼◻◻◻◻◻◻◻◻◻</p>
<p>◼◼◼◼◼◼◼◼◼◼◻◻◻◻◻◻◻◻</p>
<p>◼◼◼◼◼◼◼◼◼◼◼◻◻◻◻◻◻◻</p>
<p>◼◼◼◼◼◼◼◼◼◼◼◼◻◻◻◻◻◻</p>
<p>◼◼◼◼◼◼◼◼◼◼◼◼◼◻◻◻◻◻</p>
<p>◼◼◼◼◼◼◼◼◼◼◼◼◼◼◻◻◻◻</p>
<p>◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◻◻◻</p>
<p>◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◻◻</p>
<p>◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◻</p>
<p>◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼</p>
</div>
<div id="box3" class="box">
<p>◼◻◻</p>
<p>◼◼◻</p>
<p>◼◼◼</p>
</div>
</div>
IF I understand your question correctly, the flex-shrink property should be what you are looking for.
Set #box1 to flex-shrink: 0
Set #box2 to flex-shrink: 1
Set #box3 to flex-shrink: 1

Resources