Search code examples
htmlcssalignmenthtml-table

Forcing equal height on DIVs within TDs


I'm using a table layout for data representation:

Table layout screenshot

The problem is that according to the design, i must put these separation borders between the cells.

I saw no way of accomplishing this, other than through the use of div elements within the td elements (which - correct me if i'm mistaken - shouldn't pose a problem).

Example

<table>
    <tr>
       <td>
          <div class="inner">
             Content
          </div>
       </td>
    </tr>
</table>

CSS

table td {
    padding: 15px 10px;
    border-bottom: 1px solid #e5e5e5;
}

table td div.inner {
    padding: 10px 25px 10px 0;
    border-right: 1px solid #e5e5e5;        
}

It works fairly well - what you see in the shot is the actual rendering in the browser.

But when you take a close look, you'll notice that the vertical lines (the border-right property of div.inner have varying heights. This, of course, makes sense and i understand why it happens. The content within div.inner will cause it to grow in height, adding the padding.

I tried setting a fixed height to div.inner which would be ok for my table, because i know exactly how much data i will represent and that it will never exceed a certain height. But when doing this, all content within div.inner becomes vertically aligned to the top, meaning that the naturally applied vertical-align property of my td elements is no longer affecting the content inside div.inner.

I tried applying display: inline-block to div.inner to trigger vertical centered alignment, which then caused the widths to vary. So i added width: 100% as well, which then resulted in misalignments on the horizontal axis (text overlapped borders) and finally didn't show the desired result regarding the vertical alignment. So this approach is fruitless.

How could i make those vertical separator lines be of equal height?

Or, alternatively, ...

How could i force vertical alignment of all content, when using a fixed height on div.inner?

Please note: Using line-height in any way to achieve the result (or attempt to) is not an option for me. As you can see in the screenshot, i am displaying a progress bar. This incorporates further elements within div.inner.


Solution

  • I do not know what kind of browsers do you have to support for, but my solution requires browser support for the :before or :after pseudo elements, as well as support for the :last-child (or any CSS3) selectors.

    Currently the global stats points to:

    • 84.9% total support + 7.56% partial support for CSS generated content. Source
    • 84.79% support for CSS3 selectors. Source

    Therefore it is important that perfect cross-browser compatibility is impossible to be achieved, especially when considering antiquated browsers, but it only affects the layout, not the functionality of your site ;)

    My solution is to set the position of each table cell to relative, and then add a pseudo-element that has a right border of 1px in width that is positioned absolutely within each cell:

    table td {
        padding: 15px 10px;
        position: relative;
        border-bottom: 1px solid #e5e5e5;
    }
    table td:before {
        border-right: 1px solid #e5e5e5;
        content: ""; /* Need to declare content, even when empty! */
        position: absolute;
        top: 10px;
        bottom: 10px;
        right: 10px;
        width: 0;
    }
        /* Optional, only if you want to                */
        /* remove border on last td element on each row */
        table td:last-child:before {
            display: none;    
        }
    

    See working fiddle here (tested in Chrome, Safari and Firefox): http://jsfiddle.net/teddyrised/e4LXY/

    The merits of this method is that it is widely supported in most modern browsers, and that since the :before pseudo element is added to the table cell instead of the inner div, it will stretch with the final computed height of the row, therefore ensuring that they will be of all equal height. The fiddle demonstrates that the content can be of variable height.

    The only demerit is that there is no backward compatibility for browsers that do not support CSS generated content and/or CSS3 selectors. You might want to consider using a fallback style (like, a solid border for the entire table) for visitors on older browsers.