Andy Jacobs
Andy Jacobs

Reputation: 957

Split a table cell vertically

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.

Upvotes: 1

Views: 31534

Answers (5)

Brock Adams
Brock Adams

Reputation: 93643

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.
  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.
      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 jsBin.

It works with all major browsers but not IE6.

Upvotes: 3

Alerty
Alerty

Reputation: 5945

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">
<html xmlns="http://www.w3.org/1999/xhtml">
<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).

Upvotes: 1

abelito
abelito

Reputation: 1104

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>

Upvotes: 0

Mawg
Mawg

Reputation: 40215

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

Upvotes: 1

Shunter1112
Shunter1112

Reputation: 623

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>

Upvotes: 5

Related Questions