views:

4148

answers:

4

I'm trying to design some HTML/CSS that can put a border around specific rows in a table. Yes, I know I'm not really supposed to use tables for layout but I don't know enough CSS to completely replace it yet.

Anyways, I have a table with multiple rows and columns, some merged with rowspan and colspan, and I'd like to put a simple border around parts of the table. Currently, I'm using 4 separate CSS classes (top, bottom, left, right) that I attach to the <td> cells that are along the top, bottom, left, and right of the table respectively.

<html>
<head>

<style type="text/css">
.top {
    border-top:thin solid;
    border-color:black;
}

.bottom {
    border-bottom:thin solid;
    border-color:black;
}

.left {
    border-left:thin solid;
    border-color:black;
}

.right {
    border-right:thin solid;
    border-color:black;
}
</style>

</head>
<body>

<table cellspacing="0">
  <tr>
    <td>no border</td>
    <td>no border here either</td>
  </tr>
  <tr>
    <td class="top left">one</td>
    <td class="top right">two</td>
  </tr>
  <tr>
    <td class="bottom left">three</td>
    <td class="bottom right">four</td>
  </tr>
  <tr>
    <td colspan="2">once again no borders</td>
  </tr>
  <tr>
    <td class="top bottom left right" colspan="2">hello</td>
  </tr>
  <tr>
    <td colspan="2">world</td>
  </tr>
</table>
</html>

Is there any easier way to do what I want? I tried applying top and bottom to a <tr> but it didn't work. (p.s. I'm new to CSS, so there's probably a really basic solution to this that I've missed.)

note: I do need to have multiple bordered sections. The basic idea is to have multiple bordered clusters each containing multiple rows.

+1  A: 

Based on your requirement that you want to put a border around an arbitrary block of MxN cells there really is no easier way of doing it without using Javascript. If your cells are fixed with you can use floats but this is problematic for other reasons. what you're doing may be tedious but it's fine.

Ok, if you're interested in a Javascript solution, using jQuery (my preferred approach), you end up with this fairly scary piece of code:

<html>
<head>

<style type="text/css">
td.top { border-top: thin solid black; }
td.bottom { border-bottom: thin solid black; }
td.left { border-left: thin solid black; }
td.right { border-right: thin solid black; }
</style>
<script type="text/javascript" src="jquery-1.3.1.js"></script>
<script type="text/javascript">
$(function() {
  box(2, 1, 2, 2);
});

function box(row, col, height, width) {
  if (typeof height == 'undefined') {
    height = 1;
  }
  if (typeof width == 'undefined') {
    width = 1;
  }
  $("table").each(function() {
    $("tr:nth-child(" + row + ")", this).children().slice(col - 1, col + width - 1).addClass("top");
    $("tr:nth-child(" + (row + height - 1) + ")", this).children().slice(col - 1, col + width - 1).addClass("bottom");
    $("tr", this).slice(row - 1, row + height - 1).each(function() {
      $(":nth-child(" + col + ")", this).addClass("left");
      $(":nth-child(" + (col + width - 1) + ")", this).addClass("right");
    });
  });
}
</script>
</head>
<body>

<table cellspacing="0">
  <tr>
    <td>no border</td>
    <td>no border here either</td>
  </tr>
  <tr>
    <td>one</td>
    <td>two</td>
  </tr>
  <tr>
    <td>three</td>
    <td>four</td>
  </tr>
  <tr>
    <td colspan="2">once again no borders</td>
  </tr>
</tfoot>
</table>
</html>

I'll happily take suggestions on easier ways to do this...

cletus
JavaScript might be acceptable - what do you have in mind?
Kyle Cronin
Seems like you are just adding classes to the td tags? Why couldn't this be done with some server-side script, generated statically, or worst-case just by hand? Looks like JavaScript abuse to me.
Thomas
Actually the poster ASKED for a Javascript solution. You can't say it's Javascript abuse since there's not enough information. For example, are the borders being added because of clicking the user does? If so, a server solution is incorrect.
cletus
Sorry about the lack of information. This will be generated server-side, so it's true that I could just add in the classes manually, but I do like how the JS solution provides a simpler interface to do so. So while I probably won't go with the JS it's a good solution to see.
Kyle Cronin
+2  A: 

The only other way I can think of to do it is to enclose each of the rows you need a border around in a nested table. That will make the border easier to do but will potentially creat other layout issues, you'll have to manually set the width on table cells etc.

Your approach may well be the best one depending on your other layout rerquirements and the suggested approach here is just a possible alternative.

<table cellspacing="0">  
    <tr>    
        <td>no border</td>    
        <td>no border here either</td>  
    </tr>  
    <tr>
        <td>
             <table style="border: thin solid black">
                  <tr>    
                        <td>one</td>    
                        <td>two</td>  
                  </tr>  
                  <tr>    
                      <td>three</td>    
                      <td>four</td>  
                  </tr>  
             </table>
         </td>
    </tr>
    <tr>    
         <td colspan="2">once again no borders</td>  
    </tr>  
    <tr>
        <td>
             <table style="border: thin solid black">
                  <tr>    
                        <td>hello</td>  
                   </tr>
             </table>
         </td>
    </tr>
    <tr>    
         <td colspan="2">world</td>  
    </tr>
</table>
sipwiz
Thanks for your answer; you're right about the layout issues though - I would prefer columns to line up without doing it by hand. What about applying a class to a <tr> tag - is that possible?
Kyle Cronin
If you use a table with “table-layout: fixed” and explicitly set the width of each column (by using <col> or just setting the width of cells in the first row), the columns will line up regardless of content. You don't even need to nest the tables, three separate tables would do the example fine.
bobince
+1  A: 

Here's an approach using tbody elements that could be the way to do it. You can't set the border on a tbody (same as you can't on a tr) but you can set the background colour. If the effect you're wanting to acheive can be obtained with a background colour on the groups of rows instead of a border this will work.

<table cellspacing="0">  
    <tbody>
        <tr>    
            <td>no border</td>    
            <td>no border here either</td>  
        </tr>  
    <tbody bgcolor="gray">
        <tr>    
            <td>one</td>    
            <td>two</td>  
        </tr>  
        <tr>    
            <td>three</td>    
            <td>four</td>  
        </tr>  
    <tbody>
        <tr>    
             <td colspan="2">once again no borders</td>  
        </tr>  
    <tbody bgcolor="gray">
        <tr>    
             <td colspan="2">hello</td>  
        </tr>
    <tbody>
    <tr>    
         <td colspan="2">world</td>  
    </tr>
</table>
sipwiz
+1  A: 

Thank you to all that have responded! I've tried all of the solutions presented here and I've done more searching on the internet for other possible solutions, and I think I've found one that's promising:

<html>
<head>

<style type="text/css">
tr.top td { border-top: thin solid black; }
tr.bottom td { border-bottom: thin solid black; }
tr.row td:first-child { border-left: thin solid black; }
tr.row td:last-child { border-right: thin solid black; }
</style>

</head>
<body>

<table cellspacing="0">
  <tr>
    <td>no border</td>
    <td>no border here either</td>
  </tr>
  <tr class="top row">
    <td>one</td>
    <td>two</td>
  </tr>
  <tr class="bottom row">
    <td>three</td>
    <td>four</td>
  </tr>
  <tr>
    <td colspan="2">once again no borders</td>
  </tr>
  <tr class="top bottom row">
    <td colspan="2">hello</td>
  </tr>
  <tr>
    <td colspan="2">world</td>
  </tr>
</table>

</body>
</html>

Instead of having to add the top, bottom, left, and right classes to every <td>, all I have to do is add top row to the top <tr>, bottom row to the bottom <tr>, and row to every <tr> in between. Is there anything wrong with this solution? Are there any cross-platform issues I should be aware of?

Kyle Cronin
Just ran a test through browsershots and it looks like IE (all versions) doesn't like the first-child and last-child attributes. :-/
Kyle Cronin
Adam Bernier