views:

112

answers:

5

I've got an HTML table, where some cells have dynamic content that will change height over time. Let's say I want to have one cell fill the bottom half with one color and the top half with another color. I'd like to do it with HTML/CSS such that as the other cells change height, the color cell will adjust to still be half-and-half (i.e., each color takes half of the new height).

I've tried variations of the following code. If both heights are 50% then I only see two colored dots. If both heights are 50px then A) I don't think it will adjust, and B) It's too tall for the current neighbor.

<table border="1">
<tr>
  <td>1<br />2</td>
  <td>
    <table border="1">
      <tr>
        <td style="background-color: Blue; height: 50%" />
      </tr>   
      <tr>
        <td style="background-color: Red; height: 50px" />
      </tr>
    </table>
  </td>
</tr>
</table>

Is there an easy trick to do this? Note that my final solution only needs to have a 1px vertical line, of half the cell height - so I could use a border, or background color, or even create a graphic if it would help. Oh, and I'm targeting multiple browsers.

Thanks in advance.

+1  A: 

I think you need to decide parent table size to separete half like this.

<table border="1" style="height:100px">
<tr>
 <td rowspan="2">1<br />2</td>
 <td style="background-color: Blue; height: 50%" />   
</tr>
<tr>
 <td style="background-color: Red; height: 50%" />
</tr>
</table>
Shunter1112
I don't know the height of my table, and I know it's going to change over time. So this won't work for me.
Andy Jacobs
A: 

Why not uses straighforward HTML and the <rowspan> keyword? That seems to me to be the simplest approach.

Use <TD ROWSPAN="2"> for the cell that you want to split. You can then use standard HTML / CSS colouring on those two cells? Since each is just a standard table cell, you can change their borders, etc

There is an example at http://www.tedmontgomery.com/tutorial/tblxmpls.html

LeonixSolutions
I did try this, but I couldn't get each row to have the same height. So it didn't evenly divide the cell.
Andy Jacobs
hmmm, not even when you use HTNL / CSS to split the height? Can you post how you tried?
LeonixSolutions
How do you populate the cells? Manually or programatically? If they are not the same height, then I am guessing that the contents are of different sizes. Maybe if you just padded the short one with trailing spaces until they are the same length?
LeonixSolutions
I tried the following (and saw the red line noticably longer than the blue - they met next to the "2" rather than the "3"):<table border="1"> <tr> <td rowspan="2">1<br />2<br />3<br />4<br />5</td> <td style="background-color: Blue;" /> </tr> <tr> <td style="background-color: Red;" /> </tr> </table>
Andy Jacobs
+1  A: 

I believe you are having difficulty because you are mixing structure and layout. You should use CSS for layout. You should drop the inner table and use some divs.

I recommend that you create a html document and copy/paste the code of the following examples from the code sample. For the moment, I do not have IE so I was not able to test the sample with that browser.

Here is the code sample :

.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Test</title>
    <style type="text/css">
        body, html 
        {
            margin:0;
            padding:0;
            color:#000;
            background: #333;
        }

        h2
        {
            color: #FFF;
            font-weight: bold;
        }

        p
        {
            font-size: 16px;
            color: #FFF;
        }

        #example1
        {
            position: relative;
            margin: 0 auto;
            background: #06F;
            width: 600px;
            min-height: 550px;
            height: auto;
            padding: 10px;
            margin-bottom: 10px;
            overflow: auto;
        }

        #example2
        {
            position: relative;
            margin: 0 auto;
            background: #06F;
            width: 600px;
            min-height: 550px;
            height: auto;
            padding: 10px;
            overflow: auto;
        }

        #table1 td
        {
            height: 400px;
            display: block;
            float: left;
            width: 250px;
        }

        .content
        {
            position: relative;
            margin: 0 auto;
        }

        .table1
        {
            width: auto;
        }

        .column
        {
            position: relative;
            height: 400px;
            width: 250px;
            float: left;
            margin-left: 2px;
        }

        .cell
        {
            position: relative;
            height: 100%;
            border:solid 1px #F00;
        }

        .top_cell
        {
            position: relative;
            height: 50%;
            padding: 5px;
            background: #0FF;
            overflow: auto;
        }

        .bottom_cell
        {
            position: relative;
            height: 50%;
            padding: 5px;
            background: #C9F;
            overflow: auto;
        }


    </style>
</head>

<body>
    <div class="content">

        <div id="example1">
            <h2> Example 1: </h2>
            <p>
                This example is made only with CSS...
            </p>

            <div class="table1">
                <div class="column">
                    <div class="cell">
                        <div class="top_cell">
                            <p>Test 1 Top</p>
                            <p>Test 1 Top</p>
                            <p>Test 1 Top</p>
                            <p>Test 1 Top</p>
                            <p>Test 1 Top</p>
                            <p>Test 1 Top</p>
                            <p>Test 1 Top</p>
                            <p>Test 1 Top</p>
                            <p>Test 1 Top</p>
                        </div>
                        <div class="bottom_cell">
                            <p>Test 1 Bottom</p>
                            <p>Test 1 Bottom</p>
                            <p>Test 1 Bottom</p>
                            <p>Test 1 Bottom</p>
                            <p>Test 1 Bottom</p>
                        </div>
                    </div>
                </div>

                <div class="column">
                    <div class="cell">
                        <div class="top_cell">
                            <p>Test 2 Top</p>
                            <p>Test 2 Top</p>
                            <p>Test 2 Top</p>
                            <p>Test 2 Top</p>
                            <p>Test 2 Top</p>
                            <p>Test 2 Top</p>
                            <p>Test 2 Top</p>
                            <p>Test 2 Top</p>
                        </div>
                        <div class="bottom_cell">
                            <p>Test 2 Bottom</p>
                            <p>Test 2 Bottom</p>
                            <p>Test 2 Bottom</p>
                            <p>Test 2 Bottom</p>
                            <p>Test 2 Bottom</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div id="example2">
            <h2> Example 2: </h2>
             <p>
                This example is made with a HTML table and some CSS...
            </p>
            <table id="table1">
                <tr>
                    <td>
                        <div class="cell">
                            <div class="top_cell">
                                <p>Test 1 Top</p>
                                <p>Test 1 Top</p>
                                <p>Test 1 Top</p>
                                <p>Test 1 Top</p>
                                <p>Test 1 Top</p>
                                <p>Test 1 Top</p>
                                <p>Test 1 Top</p>
                                <p>Test 1 Top</p>
                                <p>Test 1 Top</p>
                            </div>
                            <div class="bottom_cell">
                                <p>Test 1 Bottom</p>
                                <p>Test 1 Bottom</p>
                                <p>Test 1 Bottom</p>
                                <p>Test 1 Bottom</p>
                                <p>Test 1 Bottom</p>
                                <p>Test 1 Bottom</p>
                                <p>Test 1 Bottom</p>
                                <p>Test 1 Bottom</p>
                            </div>
                        </div>
                    </td>
                    <td>
                        <div class="cell">
                            <div class="top_cell">
                                <p>Test 2 Top</p>
                                <p>Test 2 Top</p>
                                <p>Test 2 Top</p>
                                <p>Test 2 Top</p>
                            </div>
                            <div class="bottom_cell">
                                <p>Test 2 Bottom</p>
                                <p>Test 2 Bottom</p>
                                <p>Test 2 Bottom</p>
                                <p>Test 2 Bottom</p>
                                <p>Test 2 Bottom</p>
                                <p>Test 2 Bottom</p>
                                <p>Test 2 Bottom</p>
                                <p>Test 2 Bottom</p>
                                <p>Test 2 Bottom</p>
                            </div>
                        </div>
                    </td>
                </tr>
            </table>
        </div>
    </div>
</body>
</html>

Tested on Safari 5 and Firefox 3 on Mac OS X (Snow Leopard).

Alerty
Good luck with that. Do you have sample code?
Robert Harvey
@Robert Harvey: Working on it ;)
Alerty
I'll echo Robert's request for more info. I actually started with DIV's, but moved to tables to get all the other things to line up the way I wanted. Is there a tutorial for using <DIV> for lining things up, like you can do with <TABLE>?
Andy Jacobs
@Andy Jacobs: Will your table always have only 1 row that is split into 2 parts with 2 columns?
Alerty
@Andy Jacobs: Also, do you want the content of the cell divided into a 'top cell' and 'bottom cell' or do you only want the background be divided into two colors?
Alerty
@Alerty: Your new code (edit 2, as of a few minutes ago) only appears to work because the content paragraphs `Test 1 Top/Bottom` are carefully balanced. This solution will not work for dynamic content or resizing on the fly. The table example also busts the row alignment on unbalanced content.
Brock Adams
@Brock Adams: Sorry, I was not really careful with that. I am correcting it right now.
Alerty
@Brock Adams: Should be looking alright now (in a standard compliant browser).
Alerty
@Alerty: I tested edit-7 code and the backgrounds are evenly split but most of the `top_cell` and `bottom_cell` have vertical scrollbars! USing FF 3.6 on Win XP.
Brock Adams
@Brock Adams: That is voluntary. The content of the top and bottom cells are not equal. In order to have half and half heights I have no choice but to use overflow: auto;
Alerty
I'm still new to CSS, but I'm not seeing how to make some DIVs appear to the left, but aligned with the bottom of the DIV next to is (without explicity setting one's height), and some centered, etc. I tried my example above as follows, but it only lined up the DIVs vertically, where I wanted the two to appear to the left of the tall one (evenly split):(to be continued...)
Andy Jacobs
<div> <div style="float:left"> <div style="height:50%; background-color: Red"></div> <div style="height:50%; background-color: Blue"></div> </div> <div style="height:100%">asdf<br /><br /><br /><br /><br /><br />a<br /><br /><br /><br />b </div></div>
Andy Jacobs
@Alerty - I think I will have one row per table, but many columns (I'm using the table to align things vertically). Only one column will need the split. But I will have a few such tables on the page.
Andy Jacobs
I'm actually trying to draw a vertical line in either the bottom half or top half of the cell (by making the cell 1px wide). Some cells will need it drawn in the top half, and others in the bottom. I can draw a line the entire height simply by making the background-color the line color I want (with a width of 1). But the entire hight of the cell is too high. I was hoping that if I could solve my posted problem, I could translate the solution to this problem. (e.g., I could make one color the table's background color, etc.).
Andy Jacobs
@Andy Jacobs: It probably is possible to solve your problem with only HTML/XHTML and CSS. I just need to know if you want the content (text, image, etc.) and background split into a top section of the cell and the bottom section of the cell (like two rows) or you only want the background color of the row to be divided into two even parts.
Alerty
I'm trying to draw a single pixel wide vertical line in either the top or bottom half of the (single pixel wide) cell. The other half should appear blank. So I have no other content to display in this cell. If I can avoid additional resources (e.g., bitmap images), it's better, but not a requirement. So using the background color to paint would be great (but again, not a requirement).
Andy Jacobs
I've found I can get close to what I want using a background color for the line, and adding a white (i.e., the page background color) "border" to the other half (i.e., top or bottom). But the problem with this is that it doesn't re-size. I haven't been able to specify the border height as "50%" - it only seems to work with px values, which don't automatically resize.
Andy Jacobs
@Andy Jacobs: You do not need any images or background colors to achieve a single border pixel. You need to use the CSS border properties (border-top, border-bottom, etc.). Now if you want me to help you, I need to know what you want. Do you want to only split the background into two equal parts of different colors (with a 1px border in the middle) or do you want to split the content as well as the background into two parts? In other words, do you want the content to be independent from the two different backgrounds or do you want the content to be divided into two rows(top cell and low cell).
Alerty
@Alerty, I've tried to answer your question above. I need to split the cell into two equal parts with one color at the top and another at the bottom. There does not need to be any separation between them. The colors are the only things that will be displayed in this cell - there is no other content in this cell. The split should be at exactly half the height (and ideally, should automatically adjust as the cell height changes due to other cells in the same row changing their heights).
Andy Jacobs
A: 

I re-read the question and realized I made a big mistake in implementing my answer. I would suggest using a divs like Andy says, but I stand by using javascript and css. I do not see an obvious method to implement dynamic heights to divs or tables without assigning ids and manipulating heights that are generated and returned by the browser. Divs and tables operate in that fashion for some reason.

<script type="text/javascript">
    /* FUNCTION: resizeTable
     * DESCRIPTION: Resizes table_id so that it is twice the height of the larger
          cell. The objective is to have two equally tall rows.
     * EXAMPLE: <body onload="resizeTable();">
     */
    function resizeTable() {
        // get the dom elements of the table and cells
        var table = document.getElementById("table");
        var cell = document.getElementById("cell");
        var diva = document.getElementById("div1");
        var div4 = document.getElementById("div2");

        // determine margin
        var margin = ( table.offsetHeight - cell.offsetHeight );

        // set the div's height to 1 larger than the cells to ensure it is full
        diva.style.height = ( ( cell.offsetHeight - ( margin / 2 ) ) / 2 ) + "px";
        div4.style.height = ( ( cell.offsetHeight - ( margin / 2 ) ) / 2 + 1 ) + "px";
    }

    // add onload event
    window.onload = function() { resizeTable(); }
</script>

<table id="table" border="1" style="border-collapse: collapse;">
    <tr>
      <td id="cell">1<br />2a<br />a</font></td>
      <td style="padding: 0px;">
        <div id="div1" style="width: 5px; background: blue;">
            &nbsp;
        </div>
        <div id="div2" style="width: 5px; background: red;">
            &nbsp;
        </div>
      </td>
    </tr>
</table>
abelito
Do not mix CSS and JavaScript. If you really want to have 'dynamic CSS' use a server side language for that like PHP. JavaScript can be turn off and the user will see one heck of a mess!
Alerty
The problem is, there is no server side way to generate content on the client's browser and know the height of the tables. If you try to set heights for either DIV or Table implementations, you may be making the heights too big or too small for the data. However, if the data being insertted into the cell is purely data/text that will be uniform in height, Andy could probably do a count of the number of lines, then set the height of the div/table to be in em measurements.
abelito
Admitedly, I may need to go with such a solution. But I was hoping to avoid this, since I'll need to either hook up all sorts of triggers to resize multiple cells, or keep track of things in my code (i.e., instead of actual events with triggers) to make sure things get adjusted at the right time. Either approach sounds like it could get fragile.
Andy Jacobs
@abelito: There is such a thing called relative positioning.
Alerty
+1  A: 

You can use all kinds of extra spaghetti markup or you can add one class to your table, like so:

<table class="FunkifyMyBackgounds">
    <tr>
        <th>Heading 1</th>
        <th>Heading 2</th>
    </tr>
    <tr>
        <td>...</td>
        <td>...</td>
    </tr>
</table>

.
and use some very simple jQuery javascript.

<script type="text/javascript">
    function SetAllSpecialCellBackgrounds (bNeedToCreateStructure)
    {
        var zCellsToBackgroundify               = $(".FunkifyMyBackgounds td");

        //--- Set each cell's funky background.
        zCellsToBackgroundify.each (function (idx) {SetA_SpecialCellBackground ($(this), idx, bNeedToCreateStructure);} );
    }


    function SetA_SpecialCellBackground (zJnode, K, bNeedToCreateStructure)
    {
        if (bNeedToCreateStructure)
        {
            //--- Add our special background structure.
            var sIdName                             = 'idSpecialCellBG_Container' + K;

            zJnode.append
            (
                '<div id="' + sIdName + '" class="SplitCellBackground">'                            +
                    '<div class="TopOfCell">&nbsp;<\/div><div class="BottomOfCell">&nbsp;<\/div>'   +
                '<\/div>'
            );
        }

        ResizeA_SpecialCellBackground (zJnode);
    }


    function ResizeA_SpecialCellBackground (zJnode)
    {
        var zCellBG_Frame                       = zJnode.find ('div.SplitCellBackground');

        //--- Set the background container to match the cell dimensions.
        zCellBG_Frame[0].style.width            = zJnode.outerWidth  (false) + 'px';
        zCellBG_Frame[0].style.height           = zJnode.outerHeight (false) + 'px';

        //--- Position absolutely; Adjust for margin, if needed.
        var aContentPos                         = zJnode.offset ();

        //--- Redundant for IE. Tested and IE really seems to need it, jQuery has failed me!
        zCellBG_Frame[0].style.top              = aContentPos.top  + 'px';
        zCellBG_Frame[0].style.left             = aContentPos.left + 'px';

        zCellBG_Frame.offset (aContentPos);
    }


    $(document).ready
    (
        function ()
        {
            SetAllSpecialCellBackgrounds (true);

            /*--- Globally catch table cell resizes caused by the browser window change.
                For other changes we could fire on DOMSubtreeModified, but IE and Opera are
                poopy-heads!  (Per usual)
                So a cross-browser, good-enough solution is just to use a timer.  Keep it just under
                a second per usability guidelines.
            */
            $(window).resize (function() {SetAllSpecialCellBackgrounds (false);} );
            setInterval (function()      {SetAllSpecialCellBackgrounds (false);}, 444);
        }
    );
</script>

.

Required CSS:

/***** Start of split-cell, specific styles. ****
*/
.SplitCellBackground, .TopOfCell, .BottomOfCell {
    margin:             0;
    padding:            0;
    width:              100%;
    height:             50%;
    z-index:            -10;
}
.SplitCellBackground {
    position:           absolute;
    width:              10em;
    height:             10em;
}
.TopOfCell {
    background:         #33FF33;
}
.BottomOfCell {
    background:         #FF33FF;
}
/***** End of split-cell, specific styles. *****/

.

You can see the complete code, in action at: http://scratchpad2.com/public/TableWithSplitBackground.htm .

It works with all major browsers but would require a a slight tweak for IE6 (available for a $30,000 donation to my Paypal. ;-) )

Brock Adams