Firefox table sticky header row events not firing - html

I have a simple HTML table with a sticky header row. The header cell has a mouse enter event attached to it. In Firefox, the event stops firing when the user has scrolled down. This occurs ONLY when there are 21 rows (counting header) or more.
I have tested this in Chrome and Safari where this functionality appears to work correctly. I do not understand why this problem is occurring in Firefox.
const stickyRows = document.getElementsByClassName('sticky-row');
Array.from(stickyRows).forEach((stickyRowElement) => {
stickyRowElement.children[0].onmouseenter = () => console.log('mouse enter cell');
});
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
.sticky-row {
top: 0;
position: sticky;
background-color: white;
}
<div style="max-height: 300px; overflow: scroll">
<table style="float:left">
<tr class="sticky-row"><th>Sticky header for 20 rows</th></tr>
<tr><td>Row 2</td></tr>
<tr><td>Row 3</td></tr>
<tr><td>Row 4</td></tr>
<tr><td>Row 5</td></tr>
<tr><td>Row 6</td></tr>
<tr><td>Row 7</td></tr>
<tr><td>Row 8</td></tr>
<tr><td>Row 9</td></tr>
<tr><td>Row 10</td></tr>
<tr><td>Row 11</td></tr>
<tr><td>Row 12</td></tr>
<tr><td>Row 13</td></tr>
<tr><td>Row 14</td></tr>
<tr><td>Row 15</td></tr>
<tr><td>Row 16</td></tr>
<tr><td>Row 17</td></tr>
<tr><td>Row 18</td></tr>
<tr><td>Row 19</td></tr>
<tr><td>Row 20</td></tr>
</table>
<table>
<tr class="sticky-row"><th>Sticky header for 21 rows</th></tr>
<tr><td>Row 2</td></tr>
<tr><td>Row 3</td></tr>
<tr><td>Row 4</td></tr>
<tr><td>Row 5</td></tr>
<tr><td>Row 6</td></tr>
<tr><td>Row 7</td></tr>
<tr><td>Row 8</td></tr>
<tr><td>Row 9</td></tr>
<tr><td>Row 10</td></tr>
<tr><td>Row 11</td></tr>
<tr><td>Row 12</td></tr>
<tr><td>Row 13</td></tr>
<tr><td>Row 14</td></tr>
<tr><td>Row 15</td></tr>
<tr><td>Row 16</td></tr>
<tr><td>Row 17</td></tr>
<tr><td>Row 18</td></tr>
<tr><td>Row 19</td></tr>
<tr><td>Row 20</td></tr>
<tr><td>Row 21</td></tr>
</table>
</div>

Related

How can I overflow table rows to a second column?

I have a table of hundreds of short rows, and I would like to display the rows in columns rather than all underneath each other, like so:
I know I can create two tables and align them, but I would prefer it to be a single table for accessibility purposes, so the HTML of the above would be something like:
<table>
<thead>
<tr><th>Col 1</th><th>Col 2</th></tr>
</thead>
<tbody>
<tr><td>Row 1 Col 1</td><td>Row 1 Col 2</td></tr>
<tr><td>Row 2 Col 1</td><td>Row 2 Col 2</td></tr>
<tr><td>Row 3 Col 1</td><td>Row 3 Col 2</td></tr>
<tr><td>Row 4 Col 1</td><td>Row 4 Col 2</td></tr>
</tbody>
</table>
The closest I've managed to get is by adding multiple tbody elements and aligning them with flexbox (see below), but this has the downside that the header and caption won't be displayed correct:
I can fix that with some HTML/CSS-fu, or by removing the thead and inserting the header elements inside the tbody (without thead), but it seems rather ugly.
Is there a more straightforward way to produce multi-column tables like this?
I don't really see anything obvious in the HTML specification.
<style>
table { border-collapse: collapse; }
td { border: 1px solid #000; }
table { display: flex; justify-content: flex-start; }
tbody { margin-right: 1em; }
</style>
<table>
<caption>Table test</caption>
<thead>
<tr><th>Col 1</th><th>Col 2</th></tr>
</thead>
<tbody>
<tr><td>Row 1 Col 1</td><td>Row 1 Col 2</td></tr>
<tr><td>Row 2 Col 1</td><td>Row 2 Col 2</td></tr>
</tbody>
<tbody>
<tr><td>Row 3 Col 1</td><td>Row 3 Col 2</td></tr>
<tr><td>Row 4 Col 1</td><td>Row 4 Col 2</td></tr>
</tbody>
</table>
Edit:
Complete re-write using as much of your HTML as possible. Removed the last answer too.
This version will dynamically scale to suit the page, but you will need to let the CSS know at what screen size you want it to change. Currently set to 520px.
You will need to copy and paste the code to a test page and resize the window to see the dynamic sizing.
table {
width:100%;
max-width:520px;
text-align:center;
}
.tWide {
display:none;
}
#media all and (min-width:520px) {
thead tr, .tWide {
display:inline-block;
width:46%;
}
thead tr th {
display:inline-block;
width:46%;
text-align:center;
}
tbody {
display:inline-block;
width:46%;
}
td, th { width:23%; }
}
<table>
<caption>Table test</caption>
<thead>
<tr><th>Col 1</th><th>Col 2</th></tr>
<tr class="tWide"><th>Col 1</th><th>Col 2</th></tr>
</thead>
<tbody>
<tr><td>Row 1 Col 1</td><td>Row 1 Col 2</td></tr>
<tr><td>Row 2 Col 1</td><td>Row 2 Col 2</td></tr>
</tbody>
<tbody>
<tr><td>Row 3 Col 1</td><td>Row 3 Col 2</td></tr>
<tr><td>Row 4 Col 1</td><td>Row 4 Col 2</td></tr>
</tbody>
</table>

Highlight rows with rowspan

I wish to highlight rows in html tables while using rowspans when hovering over a row. I'd prefer that to be implementable with CSS only with minimal or no javascript.
Right now the Table row gets highlighted, but when having a 'sub' row it highlights only that instead of the row it's visually a 'part' of.
table {
width: 100%;
}
.topLevelRow td {
border-top:double 3px silver;
}
td {
border-top:solid 1px silver;
}
tr:hover {
background-color:lightgray;
}
<html>
<head></head>
<body>
<table>
<tr class="topLevelRow">
<td rowspan="3">1</td>
<td rowspan="3">Text 1</td>
<td>Sub A 1</td>
<td>Sub B 1</td>
</tr>
<tr><td>Sub A 2</td><td>Sub B 2</td></tr>
<tr><td>Sub A 3</td><td>Sub B 3</td></tr>
<!-- . -->
<tr class="topLevelRow">
<td rowspan="5">2</td>
<td rowspan="5">Text 2</td>
<td>Sub A 1</td>
<td rowspan="1">Sub B 1</td>
</tr>
<tr><td rowspan="1">Sub A 2</td><td rowspan="1">Sub B 2</td></tr>
<tr><td rowspan="1">Sub A 3</td><td rowspan="1">Sub B 3</td></tr>
<tr><td rowspan="1">Sub A 4</td><td rowspan="1">Sub B 4</td></tr>
<tr><td rowspan="1">Sub A 5</td><td rowspan="1">Sub B 5</td></tr>
</table>
</body>
</html>
As you can see it only highlights part of the rows. How can I highlight all of it?
You can use multiple <tbody> elements to define areas on your table. In this case you have one <table> element with some groups of rows. Using multiple <tbody> elements in <table> element is also valid HTML5.
table {
width: 100%;
}
td {
border-top: 1px solid silver;
}
tbody tr:nth-child(1) td {
border-top: 3px double silver;
}
tbody:hover tr {
background-color: lightgray;
}
<html>
<head></head>
<body>
<table>
<tbody>
<tr>
<td rowspan="3">1</td>
<td rowspan="3">Text 1</td>
<td>Sub A 1</td>
<td>Sub B 1</td>
</tr>
<tr><td>Sub A 2</td><td>Sub B 2</td></tr>
<tr><td>Sub A 3</td><td>Sub B 3</td></tr>
</tbody>
<tbody>
<tr>
<td rowspan="5">2</td>
<td rowspan="5">Text 2</td>
<td>Sub A 1</td>
<td>Sub B 1</td>
</tr>
<tr><td>Sub A 2</td><td>Sub B 2</td></tr>
<tr><td>Sub A 3</td><td>Sub B 3</td></tr>
<tr><td>Sub A 4</td><td>Sub B 4</td></tr>
<tr><td>Sub A 5</td><td>Sub B 5</td></tr>
</tbody>
</table>
</body>
</html>
The easiest way would be to break the table after each block. This is the simplest way, but it depends, if your template engine (or what ever you are using) allows this.
table {
width: 100%;
}
table:hover {
background-color:lightgray;
}
.topLevelRow td {
border-top:double 3px silver;
}
td {
border-top:solid 1px silver;
}
<html>
<head></head>
<body>
<table>
<tr class="topLevelRow">
<td rowspan="3">1</td>
<td rowspan="3">Text 1</td>
<td>Sub A 1</td>
<td>Sub B 1</td>
</tr>
<tr><td>Sub A 2</td><td>Sub B 2</td></tr>
<tr><td>Sub A 3</td><td>Sub B 3</td></tr>
</table>
<!-- Break table here and start new one -->
<table>
<tr class="topLevelRow">
<td rowspan="5">2</td>
<td rowspan="5">Text 2</td>
<td>Sub A 1</td>
<td rowspan="1">Sub B 1</td>
</tr>
<tr><td rowspan="1">Sub A 2</td><td rowspan="1">Sub B 2</td></tr>
<tr><td rowspan="1">Sub A 3</td><td rowspan="1">Sub B 3</td></tr>
<tr><td rowspan="1">Sub A 4</td><td rowspan="1">Sub B 4</td></tr>
<tr><td rowspan="1">Sub A 5</td><td rowspan="1">Sub B 5</td></tr>
</table>
</body>
</html>

Display table rows horizontally in I.E9

Below is my code
HTML
<div>
<table>
<tr><td>Row 1</td></tr>
<tr><td>Row 2</td></tr>
<tr><td>Row 3</td></tr>
<tr><td>Row 4</td></tr>
<tr><td>Row 5</td></tr>
<tr><td>Row 6</td></tr>
<tr><td>Row 7</td></tr>
<tr><td>Row 8</td></tr>
<tr><td>Row 9</td></tr>
<tr><td>Row 10</td></tr>
<tr><td>Row 11</td></tr>
<tr><td>Row 12</td></tr>
</table>
</div>
CSS
div{
min-width: 30px;
max-width: 400px;
}
tr{
display:inline-flex;
}
Link: JsFiddle
I want to display table rows horizontally, if rows width increases the max-width of the div it should come to next row.
The above code is working in I.E 10 + and Chrome and FF.
Here the challenge is not working in I.E 9.
Any suggestion how to make it work in IE. inline-flex not supported in IE9
I also used display: table-cell. But its not increasing the height of the div

GraphViz HTML nested tables

I am using GraphViz to make a tabular structure. I was using the record style, but the boxes weren't lining up. Given the answer to this question, I thought I'd use the HTML style instead. However, I can't seem to properly nest tables. Here's my dot code:
digraph test {
graph [ratio=fill];
node [label="\N", fontsize=15, shape=plaintext];
graph [bb="0,0,352,154"];
arset [label=<
<TABLE ALIGN="LEFT">
<TR>
<TD>Top left</TD>
<TD>
<TABLE>
<TR><TD>Row 1</TD></TR>
<TR><TD>Row 2</TD></TR>
</TABLE>
</TD>
</TR>
<TR>
<TD>Bottom Left</TD>
<TD>
<TABLE>
<TR><TD>Row 1</TD></TR>
<TR><TD>Row 2</TD></TR>
</TABLE>
</TD>
</TR>
</TABLE>
>, ];
}
And here's the output:
So many extra lines! Can anyone help me figure out how to properly make a nested table? On the flip side, an answer to the linked question detailing how to get cells to align using the record display would suffice.
I've added BORDER="0" to inner tables
digraph test {
graph [ratio=fill];
node [label="\N", fontsize=15, shape=plaintext];
graph [bb="0,0,352,154"];
arset [label=<
<TABLE ALIGN="LEFT">
<TR>
<TD>Top left</TD>
<TD>
<TABLE BORDER="0">
<TR><TD>Row 1</TD></TR>
<TR><TD>Row 2</TD></TR>
</TABLE>
</TD>
</TR>
<TR>
<TD>Bottom Left</TD>
<TD>
<TABLE BORDER="0">
<TR><TD>Row 1</TD></TR>
<TR><TD>Row 2</TD></TR>
</TABLE>
</TD>
</TR>
</TABLE>
>, ];
}
and here is the result
You can find here many other options to control HTML layout
Instead of this :
<TD>
<TABLE BORDER="0">
<TR><TD>Row 1</TD></TR>
<TR><TD>Row 2</TD></TR>
</TABLE>
</TD>
You can do this also :
<TD COLSPAN="2">Row 1<BR/>Row 2</TD>

How to put spacing between TBODY elements

I have a table like this:
<table>
<tfoot>
<tr><td>footer</td></tr>
</tfoot>
<tbody>
<tr><td>Body 1</td></tr>
<tr><td>Body 1</td></tr>
<tr><td>Body 1</td></tr>
</tbody>
<tbody>
<tr><td>Body 2</td></tr>
<tr><td>Body 2</td></tr>
<tr><td>Body 2</td></tr>
</tbody>
<tbody>
<tr><td>Body 3</td></tr>
<tr><td>Body 3</td></tr>
<tr><td>Body 3</td></tr>
</tbody>
</table>
I'd like to put some spacing between each tbody element, but padding and margin have no effect. Any ideas?
Something like this will work, depending on your browser support requirements:
tbody::before
{
content: '';
display: block;
height: 15px;
}
Try this, if you don't mind not having borders.
<style>
table {
border-collapse: collapse;
}
table tbody {
border-top: 15px solid white;
}
</style>
<table>
<tfoot>
<tr><td>footer</td></tr>
</tfoot>
<tbody>
<tr><td>Body 1</td></tr>
<tr><td>Body 1</td></tr>
<tr><td>Body 1</td></tr>
</tbody>
<tbody>
<tr><td>Body 2</td></tr>
<tr><td>Body 2</td></tr>
<tr><td>Body 2</td></tr>
</tbody>
<tbody>
<tr><td>Body 3</td></tr>
<tr><td>Body 3</td></tr>
<tr><td>Body 3</td></tr>
</tbody>
</table>
People will always have controversial opinions about using empty table elements to layout a page (as evidenced by this answer's downvote). I recognize this, but sometimes its easier to use them this way when you are working in a "quick and dirty" way.
I've used empty rows in past projects to space groups of table rows. I assigned the spacer rows a css class of their own and defined a height for that class that acted as a top and bottom margin for that group of table rows.
.separator{
height: 50px;
}
<table>
<tr><td>Cell 1</td><td>Cell 2</td></tr>
<tr><td>Cell 1</td><td>Cell 2</td></tr>
<tr><td>Cell 1</td><td>Cell 2</td></tr>
<tr class="separator" colspan="2"></tr>
<tr><td>Cell 1</td><td>Cell 2</td></tr>
<tr><td>Cell 1</td><td>Cell 2</td></tr>
<tr><td>Cell 1</td><td>Cell 2</td></tr>
<tr class="separator" colspan="2"></tr>
tr><td>Cell 1</td><td>Cell 2</td></tr>
<tr><td>Cell 1</td><td>Cell 2</td></tr>
<tr><td>Cell 1</td><td>Cell 2</td></tr>
</table>
If you don't have borders on your table cells, you could also define a height to your typical cell or row in your style sheet that evenly spaces out all rows of your table.
tr{
height: 40px;
}
I had been having trouble with cross-browser support for spacing multiple <tbody>'s using the ::before pseudo-selector if any <td>'s had a rowspan.
Basically, if your <tbody> is structured like this:
<tbody>
<tr>
<td>td 1</td>
<td rowspan"2">td 2</td>
<td>td 3</td>
<td>td 4</td>
</tr>
<tr>
<td>td 1</td>
<td>td 2</td>
<td>td 4</td>
</tr>
</tbody>
...and your ::before pseudo-selector displays the content as a block like this:
tbody::before
{
content: '';
display: block;
height: 10px;
}
...then this will cause the table to cut off any columns that use rowspan.
The solution is to style ::before pseudo as a table-row:
tbody::before
{
content: '';
display: table-row;
height: 10px;
}
This should have good cross-browser support.
Here's a fiddle
Here's another possibility that relies on :first-child which is not available in all browsers:
<style>
table {
border-collapse: collapse;
}
td {
border: 1px solid black;
}
tbody tr:first-child td {
padding-top: 15px;
}
</style>
<table>
<tfoot>
<tr><td>footer</td></tr>
</tfoot>
<tbody>
<tr><td>Body 1</td></tr>
<tr><td>Body 1</td></tr>
<tr><td>Body 1</td></tr>
</tbody>
<tbody>
<tr><td>Body 2</td></tr>
<tr><td>Body 2</td></tr>
<tr><td>Body 2</td></tr>
</tbody>
<tbody>
<tr><td>Body 3</td></tr>
<tr><td>Body 3</td></tr>
<tr><td>Body 3</td></tr>
</tbody>
</table>
Just set display as block and it will work.
table tbody{
display:block;
margin-bottom:10px;
border-radius: 5px;
}
Of all of the answers given above, only djenson47's answers retain separation of presentation and content. The drawback of the collapsed border model method is that you can no longer use the table's border or cellspacing attributes to separate the individual cells. You could argue that this is a good thing, and there are some workarounds, but it can be a pain. So I think the first-child method is the most elegant.
Alternatively, you could also set your TBODY class' overflow property to anything other than "visible." This method allows you to retain a separated borders model as well:
<style>
tbody {
overflow: auto;
border-top: 1px solid transparent;
}
</style>
<table>
<tfoot>
<tr><td>footer</td></tr>
</tfoot>
<tbody>
<tr><td>Body 1</td></tr>
<tr><td>Body 1</td></tr>
<tr><td>Body 1</td></tr>
</tbody>
<tbody>
<tr><td>Body 2</td></tr>
<tr><td>Body 2</td></tr>
<tr><td>Body 2</td></tr>
</tbody>
<tbody>
<tr><td>Body 3</td></tr>
<tr><td>Body 3</td></tr>
<tr><td>Body 3</td></tr>
</tbody>
</table>
You can use border-spacing in a table with table row groups to add a space between those groups. Though, I don't think there is a way to specify which groups are spaced and which are not.
<table>
<thead>
...
</head>
<tbody>
...
</tbody>
<tbody>
...
</tbody>
<tfoot>
...
</tfoot>
</table>
CSS
table {
border-spacing: 0px 10px; /* h-spacing v-spacing */
}
Because padding can be applied to TD's, you can do a trick with the + sign. Then it will be possible to give a top padding to the TD's of the first TR of a tbody:
// The first row will have a top padding
table tbody + tbody tr td {
padding-top: 20px;
}
// The rest of the rows should not have a padding
table tbody + tbody tr + tr td {
padding-top: 0px;
}
I have added the "tbody + tbody" so the first tbody won't have a top padding. However, it's not required.
As far as I know there are no drawbacks :), though didn't test the older browsers.
NEW ANSWER
You can use as many <tbody> tags as you like. I didn't realize that was ok by W3C until now. Not to say my below solution doesn't work (it does), but to do what you're trying to do, assign your <tbody> tags classes and then reference their individual <td> tags through CSS like so:
table tbody.yourClass td {
padding: 10px;
}
and your HTML thusly:
<table>
<tbody>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
</tbody>
<tbody class="yourClass">
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
</tbody>
<tbody>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
</tbody>
</table>
Try that guy out :)
OLD ANSWER
whatever you do, DON'T insert blank rows...
you shouldn't have more than 1 tbody element in your table. what you can do is set the class or id attribute in your <tr> elements and give their corresponding <td> tags padding:
table {
border-collapse: collapse;
}
tr.yourClass td {
padding: 10px;
}
You can even assign the top and bottom <tr>'s an additional class so that they only do top or bottom padding, respectively:
tr.yourClass.topClass td {
padding: 10px 0 0 0;
}
tr.yourClass.bottomClass td {
padding: 0 0 10px 0;
}
and in your HTML, your <tr> tag would look like this:
<table>
<tbody>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr class="yourClass topClass"><td>Text</td></tr>
<tr class="yourClass"><td>Text</td></tr>
<tr class="yourClass bottomClass"><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
</tbody>
</table>
Hope this helps!
djensen47 answer works great for newer browsers, however, as it was pointed out, IE7 it does not work in.
My workaround for this issue to support the older browsers was to wrap each cells contents inside a div. Then add a margin-top to the div.
<table class="tbl">
<tr></tr>
<tr></tr>
<tr></tr>
<tr><td><div></div></td></tr>
</table>
CSS
.tbl tr td div {
height:30px;
margin-top:20px;
}
The height setting keeps the cells at least 30px high to prevent any cell coloring used inside the div from collapsing around the text. The margin-top creates the desired space by making the entire row taller.
Came across this while trying to solve it myself. I had success with putting a <br> tag right before the closing </tbody> tag. It is a purely visual fix, but seems to work on most browsers I tested.
<table>
<tbody>
<tr>
<td></td>
</tr>
<br>
</tbody>
<tbody>
<tr>
<td></td>
</tr>
</tbody>
</table>
Should be accessible as well.
With credit to everyone else who answered first ...
table {
border-collapse: collapse;
table-layout: fixed;
width: 50%;
}
tbody:before {
content: "";
display:block;
border-top: 15px solid white;
}
tbody tr {
border-color: #000;
border-style: solid;
}
tbody tr:first-of-type{
border-width: 2px 2px 0 2px;
}
tbody tr:nth-of-type(1n+2){
border-width: 0 2px 0 2px;
}
tbody tr:last-of-type{
border-width: 0 2px 2px 2px;
}
tbody tr:nth-child(odd) {
background-color: #ccc;
}
tbody tr:hover {
background-color: #eee;
}
td {
text-align: right;
}
<table>
<tbody>
<tr>
<th colspan="3">One</th>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="3">Two</th>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>