CSS 100% height with padding/margin - css

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>

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.

Position Google Maps with sidebar on right and fixed header on top

I'm looking to position a Google Maps div with a sidebar on the right that displays listings. I want to make it so the window doesn't scroll, and the contents on the page are fluid when resizing the screen.
I have previously attempted to use box-sizing like the following:
#map-wrapper * {
box-sizing: border-box !important;
-moz-box-sizing: border-box !important;
-khtml-box-sizing: border-box !important;
-webkit-box-sizing: border-box !important;
-ms-box-sizing: border-box !important;
}
#map-container {
position: absolute;
width: 100%; height: 100%;
margin: 0;
overflow: hidden;
border-top: 50px solid transparent !important; border-right: 350px solid transparent !important;
}
This starts to become a nightmare when trying to have a scrolling list in the sidebar. Does anyone have a good solution, or am I on the right track with box-sizing?
Box-sizing is purely optional for something like this. There are many ways to go about it, but I have one favored method that is simple and works well in old browsers like IE6.
For the various frames you are trying to create (sidebar and Gmaps/content frame) create a css rule that sets position:absolute; overflow:auto;. Now you can take advantage of a cool trick in CSS absolute positioning. If you set both top and bottom in CSS, the height is automatically calculated. Same goes for widths using left/right. So to make our two divs 100% height set top: 0; bottom:0;.
If you want the sidebar to be 300px wide and anchored to the right, then set width:300px; right:0;. For the content div, set right:300px; left:0;.
Now you need to prevent the body scrollbars from appearing. First of all, you will need to remove the default margin/padding from body by setting them to 0. Also, you need to set html & body to height:100%; (100% equals the viewing area height), other wise they default to auto which is the content's height. It is also wise to add overflow:hidden to body, since some browsers think `body{height:100%;} means they need to show scrollbars.
Here is a quick mockup on JS fiddle showing you how this works.
Elimn's suggestion did not work for me, but the following did (I created a header bar above the Google Map):
body { height: 100%; margin: 0; padding: 0; overflow: hidden; }
#map-canvas { height: 100%; overflow: auto; }
In the body:
<div id="topmenubar" style="position:relative;background:olive;height:40px;top:0;"></div>
<div id="map-canvas"></div>

Wrong height of DIV image wrapper with percentage width values

I want to wrap an image into an html DIV and, since I want this to be fully scalable with the size of the window, I want to set the width of the DIV in percentage as follows:
html
<div id="wrapper">
<img src="http://openclipart.org/people/netalloy/rally-car.svg" />
</div>
css
#wrapper {
position: absolute;
width: 50%;
}
#wrapper img {
width: 100%;
}
The image should determine the height of its container. This is because the image width is set to 100% and the image height is calculated accordingly maintaining the correct aspect ratio.
The result is visible on jsfiddle: http://jsfiddle.net/lorenzopolidori/5BN4g/15/
My questions are:
Why do all modern browsers render the wrapper DIV 5px taller than the inner image?
How can I get rid of this 5px gap, while still setting all the sizes in percentage and without using javascript?
Surprisingly, this happens in Chrome (21.0.1180.89), Firefox (15.0.1) and IE8, while IE7 renders it correctly, matching the height of the DIV with the height of the image.
Check this out :
http://jsfiddle.net/5BN4g/29/
It's a line-height issue :-)
You need :
#wrapper {
width: 60%;
background-color: #aaa;
margin: 50px auto;
line-height:0;
}
#wrapper img {
width:100%;
border: 1px dashed red;
box-sizing:border-box;
}
​
I used box-sizing to make sure the width of the image doesn't overflow the container
................
Hi now add vertical-align:top in your img tag throw css
as like this
#wrapper img {
width: 100%;
border: 1px dashed red;
vertical-align:top; // add this line
}
live demo
OK, fiddling about, I found a good possible solution:
#wrapper img {
display: block;
width: 100%;
border: 1px dashed red;
}
Changing from the default inline display to a block display eliminates the line-height problem straight away.
This approach is also semantically correct because in this case what we really want is a single image wrapped in a DIV without any other elements in it, so the concept of line-height needs to be completely wiped off by displaying the image as a block.
It works on all major browsers: http://jsfiddle.net/lorenzopolidori/5Cpf2/3/
I think you shuold set align property to force browser show correctly img tag.
<div id="wrapper">
<img align="center" src="http://openclipart.org/image/800px/svg_to_png/74557/rally-car.png" />
</div>
DEMO
I think is because it doesn't see as a Table
i added the display:table in your code
And it looks fine now, check the link
Example Display Table
Your issue is that an image -- the <img> tag, to be exact -- is an inline element. All you need to do is set display: block on the image and the extra padding goes away. Demo.

html - how to make a scroll with the width on auto?

I have a div with lots of content in it, and trying to set a width to be 100% of the parent element. This div also uses a padding, so I thought I should be setting the width to auto.
But for some reason it always expands past the parent width. I even have overflow set to scroll.
What I want is the div to have a scroll bar (only horizontal), and its width to fit the parent width.
Does anyone know how I can fix this?
100% width of its parent, with padding:
Given that the padding you mention is applied to the 100% wide element, the problem is within the box model that browsers use. If you apply 100% width and some padding, the element will get width + padding as its complete width, thus causing it to become too large. There are a few ways to solve this:
CSS3 introduces a new property called box-sizing, by setting it to border-box, the padding will be added within the given width of the element, instead of adding to the width causing the element to become "to big". (Notice the lack of support by older browsers).
I believe it would be possible to use left: 0; right: 0; instead of using width: 100%;. In that case you can add padding, without the element becoming to wide.
The second option in practice:
<!-- The markup -->
<div class="parent">
<div class="child">Child</div>
</div>​
/* The CSS */
.parent {
width: 200px;
height: 200px;
position: relative;
background-color: #666;
}
.child {
position: absolute;
left: 0;
right: 0;
padding: 10px;
background-color: #888;
}
​
Here is a working example of the second option: http://jsfiddle.net/mGLRD/
Horizontal scroll-bar:
To get a horizontal scroll-bar, you will have to look in to the overflow-x CSS-property. By setting it to scroll, you will see a disabled scrollbar when there is no content to scroll, so the scrollbar is always visible. Your other option is to set it to auto, where the scrollbar will become visible if needed (may vary between different browsers).
Try:
div#content {
width:auto;
padding:20px;
overflow-x:auto;
}
See my demo: http://jsfiddle.net/HRRsU/3/
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
http://www.w3schools.com/cssref/css3_pr_box-sizing.asp

Setting width/height as percentage minus pixels

I'm trying to create some re-usable CSS classes for more consistency and less clutter on my site, and I'm stuck on trying to standardize one thing I use frequently.
I have a container <div> that I don't want to set the height for (because it will vary depending on where on the site it is), and inside it is a header <div>, and then an unordered list of items, all with CSS applied to them.
It looks a lot like this:
I want the unordered list to take up the remaining room in the container <div>, knowing that the header <div> is 18px tall. I just don't know how to specify the list's height as "the result of 100% minus 18px".
I've seen this question asked in a couple other contexts on SO, but I thought it would be worth asking again for my particular case. Does anyone have any advice in this situation?
You can use calc:
height: calc(100% - 18px);
Note that some old browsers don't support the CSS3 calc() function, so implementing the vendor-specific versions of the function may be required:
/* Firefox */
height: -moz-calc(100% - 18px);
/* WebKit */
height: -webkit-calc(100% - 18px);
/* Opera */
height: -o-calc(100% - 18px);
/* Standard */
height: calc(100% - 18px);
For a bit of a different approach you could use something like this on the list:
position: absolute;
top: 18px;
bottom: 0px;
width: 100%;
This works as long as the parent container has position: relative;
I use Jquery for this
function setSizes() {
var containerHeight = $("#listContainer").height();
$("#myList").height(containerHeight - 18);
}
then I bind the window resize to recalc it whenever the browser window is resized (if container's size changed with window resize)
$(window).resize(function() { setSizes(); });
Don't define the height as a percent, just set the top=0 and bottom=0, like this:
#div {
top: 0; bottom: 0;
position: absolute;
width: 100%;
}
Presuming 17px header height
List css:
height: 100%;
padding-top: 17px;
Header css:
height: 17px;
float: left;
width: 100%;
Use negative margins on the element you would like to minus pixels off. (desired element)
Make overflow:hidden; on the containing element
Switch to overflow:auto; on the desired element.
It worked for me!
Try box-sizing. For the list:
height: 100%;
/* Presuming 10px header height */
padding-top: 10px;
/* Firefox */
-moz-box-sizing: border-box;
/* WebKit */
-webkit-box-sizing: border-box;
/* Standard */
box-sizing: border-box;
For the header:
position: absolute;
left: 0;
top: 0;
height: 10px;
Of course, the parent container should has something like:
position: relative;
Another way to achieve the same goal: flex boxes.
Make the container a column flex box, and then you have all freedom to allow some elements to have fixed-size (default behavior) or to fill-up/shrink-down to the container space (with flex-grow:1 and flex-shrink:1).
#wrap {
display:flex;
flex-direction:column;
}
.extendOrShrink {
flex-shrink:1;
flex-grow:1;
overflow:auto;
}
See https://jsfiddle.net/2Lmodwxk/
(try to extend or reduce the window to notice the effect)
Note: you may also use the shorthand property:
flex:1 1 auto;
I tried some of the other answers, and none of them worked quite how I wanted them to. Our situation was very similar where we had a window header and the window was resizable with images in the window body. We wanted to lock the aspect ratio of the resizing without needing to add in calculations to account for the fixed size of the header and still have the image fill the window body.
Below I created a very simple snippet that shows what we ended up doing that seems to work well for our situation and should be compatible across most browsers.
On our window element we added a 20px margin which contributes to positioning relative to other elements on the screen, but does not contribute to the "size" of the window. The window-header is then positioned absolutely (which removes it from the flow of other elements, so it won't cause other elements like the unordered list to be shifted) and its top is positioned -20px which places the header inside of the margin of the window. Finally our ul element is added to the window, and the height can be set to 100% which will cause it to fill the window's body (excluding the margin).
*,*:before,*:after
{
box-sizing: border-box;
}
.window
{
position: relative;
top: 20px;
left: 50px;
margin-top: 20px;
width: 150px;
height: 150px;
}
.window-header
{
position: absolute;
top: -20px;
height: 20px;
border: 2px solid black;
width: 100%;
}
ul
{
border: 5px dashed gray;
height: 100%;
}
<div class="window">
<div class="window-header">Hey this is a header</div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
Thanks, i solved mine with your help, tweaking it a little since i want a div 100% width 100% heigth (less height of a bottom bar) and no scroll on body (without hack / hiding scroll bars).
For CSS:
html{
width:100%;height:100%;margin:0px;border:0px;padding:0px;
}
body{
position:relative;width:100%;height:100%;margin:0px;border:0px;padding:0px;
}
div.adjusted{
position:absolute;width:auto;height:auto;left:0px;right:0px;top:0px;bottom:36px;margin:0px;border:0px;padding:0px;
}
div.the_bottom_bar{
width:100%;height:31px;margin:0px;border:0px;padding:0px;
}
For HTML:
<body>
<div class="adjusted">
// My elements that go on dynamic size area
<div class="the_bottom_bar">
// My elements that goes on bottom bar (fixed heigh of 31 pixels)
</div>
</div>
That did the trick, oh yes i put a value little greatter on div.adjusted for bottom than for bottom bar height, else the vertical scrollbar appears, i adjusted to be the nearest value.
That difference is because one of the elements on dynamic area is adding an extra bottom hole that i do not know how to get rid of... it is a video tag (HTML5), please note i put that video tag with this css (so there is no reason for it to make a bottom hole, but it does):
video{
width:100%;height:100%;margin:0px;border:0px;padding:0px;
}
The objetive: Have a video that takes the 100% of the brower (and resizes dynamically when browser is resized, but without altering the aspect ratio) less a bottom space that i use for a div with some texts, buttons, etc (and validators w3c & css of course).
EDIT: I found the reason, video tag is like text, not a block element, so i fixed it with this css:
video{
display:block;width:100%;height:100%;margin:0px;border:0px;padding:0px;
}
Note the display:block; on video tag.
I'm not sure if this work in your particular situation, but I've found that padding on the inside div will push content around inside of a div if the containing div is a fixed size. You would have to either float or absolutely position your header element, but otherwise, I haven't tried this for variable size divs.

Resources