Cols, colgroups and css ":hover" pseudoclass - css

I'm trying to create a table to display an individual's BMI.
As a part of this, I'd like, on :hover, for the <tr> and <col> (or <colgroup>) to be highlighted also, in order for the intersection to be more apparent.
As the table will feature both metric and imperial measurements, the :hover doesn't have to stop at the cell (from any direction) and would, in fact, be a bonus if it extended from one axis to the other. I'm also using the XHTML 1.1 Strict doctype, if this makes a difference?
So... an example (the real table's... larger), but this should be representative:
<script>
tr:hover {background-color: #ffa; }
colgroup:hover,
col:hover {background-color: #ffa; }
</script>
...
<table>
<col class="weight"></col><colgroup span="3"><col class="bmi"></col></colgroup>
<tr>
<th></th>
<th>50kg</th>
<th>55kg</th>
<th>60kg</th>
</tr>
<tr>
<td>160cm</td>
<td>20</td>
<td>21</td>
<td>23</td>
</tr>
<tr>
<td>165cm</td>
<td>18</td>
<td>20</td>
<td>22</td>
</tr>
<tr>
<td>170cm</td>
<td>17</td>
<td>19</td>
<td>21</td>
</tr>
</table>
Am I asking the impossible, do I need to go JQuery-wards?

Here's a pure CSS method using no JavaScript.
I used ::before and ::after pseudo-elements to do the row and column highlighting. z-index keeps the highlighting below the <td>s in case you need to handle click events. position: absolute allows them to leave the confines of the <td>. overflow: hidden on the <table> hides the highlight overflow.
It wasn't necessary, but I also made it select just the row or column when you're in the headers. The .row and .col classes take care of this. If you wish the simplify, you can remove them.
This works in all modern browsers (and degrades gracefully on older browsers by doing nothing).
Demo: http://jsfiddle.net/ThinkingStiff/rUhCa/
Output:
CSS:
table {
border-spacing: 0;
border-collapse: collapse;
overflow: hidden;
z-index: 1;
}
td, th, .row, .col {
cursor: pointer;
padding: 10px;
position: relative;
}
td:hover::before,
.row:hover::before {
background-color: #ffa;
content: '\00a0';
height: 100%;
left: -5000px;
position: absolute;
top: 0;
width: 10000px;
z-index: -1;
}
td:hover::after,
.col:hover::after {
background-color: #ffa;
content: '\00a0';
height: 10000px;
left: 0;
position: absolute;
top: -5000px;
width: 100%;
z-index: -1;
}
HTML:
<table>
<tr>
<th></th>
<th class="col">50kg</th>
<th class="col">55kg</th>
<th class="col">60kg</th>
<th class="col">65kg</th>
<th class="col">70kg</th>
</tr>
<tr>
<th class="row">160cm</th>
<td>20</td><td>21</td><td>23</td><td>25</td><td>27</td>
</tr>
<tr>
<th class="row">165cm</th>
<td>18</td><td>20</td><td>22</td><td>24</td><td>26</td>
</tr>
<tr>
<th class="row">170cm</th>
<td>17</td><td>19</td><td>21</td><td>23</td><td>25</td>
</tr>
<tr>
<th class="row">175cm</th>
<td>16</td><td>18</td><td>20</td><td>22</td><td>24</td>
</tr>
</table>

There is a very decent jQuery plugin I've come across located here which does a very good job of this kind of thing with loads of examples. Preferentially I'd use that.

AFAIK CSS Hovers on TR's aren't supported in IE anyway, so at best the TR part of that will only work in Firefox.
Never even seen a :hover work on a col/colgroup so not sure if that's possible...
Think you might be stuck with a Javascript implementation.
Theres an example here that works (rows & cols) in Firefox
but again its broken in IE... cols don't work.

Live answer (https://jsfiddle.net/craig1123/d7105gLf/)
There are already CSS and JQuery answers; however, I have written a simple pure javascript answer.
I first find all the col and td tags, get the column index of each cell by doing element.cellIndex, and then add a CSS class with a background on mouseenter and removing it on mouseleave.
HTML
<table id='table'>
<col />
<col />
<col />
<col />
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Birthdate</th>
<th>Preferred Hat Style</th>
</tr>
</thead>
<tbody>
<tr>
<td>Abraham Lincoln</td>
<td>204</td>
<td>February 12</td>
<td>Stovepipe</td>
</tr>
<tr>
<td>Winston Churchill</td>
<td>139</td>
<td>November 30</td>
<td>Homburg</td>
</tr>
<tr>
<td>Rob Glazebrook</td>
<td>32</td>
<td>August 6</td>
<td>Flat Cap</td>
</tr>
</tbody>
</table>
CSS
body {
font: 16px/1.5 Helvetica, Arial, sans-serif;
}
table {
width: 80%;
margin: 20px auto;
border-collapse: collapse;
}
table th {
text-align: left;
}
table tr, table col {
transition: all .3s;
}
table tbody tr:hover {
background-color: rgba(0, 140, 203, 0.2);
}
table col.hover {
background-color: rgba(0, 140, 203, 0.2);
}
tr, col {
transition: all .3s;
}
tbody tr:hover {
background-color: rgba(0,140,203,.2);
}
col.hover {
background-color: rgba(0,140,203,.2);
}
JS
const col = table.getElementsByTagName('col');
const td = document.getElementsByTagName('td');
const columnEnter = (i) => col[i].classList.add('hover');
const columnLeave = (i) => col[i].classList.remove('hover');
for (const cell of td) {
const index = cell.cellIndex;
cell.addEventListener('mouseenter', columnEnter.bind(this, index));
cell.addEventListener('mouseleave', columnLeave.bind(this, index));
}
Here is a fiddle

I came accross this neat way of doing it its from css-tricks.com I also prepared a fiddle whilst messing around with it nothing fancy but u can get the idea its with the same code provided by that css-trick page
//The Html
<table>
<colgroup></colgroup>
<colgroup></colgroup>
<colgroup></colgroup>
<colgroup></colgroup>
<colgroup></colgroup>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
//The Js
$(function(){
$("table").delegate('td','mouseover mouseleave', function(e) {
if (e.type == 'mouseover') {
$(this).parent().addClass("hover");
$("colgroup").eq($(this).index()).addClass("hover");
}
else {
$(this).parent().removeClass("hover");
$("colgroup").eq($(this).index()).removeClass("hover");
}
});
})
Check out the fiddle here

Related

Firefox doesn't style :empty elements

Here is a snippet with a sample code:
table {
border-collapse: collapse;
}
th, td {
border: 1px solid gray;
padding: 3px 6px;
}
[contenteditable]:empty:not(:focus)::before {
content: attr(data-placeholder);
color: gray;
font-size: .9rem;
}
<table>
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
</tr>
</thead>
<tbody>
<tr>
<td contenteditable="true" data-placeholder="Firstname"></td>
<td contenteditable="true" data-placeholder="Lastname"></td>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
</tr>
</tbody>
</table>
In Chrome and Safari, it works pretty much as expected:
For some reason, in Firefox, the contenteditable tds don't get the placeholder:
How can I fix this issue?
EDIT: It seems this is issue is more related to :empty than [contenteditable] as this code kinda works:
[contenteditable]:not(:focus)::before {
content: attr(data-placeholder);
color: gray;
font-size: .9rem;
}
But then the placeholder is always shown, hence not being an actual "placeholder" anymore.
Firefox has incompatibility with td:empty not because there is an issue with the css engine but because the way Firefox handles contenteditable is by adding a br tag into the region.
An alternate way to do this would be to change the html to use inputs that you disable when content is present.
table {
border-collapse: collapse;
}
th,
td {
border: 1px solid gray;
padding: 0;
}
table input {
border: none;
}
[placeholder] {
color: gray;
font-size: .9rem;
}
<table>
<thead>
<tr>
<th>Forename</th>
<th>Surname</th>
</tr>
</thead>
<tbody>
<tr>
<td><input placeholder="Forename"></td>
<td><input placeholder="Surname"></td>
</tr>
<tr>
<td><input placeholder="Forename" value="John" disabled></td>
<td><input placeholder="Forename" value="Doe" disabled></td>
</tr>
</tbody>
</table>
As #DreamTeK mentioned, Firefox seems to add a <br> in empty contenteditable elements.
His answer, using input instead of contenteditable is valid.
In case you have no choice but to use contenteditable, here is a fix in JS to remove this unwanted br:
// VanillaJS
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll('[contenteditable]').forEach((elt) => {
if (elt.children.length === 1 && elt.firstChild.tagName === "BR") {
elt.firstChild.remove();
}
})
});
// jQuery
/*
$(document).ready(() => {
$('[contenteditable]').each((_, elt) => {
if ($(elt).children().length === 1 && $(elt).has('br')) {
$(elt).html('');
}
});
});
*/
table {
border-collapse: collapse;
}
th, td {
border: 1px solid gray;
padding: 3px 6px;
}
[contenteditable]:empty:not(:focus)::before {
content: attr(data-placeholder);
color: gray;
font-size: .9rem;
}
<table>
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
</tr>
</thead>
<tbody>
<tr>
<td contenteditable="true" data-placeholder="Firstname"></td>
<td contenteditable="true" data-placeholder="Lastname"></td>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
</tr>
</tbody>
</table>

Set the first tr to fixed without losing the width

this is my fiddlejs: [https://jsfiddle.net/uj8gbeL1/]
Im trying to make fixed the first row of the table, but when i try to set the style postion:fixed, this row has a different width
How can i fix this issues without setting a "static" width to every th element?
You will solve this by using:
<tr class="globalTr" style="position:sticky;top:0;z-index:1">
Or better, put it in the css:
.globalTr:first-child {
position: sticky;
top: 0;
z-index: 1;
}
However, your code could be formatted a lot better.
Here is an example, please read the comments in the html:
div {
width: 100%;
height: 200px;
overflow: auto;
}
table {
font-family: sans-serif;
border-collapse: collapse;
}
thead {
position: sticky;
top: 0;
z-index: 1;
}
th, td {
border: 1px solid #369;
padding: 10px;
}
th {
background: #369;
color: white;
}
td {
background: aliceblue;
}
<div>
<table>
<thead>
<tr>
<th>Heading1</th> <!-- th is for headings -->
<th>Heading2</th>
</tr>
</thead>
<!-- use thead and tbody -->
<tbody>
<tr>
<td>Content</td> <!-- td is for cells -->
<td>Content</td>
</tr>
<tr>
<td>Content</td>
<td>Content</td>
</tr>
<tr>
<td>Content</td>
<td>Content</td>
</tr>
<tr>
<td>Content</td>
<td>Content</td>
</tr>
<tr>
<td>Content</td>
<td>Content</td>
</tr>
<tr>
<td>Content</td>
<td>Content</td>
</tr>
</tbody>
</table>
</div>
Use CSS position:sticky;top:0; instead of position:fixed;.

Move :after element onto new line on text truncation

I am building a table that has truncated headers and content using the :after selector.
I want to be able to move the :after content onto a new line only where the header text is truncated, is there a way of doing this only using CSS?
I am currently using jQuery and window.resize listeners to implement a solution similar to the one found here: HTML - how can I show tooltip ONLY when ellipsis is activated but would prefer to be able to do it without the extra overhead of the jQuery and the listeners
An example of the HTML and CSS is:
<style>
table, th, td {
max-width: 75%;
table-layout: fixed;
border: 1px solid black;
}
th {
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
}
th:after {
content: ":";
}
</style>
</head>
<body>
<table width="600px">
<thead>
<tr>
<th width="5%">I'm a very long table header that is going to get truncated in the browser</th>
<th width="10%">small</th>
<th width="20%">medium</th>
<th width="65%">large</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>One</td>
<td>Java</td>
<td>01/01/2010</td>
</tr>
<tr>
<td>2</td>
<td>Two</td>
<td>C</td>
<td>01/02/2010</td>
</tr>
</tbody>
</table>
</body>
</html>
If you want your :after element content should come on next line then try following code.
th:after {
content: ":";
display:block;
clear:both:
}

Create transparent HTML table [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I would like to create HTML table like this example.
How I can preserve the header gray and make the data to look like the same way?
Here is a working snippet.
border-spacing removes the spacing between cells
tr:first-of-type targets only the first row to apply background color
td:nth-child(odd) targets only the first column to make all fields bold
table{
border-spacing:0;
}
tr:first-of-type{
background:lightgray;
}
td:nth-child(odd){
font-weight:bold;
}
th,td{
padding:5px;
}
<table>
<tr>
<td>Plan / Feature</td>
<td>Standard</td>
</tr>
<tr>
<td>Plan Type</td>
<td>Annual</td>
</tr>
<tr>
<td>Email Support</td>
<td>Yes</td>
</tr>
</table>
Try this:
CSS:
table {
border-collapse: collapse;
}
table th, table thead tr {
background: #ccc;
font-weight: bold;
}
table tr td:first-child {
font-weight: bold;
}
table tr td {
background-color: transparent;
}
Example HTML:
<table>
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td>Column 1</td>
<td>Column 2</td>
</tr>
</tbody>
</table>
JSFiddle
You can style the header of a table with css
<table>
<tr>
<th>header</th>
<th>header</th>
</tr>
<tr>
<td>content</td>
<td>content</td>
</tr>
</table>
th { background-color: #ff0000; }
Or see this fiddle: http://jsfiddle.net/h4817knp/6/
Edit: To avoid the gaps in the header add
table { border-collapse: collapse; }
to the css
http://jsfiddle.net/1yn99g13/1/
You just set the background colour on the elements you want it to appear on.
There's nothing complicated about this.
table, tbody, tr, th, td { background: transparent; }
thead { background: #aaa; }
You should, of course, use CSS:
You need to get rid of the default spacing in the table:
table {
border-collapse: collapse;
border-spacing: 0;
}
You need to set the background color of the table head element:
table thead {
background-color: lightgrey;
}
You need to define your cell sizes:
td {
width: 100px;
height: 25px;
}
Working Fiddle
table {
border-collapse: collapse;
border-spacing: 0;
}
td {
width: 100px;
height: 25px;
}
table thead {
background-color: lightgrey;
}
<table>
<thead>
<tr>
<td>HeaderA</td>
<td>HeaderB</td>
</tr>
</thead>
<tbody>
<tr>
<td>Item 1</td>
<td>Value</td>
</tr>
</tbody>
</table>

Use CSS only to change behavior of tables cells under a table header when table header is selected

Is it possible to change apply css for the table cells under a table header that is selected? I don't care how th got selected I just want to use css only to apply something to those table cells where their table header is selected like italicized and underline.
<table>
<tr>
<th>col1</th>
<th class="selected">col2</th>
</tr>
<tr>
<td>cell1a</td>
<td>cell2b</td>
</tr>
<tr>
<td>cell1aa</td>
<td>cell2ba</td>
</tr>
</table>
css: (prototype...)
for the column position of the th row that is selected on this table
apply this css to the column position of all the td elements of this table
{
font-style:italic;
text-decoration: underline;
}
HERE is an article on how to color the whole row on mouse hover.
HERE is a post that gives an example how to style an element on click with css, by utilizing a checkbox
combining those two from above, i wrote you a simple example on how to achieve your goal: FIDDLE
basically you just put checkboxes in your th and use their checked state to color the entire column by inserting a huge styled background using ::after selector and hiding its overflow:
you can style the checkboxes as you see fit. put an image instead or make them disappear if you like.
HTML:
<table>
<tbody>
<tr>
<th></th>
<th><input type="checkbox">50kg</input></th>
<th><input type="checkbox">55kg</input></th>
<th><input type="checkbox">60kg</input></th>
<th><input type="checkbox">65kg</input></th>
<th><input type="checkbox">70kg</input></th>
</tr>
<tr>
<th>160cm</th>
<td>20</td>
<td>21</td>
<td>23</td>
<td>25</td>
<td>27</td>
</tr>
<tr>
<th>165cm</th>
<td>18</td>
<td>20</td>
<td>22</td>
<td>24</td>
<td>26</td>
</tr>
<tr>
<th>170cm</th>
<td>17</td>
<td>19</td>
<td>21</td>
<td>23</td>
<td>25</td>
</tr>
<tr>
<th>175cm</th>
<td>16</td>
<td>18</td>
<td>20</td>
<td>22</td>
<td>24</td>
</tr>
</tbody>
CSS:
input[type="checkbox"] {
margin: 0;
border: 0 none;
padding: 0;
}
table {
border-spacing: 0;
border-collapse: collapse;
overflow: hidden;
z-index: 1;
}
td, th {
cursor: pointer;
padding: 10px;
position: relative;
}
th input[type="checkbox"]:checked::after {
background-color: #ffa;
content: '\00a0';
height: 10000px;
left: 0;
position: absolute;
top: -5000px;
width: 100%;
z-index: -1;
}

Resources