CSS 100% height with padding/margin

2018-12-31 17:15发布

问题:

This has been driving me crazy for a couple of days now, but in reality it\'s a problem that I\'ve hit off and on for the last few years: 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.

回答1:

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



回答2:

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 :)



回答3:

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>



回答4:

The better way is with the calc() property. So your case would look like:

#myDiv {
    width: calc(100% - 5px);
    height: calc(100% - 5px);
    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!



回答5:

According the 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>


回答6:

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>



回答7:

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.



回答8:

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.



回答9:

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%).



回答10:

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



回答11:

It\'s 2018 now, the new hot shit should be mentioned here as the question keeps popping up on Google.

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.



回答12:

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;
}


回答13:

  <style type=\"text/css\">
.stretchedToMargin {
    position:absolute;
    width:100%;
    height:100%;

}
</style>


标签: css