CSS: Correct behaviour of min-height in combination with margin & padding - css

Currently I'm working on a website for myself. I decided to go for a header content footer design where the footer shall be stuck to the bottom all the time. Hence I set up a wrapper with position: relative, containing the header (#top), content (#middle), and footer (#bottom). Bottom got position: absolute with top: 0.
I've also set height: 100% for html and body and a appropriate padding-bottom for #middle to ensure that my footer won't overlap #middle.
Please find a simplified sample version here: http://www.webdevout.net/test?0w
Here is the CSS in question:
* {
padding: 0;
margin: 0;
}
html, body {height: 100%}
#wrapper {
position: relative;
background-color: #ccc;
min-height: 100%;
}
#middle {
background-color: #900;
padding-bottom: 200px;
}
#top, #bottom {
width: 100%;
height: 200px;
background-color: #bb5;
}
#bottom {position: absolute; bottom: 0;}
Now here's my problem: my understanding of the box-model is, that one should be able to achieve the same (keeping the space for the footer) with margin-bottom instead of padding-bottom for #middle, but margin-bottom isn't applied to it. I've read that min-height doesn't consider padding, border or margin, but the padding is considered here while border and margin aren't.
FF and Chrome show different behaviors when margin-bottom is used instead of padding-bottom for #middle: while Chrome just ignores the margin, FF applies it below #wrapper. My general idea would have been that my container should grow to the total size of its content with min-height, including height + padding + border + margin of #middle, but obviously it just grows to overall size of #top + height of #middle + padding of #middle.
I wonder what is the correct behavior and why padding and margin aren't interchangeable to keep the space for the footer.
While an explanation would be much appreciated, I'd be also thankful for a link to a source which could help me. I'm sorry if this duplicates another post, but I didn't find something (neither here nor via Google) fitting my special problem.
Thank you!

i had faced same problem like u are facing.
You have to use this piece of code.
#middle {
display: table;
margin: 2% auto;
width: 100%;
}
use of display : table works for me to set margin from top and bottom.

Related

Max-height on border-boxed div with padding is not set

We use the percentage trick on paddings to keep aspect ratio to a div when the user scales his window. Like this:
.div {
background: red;
width: 80%;
margin: 0 auto 10px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding-bottom: 20%;
}
Now we would like to be able to set a maximum height to this div. Because the height of the div is determined by the padding on the div we would need the div to be border-boxed. So far so good. When trying to use a min-height on the div, this works. The max-height on this div however does not work for some reason.
.div {
max-height: 60px;
}
I created a fiddle to show you what i mean: http://jsfiddle.net/UxuEB/3/.
Tested this on Chrome, FF and IE. Can somebody tell me what I'm doing wrong or why this doesn't work as expected?
I realize this answer comes incredibly late to the party but I was trying to solve this exact same thing today and this question is the first result in Google. I ended up solving it with the below code so hopefully that will help someone out in the future.
First, add an extra inner div:
<div class="control control-max-height">
<div class="control-max-height-inner">
Max-height
</div>
</div>
And set the padding on that while hiding the overflow on the outer div:
.control {
background: red;
width: 80%;
margin: 0 auto 10px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.control-max-height {
max-height: 120px;
overflow: hidden;
}
.control-max-height-inner {
padding-bottom: 20%;
}
This obviously assumes you're fine with hiding part of the inner element when it overflows. In my case that wasn't a problem because the inner element is just an empty link element to make the whole thing clickable and the outer element just has a centered background image and a border set.
See fiddle: http://jsfiddle.net/UxuEB/7/
The property max-height works on the height of the element and you want to use it on the height and padding-bottom.
I think you are confused by the box-sizing property that it changes the element height to the overal height including the padding top and bottom (also me). But this is not the case as you will see in the jsFiddle example.
An example:
The element with content is 100px in height.
The max-height is set to 50px (element is now 50px in height).
Now we apply the padding-bottom of 100px (more then the height of the element). The padding of 100px is added to the total height of the element making it 150px.
JsFiddle example: clicky
Extending from Mike's answer, the same can be achieved with a single DOM element & a pseudo element, eg.
html:
<div class="le-div"></div>
css:
div.le-div {
max-height: 200px;
/* 👇 only necessary if applying any styles to the pseudo element
other than padding:
overflow: hidden;
*/
}
div.le-div::before {
content: '';
display: block;
padding-bottom: 60%;
}
Min-height property defines the height when height is solely dependent on padding only but max-height does not.
Not sure why but now in 2020, min and max css units does nice job as we need.
.classthatshoulddefineheight {
padding-bottom: min(20%, 60px);
}
So when 20% becomes greater than 60px then it will be limited to 60px (minimum of them).
The limitation to Mike's answer (and this Brad's answer - although Brad's technique can be incorporated to reduce the number of levels of containers) is that it requires overflow: hidden - which in my use-case (and in many others) a significant limitation.
I've reworked his example to work without overflow: hidden; using an additional level and absolute positioning.
http://jsfiddle.net/2ksh56cr/2/
The trick is to add another container inside the inner box, make it absolute positioned and then add the max-height to that container as well:
.inner-inner {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
max-height: 120px;
}
As long as your fine with having some additional DOM-elements, this should work in all scenarios for more or less all browsers.
Try display: flow-root; on the parent container.

How to make a flexible-height modal with fixed header

I've created a really simple modal that allows the content to decrease or expand without running off the page - always leaving 10% margin on the top and bottom. When the page isn't tall enough to contain all the modal content, the entire modal becomes scrollable.
See jsfiddle here
Is it possible, using only CSS, to replicate this behavior but only have the modal body be scrollable, so the header is always fixed. I've tried a few things, but haven't come up with the solution yet. Making the header position: fixed almost works, I have to reposition it over the modal box and then try to add padding to the body so the content is visible under the header, which doesn't budge the scrollbars down. I always prefer to exhaust all the css alternatives before I bind some js to window resize and manually manipulate the body height.
This might be late, but I had to solve a similar issue of fixed header, fluid height, fluid width.
This is how I tackled the issue:
Give your elements a border-box box-sizing. Use a wrapper to center and create a bounding box. This can be a fluid one with min-width and max-width + percentages.
Give your content element an overflow-y of auto and a max-height of 100%;
Use box-sizing:border-box;
The complete code should be something like this:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.modal {
position: fixed;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
}
.wrap {
position: relative;
margin: 0 auto;
display: block;
width: 90%;
/* Change the max-width value on a media query breakpoint to make this example more "responsive" */
max-width: 500px;
height: 90%;
padding: 30px;
}
.modal header {
height: 30px;
padding: 0;
color: #FFF;
background-color: #007;
}
.modal .body {
background-color: #FFF;
max-height: 100%;
overflow-y: auto;
}
http://jsfiddle.net/mariomc/EhR7r/
Applying the max-height and overflow-y settings to .body rather than to .wrap...?
Edit 1:
Nothing's turned up so far within the constraints, which suggests either JavaScript or straying from the constraints (using % for the header height or px margins).
Edit 2:
Here's an initial demo using % for the header height. I added a px min-height to the header tag to prevent the header from almost disappearing on very small screens, at the expense of the top margin (which is reduced on very small screens).
On a screen >= 400px tall, it should work exactly as per the requirements (40px header with 10% height). If the header were reduced in height, it would support slightly-smaller screens (a 30px header with 10% height would support >= 300px screens). Here's a demo with a 30px header.
It's a clumsy solution, but it's the only one that turned up without using JavaScript.
Also, note that I added an h2 and a .content tag and moved the padding:10px; there, to avoid combining % height and padding in the same elements (which leads to a taller height than the % value specified).

How can I prevent fixed width elements from being pushed around?

I currently have a footer that uses a 3 column layout with a fixed center and fluid sides in order to get a nice box shadow effect. When the window is too small however, it pushes the footer to the left, and messes everything up.
I can't seem to figure out how to make sure the footer divs do not get pushed around. I keep running into this problem with my layouts.
The layout I am working on is here, and a screencast showing the problem is here.
The easiest solution is simply to add min-width:980px to #container.
#container {
background: none repeat scroll 0 0 #A8D9A7;
height: 100%;
min-height: 100%;
position: relative;
z-index: 5;
min-width: 980px; /* add this */
}
The 980px figure comes from the width:960px + padding-left:10px + padding-right:10px of the #content-container.
The container element for your main page body (<div id="body">) has computed padding-left of 10px, and the second container element, (<div id="content-container">) adds another padding-left of 10px, meaning your main body is padded from the left by 20px.
Whereas the container for your footer (<div id="footer-container">) has computed padding-left of 0.
If you add this, it will fix your problem. #footer-container {padding: 0 20px;}
Revised as the above solution messed up bottom box-shadow.
In the #footer-left-outer { rule change:
margin-right:470px;
to:
margin-right:-490px;
In the #footer-right-outer { rule change:
margin-left:-470px;
to:
margin-left:-490px;
In the #footer { rule change:
padding: 10px 10px 10px 10px;
width: 940px;
to:
padding: 10px 30px;
width: 980px;
I now understand why you were using the outer-right and outer-left.
I found a different solution that includes the partial box-shadow effect:
http://jsfiddle.net/nottrobin/Cr4NF/10/
It avoids the need for footer-left-outer and footer-right-outer but I'll leave it up to you to decide if it's neater.
It makes use of :before which only works in IE8 onwards:
http://caniuse.com/#search=:before
But then box-shadow doesn't work in IEs < 9 anyway:
http://caniuse.com/#search=box-shadow

Absolute positioned child div expands to fit the parent?

Is there anyway for an absolute positioned child to expand to fill its relative positioned parent? (The height of parent is not fixed)
Here is what i did and it is working fine with Firefox and IE7 but not IE6. :(
<div id="parent">
<div id="child1"></div>
</div>
#parent { position: relative; width: 200px; height:100%; background:red }
#child1 { position: absolute; top: 0; left: 200px; height: 100%; background:blue }
That's easy. The trick is setting top: 0px and bottom: 0px at the same time
Here's the working code
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
#parent {
display: block;
background-color: #ff0;
border: 1px solid #f00;
position: relative;
width: 200px;
height: 100%;
}
#child1 {
background-color: #f00;
display: block;
border: 1px solid #ff0;
position: absolute;
left: 200px;
top: 0px;
bottom: 0px;
}
Check out a working example here http://jsfiddle.net/Qexhh/
If I remember correctly there is a bug with how IE6 handles div height. It will only create the div to the height needed to contain the content within it when height is set to 100%. I would recommend two approaches:
Don't worry about supporting IE6 as it is a dead browser anyway
If that doesn't work, use something like jQuery to get the height of the parent div and then set the child div to that height.
fake it by setting the backgrounds to be the same colour so no-one notices the difference
You can achieve this with setting both the top and bottom attributes of the child.
See how this is done
At the bottom of that article, there is a link to Dean Edwards' IE7 (and IE8) js library that you should include for IE6 visitors. It is a JS library that actually MAKES IE6 behave like IE7 (or 8) when you include it. Sweet!
Dean Edwars' IE7 and 8 JS libraries
As far as I know, there is no way of expanding a parent element around an absolutely positioned child element. By making the child element absolutely positioned your are removing it from the regular flow of page items.
I recently built a 2-column website where the right column was absolutely positioned but the left column was not. If the left column had less content and a smaller height than the right column, the page would cut off the right column since it was absolutely positioned.
In order to resolve this, I had to determine if the height of the right column was greater than the height of the left column and if so set the height of the parent div height to the greater of the two.
Here is my jQuery solution. I'm not much of a coder so feel free to tweak this:
jQuery(function(){
var rightColHeight = jQuery('div.right_column').height();
var leftColHeight = jQuery('div.left_column').height();
if (rightColHeight > leftColHeight){
jQuery('.content_wrap').height(rightColHeight+'px');
}
});

CSS 100% height with padding/margin

With HTML/CSS, how can I make an element that has a width and/or height that is 100% of it's parent element and still has proper padding or margins?
By "proper" I mean that if my parent element is 200px tall and I specify height = 100% with padding = 5px I would expect that I should get a 190px high element with border = 5px on all sides, nicely centered in the parent element.
Now, I know that that's not how the standard box model specifies it should work (although I'd like to know why, exactly...), so the obvious answer doesn't work:
#myDiv {
width: 100%
height: 100%;
padding: 5px;
}
But it would seem to me that there must be SOME way of reliably producing this effect for a parent of arbitrary size. Does anyone know of a way of accomplishing this (seemingly simple) task?
Oh, and for the record I'm not terribly interested in IE compatibility so that should (hopefully) make things a bit easier.
EDIT: Since an example was asked for, here's the simplest one I can think of:
<html style="height: 100%">
<body style="height: 100%">
<div style="background-color: black; height: 100%; padding: 25px"></div>
</body>
</html>
The challenge is then to get the black box to show up with a 25 pixel padding on all edges without the page growing big enough to require scrollbars.
I learned how to do these sort of things reading "PRO HTML and CSS Design Patterns". The display:block is the default display value for the div, but I like to make it explicit. The container has to be the right type; position attribute is fixed, relative, or absolute.
.stretchedToMargin {
display: block;
position:absolute;
height:auto;
bottom:0;
top:0;
left:0;
right:0;
margin-top:20px;
margin-bottom:20px;
margin-right:80px;
margin-left:80px;
background-color: green;
}
<div class="stretchedToMargin">
Hello, world
</div>
Fiddle by Nooshu's comment
There is a new property in CSS3 that you can use to change the way the box model calculates width/height, it's called box-sizing.
By setting this property with the value "border-box" it makes whichever element you apply it to not stretch when you add a padding or border. If you define something with 100px width, and 10px padding, it will still be 100px wide.
box-sizing: border-box;
See here for browser support. It does not work for IE7 and lower, however, I believe that Dean Edward's IE7.js adds support for it. Enjoy :)
The solution is to NOT use height and width at all! Attach the inner box using top, left, right, bottom and then add margin.
.box {margin:8px; position:absolute; top:0; left:0; right:0; bottom:0}
<div class="box" style="background:black">
<div class="box" style="background:green">
<div class="box" style="background:lightblue">
This will show three nested boxes. Try resizing browser to see they remain nested properly.
</div>
</div>
</div>
The better way is with the calc() property. So, your case would look like:
#myDiv {
width: calc(100% - 10px);
height: calc(100% - 10px);
padding: 5px;
}
Simple, clean, no workarounds. Just make sure you don't forget the space between the values and the operator (eg (100%-5px) that will break the syntax. Enjoy!
According the w3c spec height refers to the height of the viewable area e.g. on a 1280x1024 pixel resolution monitor 100% height = 1024 pixels.
min-height refers to the total height of the page including content so on a page where the content is bigger than 1024px min-height:100% will stretch to include all of the content.
The other problem then is that padding and border are added to the height and width in most modern browsers except ie6(ie6 is actually quite logical but does not conform to the spec). This is called the box model. So if you specify
min-height: 100%;
padding: 5px;
It will actually give you 100% + 5px + 5px for the height. To get around this you need a wrapper container.
<style>
.FullHeight {
height: auto !important; /* ie 6 will ignore this */
height: 100%; /* ie 6 will use this instead of min-height */
min-height: 100%; /* ie 6 will ignore this */
}
.Padded {
padding: 5px;
}
</style>
<div class="FullHeight">
<div class="Padded">
Hello i am padded.
</div
</div>
1. Full height with padding
body {
margin: 0;
}
.container {
min-height: 100vh;
padding: 50px;
box-sizing: border-box;
background: silver;
}
<div class="container">Hello world.</div>
2. Full height with margin
body {
margin: 0;
}
.container {
min-height: calc(100vh - 100px);
margin: 50px;
background: silver;
}
<div class="container">Hello world.</div>
3. Full height with border
body {
margin: 0;
}
.container {
min-height: 100vh;
border: 50px solid pink;
box-sizing: border-box;
background: silver;
}
<div class="container">Hello world.</div>
This is one of the outright idiocies of CSS - I have yet to understand the reasoning (if someone knows, pls. explain).
100% means 100% of the container height - to which any margins, borders and padding are added. So it is effectively impossible to get a container which fills it's parent and which has a margin, border, or padding.
Note also, setting height is notoriously inconsistent between browsers, too.
Another thing I've learned since I posted this is that the percentage is relative the container's length, that is, it's width, making a percentage even more worthless for height.
Nowadays, the vh and vw viewport units are more useful, but still not especially useful for anything other than the top-level containers.
Another solution is to use display:table which has a different box model behaviour.
You can set a height and width to the parent and add padding without expanding it. The child has 100% height and width minus the paddings.
JSBIN
Another option would be to use box-sizing propperty. Only problem with both would be they dont work in IE7.
Another solution: You can use percentage units for margins as well as sizes. For example:
.fullWidthPlusMargin {
width: 98%;
margin: 1%;
}
The main issue here is that the margins will increase/decrease slightly with the size of the parent element. Presumably the functionality you would prefer is for the margins to stay constant and the child element to grow/shrink to fill changes in spacing. So, depending on how tight you need your display to be, that could be problematic. (I'd also go for a smaller margin, like 0.3%).
A solution with flexbox (working on IE11): (or view on jsfiddle)
<html>
<style>
html, body {
height: 100%; /* fix for IE11, not needed for chrome/ff */
margin: 0; /* CSS-reset for chrome */
}
</style>
<body style="display: flex;">
<div style="background-color: black; flex: 1; margin: 25px;"></div>
</body>
</html>
(The CSS-reset is not necessarily important for the actual problem.)
The important part is flex: 1 (In combination with display: flex at the parent). Funnily enough, the most plausible explanation I know for how the Flex property works comes from a react-native documentation, so I refer to it anyway:
(...) flex: 1, which tells a component to fill all available space, shared evenly amongst other components with the same parent
To add -webkit and -moz would be more appropriate
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
Frank's example confused me a bit - it didn't work in my case because I didn't understand positioning well enough yet. It's important to note that the parent container element needs to have a non-static position (he mentioned this but I overlooked it, and it wasn't in his example).
Here's an example where the child - given padding and a border - uses absolute positioning to fill the parent 100%. The parent uses relative positioning in order to provide a point of reference for the child's position while remaining in the normal flow - the next element "more-content" is not affected:
#box {
position: relative;
height: 300px;
width: 600px;
}
#box p {
position: absolute;
border-style: dashed;
padding: 1em;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
<div id="box">
<p>100% height and width!</p>
</div>
<div id="more-content">
</div>
A useful link for quickly learning CSS positioning
This is the default behavior of display: block The fastest way that you can fix it in 2020 is to set display: 'flex' of parent element and padding e.g. 20px then all its children will have 100% height relative to its height.
Border around div, rather than page body margin
Another solution - I just wanted a simple border around the edge of my page, and I wanted 100% height when the content was smaller than that.
Border-box didn't work, and the fixed positioning seemed wrong for such a simple need.
I ended up adding a border to my container, instead of relying on the margin of the body of the page - it looks like this :
body, html {
height: 100%;
margin: 0;
}
.container {
width: 100%;
min-height: 100%;
border: 8px solid #564333;
}
<style type="text/css">
.stretchedToMargin {
position:absolute;
width:100%;
height:100%;
}
</style>

Resources