14

I'm trying to fill the center cell of a table with a div element. For the purposes of illustrating the problem, the div is styled with a red background. It seems to work in Chrome, but not IE. In the fiddle below, IE is setting the height of the div to the minimum height necessary to contain its content. In tinkering around with this problem with different CSS settings, I managed to get IE to interpret "height: 100%"; as "the height of the browser window". However, as the question states, I want IE to interpret it as the height of the td cell. Any ideas?

http://jsfiddle.net/UBk79/

CSS:

*{
    padding: 0px;
    margin: 0px;
}
html, body{
    height: 100%;
}
#container{
    height:100%;
    width: 100%;
    border-collapse:collapse;
}
#centerCell{
    border: 1px solid black;
}
#main{
    height: 100%;
    background-color: red;
}

HTML:

<table id="container">
  <tr id="topRow" height="1px">
    <td id="headerCell" colspan="3">
      TOP
    </td>
  </tr>
  <tr id="middleRow">
    <td id="leftCell" width="1px">
      LEFT
    </td>
    <td id="centerCell">
      <div id="main">CENTER</div>
    </td>
    <td id="rightCell" width="1px">
      RIGHT
    </td>
  </tr>
  <tr id="bottomRow" height="1px">
    <td id="footerCell" colspan="3">
      BOTTOM
    </td>
  </tr>
</table>
Craig
  • 555
  • 1
  • 4
  • 11
  • Are you using tables for laying out the webpage? – cronoklee Oct 30 '13 at 15:24
  • Yes. I spent all day yesterday trying to invent/find a CSS solution that achieved the goal above. The closest thing I found was this answer to a different StackOverflow question: http://stackoverflow.com/a/19110204/2897709 As you can see, it uses the CSS table display properties, but it breaks down when you try to have some of your "cells" span multiple "columns", because apparently there is no CSS analog to the colspan attribute. – Craig Oct 30 '13 at 21:48
  • The other CSS solutions I found or thought of either (a) require specifying the height of the footer, or (b) don't keep the footer at the bottom of the window when the content is shorter than the height of the window, or (c) have the footer overlapping the content when the content is taller than the height of the window, or (d) require the browser to render some or all of the DOM, then run some javascript, then re-render the page. The table layout was the first solution I found that didn't have any of those problems, at least in Chrome. I can't quite seem to make it work in IE though.... – Craig Oct 30 '13 at 21:57
  • **2018 Update**: It looks like it's working now in Chrome, Firefox, IE11, and Edge. (Firefox required the `height: 100%;` addition suggested by @cloudpta.) I guess at some point IE changed its algorithm to match the others. I haven't tested older versions of IE to see exactly when the change happened. – Craig May 17 '18 at 21:56

6 Answers6

24

I did some more research on this and collected some info that might come in handy to others trying to solve similar problems. The CSS spec says the following three things that I think are important:

First, re: specifying the height (of a div) as a percentage:

The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.

http://www.w3.org/TR/CSS21/visudet.html#the-height-property

... a height of 'auto' won't fill the cell unless the content is taller than the cell's minimum height. But if we try to explicitly set the height of the containing cell or row, then we run into the following problem:

CSS 2.1 does not define how the height of table cells and table rows is calculated when their height is specified using percentage values.

http://www.w3.org/TR/CSS21/tables.html#height-layout

Since the spec doesn't define it, I guess it's not too surprising that Chrome and IE choose to calculate it differently.

Alternatively, (as xec indirectly pointed out) trying to use relative positioning has the following spec problem:

The effect of 'position:relative' on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption elements is undefined.

www.w3.org/TR/CSS21/visuren.html#propdef-position

So I've concluded there's probably not a pure CSS way to solve the problem that one can reasonably expect to work on most browsers.

At first, I thought, "Wow, the CSS spec is pretty shoddy and incomplete for leaving all this stuff undefined." As I thought about it more, though, I realized that defining the spec for these issues would a lot more complicated than it appears at first. After all, row/cell heights are calculated as a function of the heights of their content, and I want to make the height of my content a function of the row/cell height. Even though I have a well-defined, terminating algorithm for how I want it to work in my specific case, it's not clear that the algorithm would easily generalize to all the other cases that the spec would need to cover without getting into infinite loops.

Craig
  • 555
  • 1
  • 4
  • 11
  • 2
    +1 for sharing your conclusions. Hopefully CSS will get better at layout in the future with additions like flexbox and/or css grid. – xec Nov 11 '13 at 09:04
  • I'm have a hard time seeing how setting the height of an element to a percentage of it's parent's height (explicitly set or not) would cause infinite loops? There are very clear ways to make that happen and it's not arcane knowledge by a long shot. The only thing that is arcane knowledge is why this feature isn't supported by the CSS spec. – Slight Apr 15 '15 at 21:29
  • If the cell height is a function of the height of the content, you can't make the content height a function of the cell height. It's circular logic. One could add some additional complexity to the spec to deal with those cases, but as you stated there are multiple ways to make it happen, and it's not obvious which way would be best, or even that there is a single best way to make it happen. It gets messy. Anyway, I'm just guessing about why it's not defined. I wasn't on the CSS spec committee. – Craig Apr 17 '15 at 05:02
10

Just set the table cell to: position:relative and the div to:

position:absolute;
top:0;
left:0;
width:100%;
height:100%;

Edit 2017: DEMO BELOW:

Note how you cannot see the red td because the yellow div covers it entirely...

#expandingDiv {
  position: absolute;
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
  background: yellow;
}
<table style="width: 120px">
  <tr>
    <td style="background: blue">blue&nbsp;td</td>
    <td style="background: green">green&nbsp;td</td>
  </tr>
  <tr>
    <td style="background: red; position: relative">
      <div id='expandingDiv'> yellow div </div>
    </td>
    <td style="background: orange">
      Some longer text which makes the bottom two tds expand dynamically.
    </td>
  </tr>
</table>
cronoklee
  • 6,482
  • 9
  • 52
  • 80
  • 2
    That won't work without additional markup. Read more at http://css-tricks.com/absolutely-position-element-within-a-table-cell/ – xec Oct 30 '13 at 14:15
  • 2
    I already read that page. Despite the answer having been accepted, it is not correct, as Jason pointed out in his second comment on the accepted solution. The lack of proper background color is evidence that the solution proposed doesn't work. Thanks for the attempt, though. – Craig Oct 30 '13 at 14:28
  • Updated answer with an example – cronoklee Oct 27 '17 at 17:22
2

Although I liked Craig's answer and will not use the approach in this answer myself, I did get quite far with this jsFiddle.

It relies on a hack, however: Setting height: 1px on the table. It works in Chrome, FF, IE11 and Edge (all that I tested), but Chrome starts misbehaving in edge cases. See the fiddle. Here are the interesting bits:

table {
    width: 100%;
    /* Whý does this make it work? */
    height: 1px;
}

td {
    border: 10px solid blue;
    height: 100%;
}

#container {
    width: calc(100% - 20px);
    height: calc(100% - 20px);
    border: 10px solid black;
}

Too much of a hack-smell to me.

Peter V. Mørch
  • 13,830
  • 8
  • 69
  • 103
  • 1
    I think this works by making the table (and its components) have an explicitly-defined height, which allows the `100%` to be relative to it. – SLaks Sep 11 '17 at 19:59
1

have you tried changing css to:

#centerCell{
    border: 1px solid black;
    height:100%;
}

seems to work for me on edge, firefox and chrome

cloudpta
  • 134
  • 1
  • 6
  • **2018 Update**: It looks like it's working now in Chrome, Firefox, IE11, and Edge. (Firefox required the `height: 100%;` addition suggested by @cloudpta.) I guess at some point IE changed its algorithm to match the others. I haven't tested older versions of IE to see exactly when the change happened. – Craig May 17 '18 at 21:56
-1

Simply set the line height of the div; as long as its display is still a block level element. There is no need for relative or absolute positioning or hard coding of the height at the div level or any of its parents. Works in IE 8+, Firefox, and Chrome.

Example:

line-height: 50px;
// or
line-height: 2em;
TugboatCaptain
  • 4,150
  • 3
  • 47
  • 79
-1

Here's a jsfiddle: https://jsfiddle.net/55cc077/pvu5cmta/

CSS height: 100% only works if the element's parent has an explicitly defined height. This jQuery sets the table cell height in the first column.

<script type="text/javascript">
    $(function(){
    $('.myTable2 tr').each(function(){
    var H1 = $(this).height(); // Get the row height
    $(this).find('td:first').css({'height': H1 + 'px', 'line-height': H1 + 'px'}); //Set td height to row height
    });
});
</script>
55cc077
  • 9
  • 1
  • 2