De-tabulating vBulletin Forumdisplay

Collapse
X
Collapse
 

  • Kier
    started a blog post De-tabulating vBulletin Forumdisplay

    De-tabulating vBulletin Forumdisplay

    A major feature slated to debut with vBulletin 4.0 is a new front-end style marked-up with semantic XHTML and styled with CSS.
    The task of producing the new templates using this scheme has thrown up all manner of questions, challenges and show-stopping problems, one of which I will discuss here.

    Background

    In vBulletin 3.x, the primary markup vehicle was the HTML <table> tag and almost all elements on vBulletin pages could be summarized as having the following basic structure:

    HTML Code:
    <table class="tborder">
    <tr>
    	<td class="tcat">Main heading</td>
    </tr>
    <tr>
    	<td class="thead">Sub-heading</td>
    </tr>
    <tr>
    	<td class="alt1">Some content</td>
    </tr>
    <tr>
    	<td class="alt2">Some more content</td>
    </tr>
    <tr>
    	<td class="tfoot">Block footer</td>
    </tr>
    </table>
    <br />
    Using this scheme, there is semantically no more value to the main heading than to any other tag in the block. Furthermore, the <table> tag and its contents strictly dictate how the element will appear; CSS has only a limited scope to change the fundamental structure of <table> elements.

    It’s worth noting at this point that the use of the <table> tag for this (or any other) purpose does not mean that the markup is not valid XHTML. In fact, the majority of pages in vBulletin 3.x validate against the standard to which they are built, namely XHTML 1.0 Transitional.

    However, it’s clear that a major part of a move to semantic XHTML will involve using more suitable markup for page elements, making use of tags that more accurately describe their content and contextualize it on the page.

    Threadbit

    One page that presents quite a conundrum is forumdisplay.php: the page that shows the list of threads in a forum. Let’s take a look at how the thread list has been presented in past versions.

    Firstly, we have vBulletin 1.x.



    Here, the thread data is presented in classic tabular fashion, with a single data point in each column, with the exception of the ‘Last Post’ column, where we show both the time and the writer of the most recent post to the thread in question.

    This is how the thread list looked in vBulletin 2.x.



    The data is still largely tabular, though we are starting to see content other than just the title in the ‘Thread’ column, namely the icon to represent a thread containing attachments and the ‘Poll:’ prefix.

    With vBulletin 3.x, there was an attempt to cut down the number of columns.



    We can see that the name of the thread starter has moved into the same column as the thread title, placed on a new line. The rating stars have also migrated into the same column and there are several more icons representing different attributes of the thread.

    The question is:
    Is the vBulletin 3 thread list still tabular data?

    At first sight, yes it is. We have a number of columns each containing data and the arrangement looks like a grid. But do we consider the thread list to be tabular data simply because it is arranged in this way?

    If we extract all the data and put each individual item into its own column, as should arguably be the case in order for the use of <table> to be semantically correct, we would end up with the following columns:
    1. Status icon (read/unread, hot, moved, locked, posted-by-viewer)
    2. Post icon
    3. Prefix
    4. Title
    5. Thread poster
    6. Replies
    7. Views
    8. Rating
    9. Last post date / time
    10. Last poster
    11. Poll indicator
    12. Sticky indicator
    13. Attachment indicator
    14. Tag indicator
    15. Subscription indicator
    16. Deleted thread indicator
    17. Contains deleted posts indicator
    A table with this many columns is not going to win any design awards. It would be fine to view in Excel, but as an immediately accessible, visually attractive web page, it’s going to look pretty terrible.

    The Requirements

    The basic structure I require visually is that of a table. I need a liquid column (one that stretches to occupy available space) followed by a number of fixed-width columns. Each column must be capable of supporting a background colour or image that will fill the cells.

    The old way to achieve this would be to use a <table> tag with rows styled in the following way:
    HTML Code:
    <tr>
    	<td bgcolor="#FF9999">(liquid column)</td>
    	<td bgcolor="#99FF99" width="50">(fixed 1)</td>
    	<td bgcolor="#9999FF" width="100">(fixed 2)</td>
    	...
    </tr>
    Of course, we want to avoid using a <table> tag if at all possible, given that our thread list is not strictly tabular data. Happily, most modern browsers give us an alternative that offers all the benefits of a <table> but without the semantic ambiguity, namely the CSS attribute display:table-cell. This would allow us to produce a layout visually identical to a table, but using semantic mark-up, such as this:
    HTML Code:
    <style type"text/css">
    .table { display:table; width:400px; }
    .row   { display:table-row; }
    .cell  { display:table-cell; }
    .liquid { background:#FF9999; }
    .fixed50 { background:#99FF99; width:50px; }
    .fixed100 { background:#9999FF; width:100px; }
    </style>
    ...
    <li class="row">
    	<h3 class="cell liquid">(liquid column)</h3>
    	<div class="cell fixed50">(fixed 1)</div>
    	<div class="cell fixed100">(fixed 2)</div>
    	...
    </li>
    This screengrab shows how Firefox 3 renders the two different HTML snippets. It’s obvious that they are visually identical.



    This markup allows radical restyling of the appearance of the thread listing and completely avoids the problematic <table> element. So, problem solved? Unfortunately not. There is one teeny tiny problem that is getting in the way of our goal. It’s called Microsoft Internet Explorer.

    Making IE Work

    Although support for display:table-cell has been introduced in Internet Explorer 8, the reality of the situation is that IE8 is not yet out of beta, leaving IE7 as the current primary version. What’s more, a significant portion of the web-browsing population is still using (shudder) IE6. Prior to IE8, display:table-cell is not supported at all in Internet Explorer. Given that Internet Explorer’s market share still represents a significant majority, there must be a workaround so that Internet Explorer users are not presented with a disastrous mess when they visit sites running vBulletin.

    If we feed IE7 with the same CSS as we present to other browsers, IE7 will ignore the display:table-cell instruction, resulting in the cells being represented as horizontal blocks.



    Inline-Block

    Internet Explorer 7 does implement a CSS property that can offer some help in this instance, namely display:inline-block. We don’t want other browsers to see the inline-block instruction, so we will create a new stylesheet surrounded by Internet Explorer conditional comments.

    Unfortunately, IE7 seems to have some bugs related to inline-block that need to be carefully prodded to make the system work. For some reason, a simple declaration of display:inline-block seems to have no effect, but it can be made to work by following it with a display:inline call. Yes, it’s that weird.
    HTML Code:
    <--[if lt IE 8]>
    <style type="text/css">
    .cell {
    	display:inline-block;
    }
    .cell {
    	display:inline;
    }
    </style>
    <![endif]-->


    We can see from the preceding screengrab that IE is now attempting to place the blocks next to each other rather than stacking them vertically, but the liquid column is expanding to fill the whole width of the container, rather than only occupying the space left by the fixed columns. For the time being, we’ll fix this by specifying a fixed width for the liquid column. We’ll come back to the liquid problem later.



    Finally, IE7 is displaying all the blocks horizontally in table fashion, but unlike a true table, the cells are not all of equal height.

    Equal Height Cells

    We start by specifying vertical-align:top for all cells, which will cause them to be aligned along a single top edge rather than the bottom edge.

    The next task is to make all the cells of equal height – all must expand or contract automatically according to the natural height of the highest cell in the row.

    We start by adding a massive amount of padding (9999px) to the bottom of all cells, such that it will extend well past the bottom of the browser window. We then reign that back in with a negative value (-9999px) for the bottom margin. This will look extremely strange and drop all the cells of the bottom of the page, until we instruct the row to hide any overflowed content.
    HTML Code:
    <!--[if lt IE 8]>
    <style type="text/css">
    .row {
    	overflow:hidden;
    }
    .cell {
    	display:inline-block;
    	vertical-align:top;
    	padding-bottom:9999px;
    	margin-bottom:-9999px;
    }
    .cell {
    	display:inline;
    }
    </style>
    <![endif]-->


    Single Liquid Cell

    We now have (what looks like) cells of equal sizes, which expand and contract vertically as they should. The last thing that remains is to get our liquid column working.

    Internet Explorer supports expressions in CSS, which is a very powerful system allowing CSS values to be generated by Javascript. We will make use of this system to calculate the amount of space left in the row container after the fixed width cells have been inserted. The remaining width will be applied to the liquid column. I wrote a little function called liquid_td to handle this.
    HTML Code:
    .liquid {
    	width:expression(liquid_td(this));
    }


    No-Javascript Failsafe

    Everything now looks correct, though our use of expression falls over if we encounter a visitor running Internet Explorer with Javascript disabled.

    To handle this worst-case scenario, we must abandon our liquid-fixed-fixed layout and switch to a completely liquid system, specifying all the widths in percentages. This will require a further stylesheet, this time surrounded by <noscript> tags to hide it from browsers that don’t need it.

    Unfortunately, this flings us headlong into Internet Explorer’s lack of common sense when it comes to math calculations. One might expect that 60% + 15% + 25% = 100%, but Internet Explorer disagrees from time to time. The problem appears to be one of unintelligent rounding. Here are a pair of examples that illustrate the problem.

    Example 1: Container width = 400px.
    • 60% of 400 = 240
    • 15% of 400 = 60
    • 25% of 400 = 100
    • 240 + 60 + 100 = 400.
    • Result: all columns fit.
    Example 2: Container width = 399px.
    • 60% of 399 = 239.4, rounds to 240
    • 15% of 399 = 59.85, rounds to 60
    • 25% of 399 = 99.75, rounds to 100
    • 240 + 60 + 100 =400
    • Result: last column drops because 400 pixels do not fit into 399 pixels.
    To deal with this problem, we need to set the width of the first cell to 0.1% less than the desired value. This appears to instruct IE to round down instead of up, resulting in the correct number of pixels being calculated.

    Conclusion and Discussion

    Our final system works like this:
    HTML Code:
    <style type"text/css">
    .table { display:table; width:400px; }
    .row   { display:table-row; }
    .cell  { display:table-cell; }
    .liquid { background:#FF9999; }
    .fixed50 { background:#99FF99; width:50px; }
    .fixed100 { background:#9999FF; width:100px; }
    </style>
    <!--if lt IE 8]>
    <style type="text/css">
    .row {
    	overflow:hidden;
    }
    .cell {
    	display:inline-block;
    	vertical-align:top;
    	padding-bottom:9999px;
    	margin-bottom:-9999px;
    }
    .cell {
    	display:inline;
    }
    .liquid {
    	width:expression(liquid_td(this));
    }
    </style>
    <noscript>
    <style type="text/css">
    .liquid { width:59.9%; /* we actually want 60% */ }
    .fixed50 { width:15%; }
    .fixed100 { width:25%; }
    </style>
    </noscript>
    <![endif]-->
    So, now we have a working system to emulate table cell behavior in our target browsers.



    The question now is:
    Was it all worth it, just to avoid using a <table> tag?

    • Charlie O'Leary
      Charlie O'Leary commented
      Editing a comment
      I like where this is going - good job as always, Kier. I'm curious to see how these layouts translate into fluid styles on larger screens. Definitely looks sharp, and while some are pushing for change I am glad that you're sticking to similarities across all vB versions. I've always known that you have all put a lot of thought into what you do, it's just nice to see that reinforced with a bit of hard posting once in awhile.

      Thanks, and keep up the great work!

    • dutchbb
      dutchbb commented
      Editing a comment
      @Lizard King: I just would like to say that I do not like you example of a "better" forumdisplay layout at all. IMO it's cluttered, messy, and like kier has pointed out: hard to compare threads and quickly evaluate and 'scan' their data. The funny thing is: it's also a lot more boring (I.E. not interesting to look at) than kiers layout, wich was ironically one of your arguments against his layout. I think the forumdisplay presented in the last screenshot looks very close to what I would expect from vb4. Now if it's really that hard to code 100% CSS for all browsers, then it's probably better to keep the table there for a while. I would suggest never to use CSS just because you think it's "cool" to do so. We need CSS to get better content-to-code ratio. If that is not the case, then we do not need it at all.

      PS: also completely agree with feldon23.

    • Darkimmortal
      Darkimmortal commented
      Editing a comment
      I hope you have removed any uses of the expression property in the final version - you do realise the javascript gets re-evaluated during many common events such as scrolling, resizing the window, typing etc, right?

      If there's enough elements on the page with the expression property, smooth scrolling goes completely out the window.

      Behavior might be a viable alternative property if no full css solution can be found.
    Posting comments is disabled.

Related Topics

Collapse

Working...