J0HN
J0HN

Reputation: 26941

element with height 100% and overflow

What I basically need to achieve is to have an element (div, span, table, whatever) to consume 100% of its' parent height and show scrolls if it's content is taller.

The problem is, only chrome and IE in quirks work OK with height:100%; overflow: auto;. Firefox, Opera and IE in standards (any IE 7+, any "standards") just ignore the overflow and stretch the html element below the parent size. If I set fixed height it works, but I can't determine the available height before rendering, there are multiple possible values.

Simplified example (jsFiddle for this):

<body>
    <div id="parent">
        <table id='container'>
            <tr>
                <td>
                    <div id='element-in-question'>
                        <!--Content long enough to stretch the div-->
                    </div>
                </td>
            </tr>
            <tr>
            <td id='footer-cell'>
                <div id='footer'>I'm footer<div>
            </td>
            </tr>
        </table>
    </div>
</body>

Css:

#parent { height:500px; width:500px; position:absolute; }
#container { height: 100%; width:100%; }
#element-in-question { height:100%; width:100%; overflow: auto; }
#footer-cell { height:30px;}
#footer { height: 30px; }

In real app all this stuff runs in an iframe, table is used to render header and footer and so on. Please do not suggest stop using tables, it's legacy application with 100+ places that need attention. CSS only solution would be ideal.

One more point: it should work in Chrome, IE10 standards mode. FF, Opera and Safari are not supported, IE9 and below handled differently.

Update: there are about ten footers with different heights, ideally the solution should not depend on fixed footer height.

Upvotes: 5

Views: 4482

Answers (3)

Josh Burgess
Josh Burgess

Reputation: 9567

Here you go:

Updated fiddle.

The problem is that height: 100%; is going to fill the next defined container. For whatever reason, tables aren't seen as a valid container for that purpose. So what we need to do is utilize some of the quirkiness of how tables are laid out.

position: absolute;
top:5px; left:5px;
right: 5px;
bottom: 40px;
overflow: auto;
border: 1px solid green;
background-color: #eee;

No need for relative positioning on the td. Don't ask me why, perhaps someone more knowledgable than I can chime in.

Regardless, with this we can force it to expand to fill a set amount of space, while still allowing:

  1. The footer to be visible.
  2. The padding to be present (even if it's not technically padding.)
  3. This solution to work in a cross-browser environment.

Really hope this helps; if it doesn't, I'd be more than happy to give it another shot.


Update

You said that javascript isn't how you'd like to do it, but here's a short solution using jQuery which would actually solve the problem:

Updated Fiddle

$('td > div').each(function() {
    var t = $(this);
    var text = t.html();
    t.hide();
    t.height(t.parent().height());
    t.show(text);
});

Why this works:

The div needs its parent to have a defined height before 100% height works, however that's not an option for you as you've already stated that this is all dynamic content. No problem. We just need the jQuery to push the calculated height to the div after the browser has already rendered it. Simple enough, right?

Well, not so fast. Divs aren't meant to be bounded by table cells, at least not ideally. We already have something that serves as a logical, separate container in the td, and the div doesn't much care what the td's height is if it has a boatload of content that's spilling over its borders already. And when we go to query the height of that td, no matter what it actually is, it's going to report that it's larger than the elements which it contains. So, if you look on the fiddle after commenting out the lines where we empty the div, you'll see that the td is erroneously reporting itself to be almost 900 pixels tall.

So what do we do?

Well, we take that content away from the div. Now it's just a husk, and it's going to be smaller than its container in every circumstance. That means that the td isn't going to lie about misreport its size when we query it, since it's confidently containing its children.

And once we get the truth from the TD, we tell the div that the size its parent has reported is the size that it needs to be, and give it back its content.

Voila. You've got a div that actually respects its parent now. If only real children were that easy.

Upvotes: 5

Matt Coughlin
Matt Coughlin

Reputation: 18906

The basic behavior of HTML tables

Here's a demo showing how small and extra-large content affects the width and height of a table. There are gray rulers alongside the tables, showing the intended dimensions of the tables. Standalone version of the demo.

Scrolling extra-large variable-size content in a table cell appears to work to some extent vertically, and not at all horizontally.

For height, there are 3 different outcomes in different browsers:

  1. The overall height of the table is correct. This occurs with Chrome and Safari (Webkit browsers).
  2. The content row occupies the intended height of the overall table, and the footer row adds additional height to the table, causing the table to be a little taller than intended. This occurs with Firefox and Opera, and IE7/8/9/10 in Standards mode (though in IE, the footer cell is even taller than the height of the footer content, which adds significant extra height to the table).
  3. The entire height of the content row is displayed with no scrollbars, causing the table to be much taller than intended. This occurs with IE7/8/9/10 in Quirks mode.

For width, the outcome is comparable to #3 for all browsers (the full content width is always displayed with no scrollbars).

CSS compromise

The closest to a CSS solution that appears to be possible is setting a fixed height for #element-in-question (though letting it remain scrollable), and allowing the footer to vary in height. The overall size of the table would vary by however much the different footers vary in height. If the height difference of the footers is small, or if it's not critical that the overall table always has the same height, then this may be a reasonable compromise.

The CSS posted in the question would look something like the following (giving #element-in-question whatever height is determined to be optimal, when combined with the average or most-common footer height).

#parent { width:500px; position:absolute; }
#container { width:100%; }
#element-in-question { height:450px; width:100%; overflow: auto; }
#footer-cell { }
#footer { }

Here's an updated version of the demo posted in the question, using the changes listed above (tested in: IE7/8/9/10 Standards and Quirks mode, Firefox, Chrome, Safari, Opera). If there are difficulties running JSFiddle in older versions of IE, try this standalone version of the demo.

The website design appears to go beyond the bounds of what HTML tables are capable of. Unless some constraints can be imposed upon the design (such as the one described here), it looks like this will require JavaScript or jQuery.

Upvotes: 2

MIIB
MIIB

Reputation: 1849

I've got a workaround for this.tbody tag is added automatically in firefox and that cause the problem. Add height:100% to your td and height:90% to your tbody. The tbody tag never existed so you should add it with css.

table tbody{height:90%}

Live Demo

Upvotes: 0

Related Questions