43

Here is the relevant code (doesn't work):

<html>
<head>
<title>testing td checkboxes</title>
<style type="text/css">
td { border: 1px solid #000; }
label { border: 1px solid #f00; width: 100%; height: 100% }
</style>
</head>
<body>
<table>
  <tr>
    <td>Some column title</td>
    <td>Another column title</td>
  </tr>
  <tr>
    <td>Value 1<br>(a bit more info)</td>
    <td><label><input type="checkbox" /> &nbsp;</label></td>
  </tr>
  <tr>
    <td>Value 2</td>
    <td><input type="checkbox" /></td>
  </tr>
</table>
</body>
</html>

The reason is that I want a click anywhere in the table cell to check/uncheck the checkbox.

edits: By the way, no javascript solutions please, for accessibility reasons. I tried using display: block; but that only works for the width, not for the height

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Shawn
  • 10,931
  • 18
  • 81
  • 126

11 Answers11

32

I have only tested this in IE 6, 7, 8 and FF 3.6.3.

<html>
<head>
<title>testing td checkboxes</title>
<style type="text/css">
tr {
    height: 1px;
}
td {
    border: 1px solid #000;
    height: 100%;
}
label { 
    display: block; 
    border: 1px solid #f00;
    min-height: 100%; /* for the latest browsers which support min-height */
    height: auto !important; /* for newer IE versions */
    height: 100%; /* the only height-related attribute that IE6 does not ignore  */
}
</style>
</head>
<body>
<table>
    <tr>
        <td>Some column title</td>
        <td>Another column title</td>
    </tr>
    <tr>
        <td>Value 1<br>(a bit more info)</td>
        <td><label><input type="checkbox" /> &nbsp;</label></td>
    </tr>
</table>
</body>
</html>

The main trick here is to define the height of the rows so we can use a 100% height on their children (the cells) and in turns, a 100% height on the cells' children (the labels). This way, no matter how much content there is in a cell, it will forcibly expand its parent row, and its sibling cells will follow. Since the label has a 100% height of its parent which has its height defined, it will also expand vertically.

The second and last trick (but just as important) is to use a CSS hack for the min-height attribute, as explained in the comments.

glennsl
  • 28,186
  • 12
  • 57
  • 75
Valentin Flachsel
  • 10,795
  • 10
  • 44
  • 67
  • 1
    Congratulations for a css-only cross-browser solution! I just don't understand how setting a 1px height helps. Obviously, the 1px height is completely disregarded as soon as any content is found in the , and so the height of the is determined "dynamically", or rather, accordingly to the content. So what then is the difference between that and just not setting a height at all on the ? – Shawn Jun 21 '10 at 05:32
  • The way I always assumed this worked was that it provides an actual value for the 's children percentage height to work as opposed to not being defined at all (NULL ?). You will notice that as soon as you take that out, the model stops working because the 's height value has nothing to relate to - i.e 100% of NULL is still NULL. – Valentin Flachsel Jun 21 '10 at 11:14
  • 1
    It's not cross browser. It doesn't work in Safari 5.0, Iron 5.0.380 or Opera 9.64. – Gert Grenander Jun 21 '10 at 11:26
  • 1
    Semi-cross-browser then ? :) On a serious note though, I too believe that the only way to make sure this would work on all browsers (or at least as many as possible) would imply the use of JS to some extent, but then again, that too would completely fail if the user has JS disabled for whatever reason. I guess in the end the "correct" answer depends entirely on what Shawn needs his application to run on. – Valentin Flachsel Jun 21 '10 at 11:50
  • What do you mean with completely fail? My jQuery solution is a progressive enhancement. The great majority of users (yes, even people with screen readers) has JS enabled. And even for the ones that doesn't, it will fall back on the CSS. But then again... you can disable CSS as well. ;) – Gert Grenander Jun 21 '10 at 12:14
  • I meant the JS part would completely fail, not the whole page, of course. To be honest when I first read this question I was all "Oh, this is really easy with jQue ..." until I got to the part where he requested a solution that did NOT use JS :) So if he can live with this only working in a few browsers, I guess this is his solution. Otherwise I agree that he's better off with yours (nice one, btw !) or perhaps even a combination of the two, in case JS is disabled. – Valentin Flachsel Jun 21 '10 at 12:33
  • Thanks. Your CSS was nicely crafted as well. I agree on that the best solution would be a combination of the both. If the JS is enabled, it's going to work in all browsers... if not, it will work in most of the common ones. – Gert Grenander Jun 21 '10 at 12:42
  • I must agree with you both. From what has come up until now, it seems the ideal solution is a combination of both your solutions. I'll have to give FreekOne the correct answer for not using javascript (nor JQuery). Then, perhaps I will award the bounty to Gert G for having the most "complete" answer, indicating the impossibility of making this cross-browser AND giving so much "related" accessibility information. Thanks very much to both of you! – Shawn Jun 22 '10 at 01:07
  • @user1561346 the browsers this was tested in are obsolete now. Shouldn't come as a surprise that the answer itself became obsolete as well... 5 years later :) – Valentin Flachsel Nov 12 '15 at 07:49
23

Labels are inline elements by default, so setting the width and height does nothing.

label { display: block; }

Would do it.

(However, the practice of putting the label around the checkbox it is supposed to be associated with, rather than explicitly using for, doesn't work in IE.)

bobince
  • 528,062
  • 107
  • 651
  • 834
  • display: block works for width, but not for height. But thanks a lot for that IE warning! I guess I can wrap the input element in a label AND put a for attribute in there, right? – Shawn May 15 '10 at 19:49
  • 1
    Yes, you can. Actually having just checked it, this is fixed in IE7; it's only IE6 that would suffer. You can set `height` on a block, but if you set a percentage height, the parent element (to which the percentage is relative) must have a `height` specified itself. – bobince May 15 '10 at 20:13
  • Well, in this case, the parent element has no height specified.. So what do I do? – Shawn May 16 '10 at 00:41
  • You would have to specify a height. It doesn't really make any sense to have auto height on the parent but %-height on the child, which is why CSS 2.1 disallows it: it makes the height of the parent depend on the height of the child depend on the height of the parent depend on the height of the child depend on the [STACK OVERFLOW] – bobince May 16 '10 at 11:17
  • 2
    Well, the height of the TD depends on its content. Is there no way for CSS to say: "Once we've determined the dimensions of the TD element, make the label element 100% of the TDs width and height"? – Shawn May 17 '10 at 19:31
  • 1
    No, because the height of the ``'s content area is the height of the ` – bobince May 17 '10 at 23:20
  • If I understand what you're saying, the height of the td is determined once all the heights of all the elements in all the tds of that row are calculated. Therefore, if I want the label's size calculated after the td's size, I need to make that calculation once the page is shown, aka use javascript. Or in other words, what I am trying to do is impossible without javascript. Is that right? – Shawn Jun 18 '10 at 23:29
  • @bobince: Wrapping a label around a form element does work in IE. It makes the elment accessible to people with motor disabilities. But you still need to have a "label for" around the associated text in order to make it accessible to people with screen readers. – Gert Grenander Jun 19 '10 at 04:30
  • @Shawn I think it would look nice visually to have all the tds the same height or at least the clickable area around them the same size by setting the height on the label. You could also add a hover (probably using JS to make it work everywhere) so people can tell they can click any where. Personally, I at least like to add: label { cursor:pointer; } – Darryl Hein Jun 19 '10 at 04:46
  • @Darryl Hein: I would rather have the table cell containing the checkbox to act as a label for it.. If I set all the labels to the same size, I have to choose a size that's big enough for the biggest possibility, thus stretching all the smaller ones to that size unnecessarily and making the table larger than it already is (very large already). I do like the cursor: pointer idea very much though. Just added it in :) Thanks – Shawn Jun 19 '10 at 17:45
4

The way you're applying labels doesn't make the form elements fully accessible. The label should be applied on the text associated with the form element, not just the form element. But there's nothing wrong with adding another label over the form element in order to make the entire area inside the TD clickable. This is actually desirable in order to give people with motor disabilities a bigger area to click. The <label for="whatever">Your label</label> is aimed for people who use screen readers to go through the Web form.

Also, there's nothing inaccessible about using JavaScript for enhancing accessibility. JavaScript can be used as long as it degrades gracefully and doesn't stops screen readers from reading the page. Also, there's no way to use CSS to fill the cell height on the older versions of IE (which are still in use by a big number of users) without royally screwing up the look of the page. This said, you should use jQuery to fill the entire TD. The reason I don't say JavaScript is that jQuery saves you a lot of headaches by hiding a lot of the complex coding that's necessary to make this work across the great majority of browsers.

Here's the fully cross browser accessible jQuery enabled code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>Accessible Checkboxes</title>

    <script type="text/javascript" src="js/jquery.min.js"></script>

    <script type="text/javascript">
      $(document).ready(function() {
        $("table > tbody tr").each(function() { // Loop through all table rows
          var Highest=0; // We want to find the highest TD... start at zero
          var ThisHeight=0; // Initiate the temporary height variable (it will hold the height as an integer)

          $($(this).children('td')).each(function() { // Loop through all the children TDs in order to find the highest
            ThisHeight=parseInt($(this).height()); // Grab the height of the current TD

            if (ThisHeight>Highest) { // Is this TD the highest?
              Highest=ThisHeight; // We got a new highest value
            }
          });

          $(this).children('td').css('height',Highest+'px');  // Set all TDs on the row to the highest TD height
        });
      });
    </script>

    <style type="text/css">
      table {
        border: 1px solid #000;
      }

      td, label { 
        height: 100%;
        min-height: 100%;
      }

      th {
        text-align: left;
      }

      td, th {
        border: 1px solid #000;
      }

      label { 
        display: block;
      }
    </style>
  </head>
  <body>
    <form action="whatever.shtml" method="post" enctype="multipart/form-data">
      <table cellspacing="3" cellpadding="0" summary="A description of what's in the table.">
        <thead>
          <tr>
            <th scope="col">Some column title</th>
            <th scope="col">Another column title</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td scope="row"><label for="value1">Value 1<br />(a bit more info)</label></td>
            <td><label><input id="value1" type="checkbox" /> &nbsp;</label></td>
          </tr>
          <tr>
            <td scope="row"><label for="value2">Value 2</label></td>
            <td><label><input id="value2" type="checkbox" /></label></td>
          </tr>
        </tbody>
      </table>
    </form>
  </body>
</html>

You'll need to download jQuery and put the jquery.min.js file under a folder named js.

As you can see in the code, the form has been made fully accessible by adding a table summary, thead, th, scope, label for etc. Sure, it wasn't part of what you asked, but I added that as an extra bonus.

Gert Grenander
  • 16,866
  • 6
  • 40
  • 43
  • Now this is an elaborate answer! Thanks very much! I didn't know about the scope attribute nor the summary attribute and you are right about the second – Shawn Jun 19 '10 at 18:01
  • No problem Shawn. I've been working in an environment that requires accessibility for some 6+ years. You learn as you go. :) As for the script... Some browsers (*cough* IE *cough*) doesn't set the height of the `TD` to the full height of the `TR` when one `TD` is higher than the other(s). The script corrects this flaw. What it does is that goes row by row and checks which `TD` is the highest for that specific row. Then it explicitly sets all the `TD` heights for that row to the highest value. That way, the `LABEL` cells will be able to span the full height of the cell. – Gert Grenander Jun 19 '10 at 18:33
  • I see, thanks for clarifying. And so you would also be of the opinion that what I am trying to achieve is impossible without javascript? – Shawn Jun 19 '10 at 18:44
  • Yes, it's impossible if you aim for cross browser compatibility. In this case, the JavaScript (jQuery) will improve the accessibility of your Web page. – Gert Grenander Jun 19 '10 at 19:00
  • Impossible? What would you have to say about the solution proposed by FreekOne? It is css-only. Is it cross-browser? – Shawn Jun 21 '10 at 05:31
  • From what has come up until now, it seems the ideal solution is a combination of both your solution and that of FreekOne. I'll have to give FreekOne the correct answer for not using javascript (nor JQuery). Then, perhaps I will award the bounty to you for having the most "complete" answer, indicating the impossibility of making this cross-browser AND giving so much "related" accessibility information. Thanks very much to both of you! – Shawn Jun 22 '10 at 01:08
3

I did not find that the other answers worked in current browsers (2017), but absolutely positioning the label worked for me:

https://jsfiddle.net/4w75260j/5/

<html>
<head>
    <style type="text/css">            
        td.checkbox {
            position: relative;
        }
        td.checkbox label {
            /* Take up full width/height */
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;

            /* Ensure the checkbox is centered */
            display: flex;
            align-items: center;
            justify-content: center;
        }
    </style>
</head>
<body>
    <table>
        <tr>
            <td>Checkboxes</td>
            <td>Text</td>
        </tr>
        <tr>
            <td class="checkbox"><label><input type="checkbox" /></label></td>
            <td>Lorem ipsum dolor sit amet...</td>
        </tr>
    </table>
</body>
</html>

Note that this solution uses flexbox to center the checkbox; if you're targeting older browsers you may want to try the transform style of centering.

Alan
  • 1,148
  • 1
  • 9
  • 17
1

This code does what you want and it's tested on IE7+, FF, Google Chrome, Opera and Safari:

<html>
    <head>
        <title>testing td checkboxes</title>

        <style type="text/css">
            td{border:1px solid #000;width:200px;height:200px;}
            label{display:block;border:1px solid #f00;width:198px;height:198px;}
        </style>

    </head>
    <body>

        <table>
            <tr>
                <td>Some column title</td>
                <td>Another column title</td>
            </tr>
            <tr>
                <td>Value 1<br>(a bit more info)</td>
                <td><label><input type="checkbox" /> &nbsp;</label></td>
            </tr>
            <tr>
                <td>Value 2</td>
                <td><input type="checkbox" /></td>
            </tr>
        </table>

    </body>
</html>

If your problem wasn't solved, hope this solves it! ;)

Zuul
  • 16,217
  • 6
  • 61
  • 88
  • Thanks, but I can't guarantee that my content will always fit in 200px by 200px and I certainly don't want scrollbars to appear.. – Shawn Jun 19 '10 at 17:46
  • the width and height that I've placed its just for demonstration purposes! It can be change to fit your needs... the goal is to tell you that the width and height must be set or what you want will not work! – Zuul Jun 19 '10 at 18:16
  • I understand. Unfortunately, due to the dynamic nature of the content, I cannot know in advance what size of cell is needed for the content. – Shawn Jun 19 '10 at 18:25
1

This answer is a bit "out there" - for it to be valid HTML you'd have to define your own DTD, and in any case it doesn't work in IE or Opera (works in Firefox). So it's not a viable solution by any measure, but I thought I'd share anyway just for interest:

The HTML:

<table>
    <tr>
        <td>Some content</td>
        <label><input type="checkbox" /></label> <!-- no TD -->
    </tr>
    <tr>
        <td>Some<br />multi-line<br />content</td>
        <label><input type="checkbox" /></label>
    </tr>
</table>

The CSS:

label { display: table-cell; }
nickf
  • 537,072
  • 198
  • 649
  • 721
  • Interesting. I don't know enough about custom DTD's yet (I'm planning to learn one day) to understand this solution fully, but it is an approach I haven't thought of yet (nor seen). Thanks for sharing! – Shawn Jun 21 '10 at 05:40
  • Even if you implement a brand new DTD, the support for `table-cell;` is limited and there will most likely be accessibility issues, since screen readers might have problems parsing it in a reasonable way. – Gert Grenander Jun 21 '10 at 19:30
  • @Gert, **in theory** screen readers should be checking for the *style* of an element to determine how to handle it, not the *name*. But yes, you are correct: like I said, this really isn't viable given the poor cross-browser support. – nickf Jun 21 '10 at 23:59
  • @nickf - Doubt that. You might want to read up on semantic markup and accessibility. – Gert Grenander Jun 22 '10 at 00:38
0

I want a click anywhere in the table cell

<tr onclick="alert('process click here');"> ... </tr>
balexandre
  • 73,608
  • 45
  • 233
  • 342
0

Try this CSS for your label

label  {
 border:1px solid #FF0000;
 display:block;
 height:35px;
}

Here is the live Demo http://jsbin.com/ehoke3/2/

Pablo
  • 5,897
  • 7
  • 34
  • 51
  • What if that cell in the middle of the left column had another line of text? Or what if I later decide to change text size? This solution isn't ideal as I can't always know the precise height of the cells. – Shawn May 16 '10 at 00:50
  • You have two options you either use inline styles OR you should really use JavaScript - I mean why not? – Pablo May 16 '10 at 18:23
  • I really don't see how inline style will help me. I still can't determine the exact pixel-precise size of the TD at the time I write the code, plus it might change over time. And for javascript, if all else fails I don't mind, but I still feel I should give it a try for those who don't have it (for various reasons) – Shawn May 17 '10 at 19:35
0

In your row with "Value 1" you don't just have "a bit more info" you also include a break. It seems to me that all you really need to do is include a <br> in any label in the right column for when the content in the left column includes a <br>. Also, obviously <label> needs to have a display CSS attribute set to block.

<html>
<head>
<title>testing td checkboxes</title>
<style type="text/css">
td { border: 1px solid #000; }
label { border: 1px solid #f00; display: block;}
</style>
</head>
<body>
<table>
<tr><td>Some column title</td><td>Another column title</td></tr>
<tr><td>Value 1<br>(a bit more info)</td><td><label><input type="checkbox" /> &nbsp;<br>&nbsp;</label></td></tr>
<tr><td>Value 2</td><td><label><input type="checkbox" /></label></td></tr>
</table>
</body>
</html>

One note: you're not going to get perfect workalike performance in all the major browsers from the last 10 years--cough IE6--without resorting to things like JavaScript. I believe my solution is the best solution without resorting to JavaScript.

artlung
  • 33,305
  • 16
  • 69
  • 121
  • More about the IE6 implicit label bug: http://www.evotech.net/blog/2009/09/ie6ie7-implicit-label-bug/ – artlung Jun 18 '10 at 14:17
  • I just added the
    so that the content would use up two lines. There are other ways the content could use up two (or more) lines, such as having a very long string of text which needs to break into two lines to fit in the screen. This means that simply counting the
    s and adding the same amount in the right column wouldn't always work. But thanks very much for trying.
    – Shawn Jun 18 '10 at 23:24
0

The solution below:

  • has <label> which fills entirely the <td> height
  • supports any cell height (i.e. no fixed height in pixels)
  • does only on CSS (i.e. no JavaScript)
  • is multibrowser (MSIE 7/8/9/10/11, Firefox 42, Chrome 46, Seamonkey 2.39, Opera 33, Safari 5.1.7)

<html>
<head>
<title>testing td checkboxes</title>
<style type="text/css">
td { border: 1px solid #000; }
label { border: 1px solid #f00; display:block; min-height:2.3em;}
</style>
</head>
<body>
<table style="table-layout:fixed">
  <tr>
    <td>Some column title</td>
    <td>Another column title</td>
  </tr>
  <tr>
    <td>Value 1<br>(a bit more info)</td>
    <td><label><input type="checkbox" style="vertical-align:-50%" />&nbsp;</label></td>
  </tr>
  <tr>
    <td>Value 2</td>
    <td><input type="checkbox" /></td>
  </tr>
</table>
</body>
</html>

Explanations:

  • the display:block makes the <label> to take the <td> full width
  • the min-height:2.3em; makes the <label> to take the <td> full height (the minimum height a little bit higher than two lines as there are two lines in the first cell of the row; you may need to increase, e.g. I use 3.3em in my code)
  • the vertical-align:-50% makes the checkbox to be aligned vertically at the center of the cell (this is only required if the cell content spans over less lines than the first cell of the row)
Julien Kronegg
  • 4,968
  • 1
  • 47
  • 60
0

I found using display: table works for me. I tried (the previously suggested) display: table-cell and that didn't work.

td label {
    display: table;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
}
Zack Katz
  • 1,310
  • 11
  • 9