[css] 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:

Widget

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?

This question is related to css height pixel

The answer is


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;

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'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.


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.


Presuming 17px header height

List css:

height: 100%;
padding-top: 17px;

Header css:

height: 17px;
float: left;
width: 100%;

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

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

_x000D_
_x000D_
*,*:before,*:after_x000D_
{_x000D_
  box-sizing: border-box;_x000D_
}_x000D_
_x000D_
.window_x000D_
{_x000D_
  position: relative;_x000D_
  top: 20px;_x000D_
  left: 50px;_x000D_
  margin-top: 20px;_x000D_
  width: 150px;_x000D_
  height: 150px;_x000D_
}_x000D_
_x000D_
.window-header_x000D_
{_x000D_
  position: absolute;_x000D_
  top: -20px;_x000D_
  height: 20px;_x000D_
  border: 2px solid black;_x000D_
  width: 100%;_x000D_
}_x000D_
_x000D_
ul_x000D_
{_x000D_
  border: 5px dashed gray;_x000D_
  height: 100%;_x000D_
}
_x000D_
<div class="window">_x000D_
  <div class="window-header">Hey this is a header</div>_x000D_
  <ul>_x000D_
    <li>Item 1</li>_x000D_
    <li>Item 2</li>_x000D_
    <li>Item 3</li>_x000D_
    <li>Item 4</li>_x000D_
    <li>Item 5</li>_x000D_
  </ul>_x000D_
</div>
_x000D_
_x000D_
_x000D_


  1. Use negative margins on the element you would like to minus pixels off. (desired element)
  2. Make overflow:hidden; on the containing element
  3. Switch to overflow:auto; on the desired element.

It worked for me!


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