CSS - Select either first row or head row in HTML Table - html

I have a mixed set of tables on the website. Some have the thead present and others directly start with a tr without having thead.
Since I want the first row to become sticky and scroll with the user till last row in the table, I added the following code:
.wp-block-table tr:first-child {
left: 0;
position: sticky;
top: 0;
z-index: 1;
width: 25vw;
background: white;
}
But the issue now is that the table without thead scrolls but when a table has thead present then the scroll starts from the second row (i.e after skipping the thead)
I know I need to fix the table HTML so that they are consistent everywhere but in the meantime is there any CSS selector which can handle the sticky scrolling in both the cases.
If thead is not present then use my above code and if thead is present then I will need to add some extra CSS code. I need help with that extra code. Never been in such a situation before.

You can apply first-child to find the first child (thead or tbody) and the first-child inside of it to find the first tr:
table > *:first-child > tr:first-child {
background-color: green;
}
<table>
<thead>
<tr><td>THEAD</td></tr>
</thead>
<tbody>
<tr><td>TBODY</td></tr>
</tbody>
</table>
----------------------------------------
<table>
<tbody>
<tr><td>THEAD</td></tr>
<tr><td>TBODY</td></tr>
</tbody>
</table>

Related

Hide thead but keep its cells width in tbody

I always use Bootstrap grid classes in thead th tags so I'll no longer need repeating classes on tbody cells. for example:
<table>
<thead>
<tr>
<th class="col-xs-2">#</th>
<th class="col-xs-10">Title</th>
</tr>
</thead>
<tbody>
<tr><td>150</td><td>Long text in here</td></tr>
<tr><td>150</td><td>Long text in here</td></tr>
<tr><td>150</td><td>Long text in here</td></tr>
<tr><td>150</td><td>Long text in here</td></tr>
<tr><td>150</td><td>Long text in here</td></tr>
</tbody>
</table>
Now, I'm implementing a scenario that I should not use table headers. I tried display: none and visibility: hidden on thead but none of them works.
I guess I have following solutions (which are all bad INMHO!):
Add grid classes to each tbody cell (which in my large dynamic table is a bad thing)
Use css to target cells by the index eg: nth-child() which is also bad, because of duplicated CSS rules, and will be a pain in the ass becase table may dynamically change and I'll always need a SCSS compile!
Give thead a 1px height, with no inner text or anything.
Is there a better solution?
Something like this should work:
thead p {
margin: 0;
opacity: 0;
height: 0;
}
Of course the p is just an example, you can do this with any other tag.
Updated Fiddle: https://jsfiddle.net/8brbuy6v/1
Thanks to #Johann Kratzik suggestion, I managed to solve my own problem by hiding thead contents and using height: 0 on thead itself.
thead { opacity: 0; border: 0 none; height: 0; }
thead * { margin: 0; padding: 0; border: 0 none; height: 0px; }

Change the td padding for only one table, not effect style of other tables?

I have several tables and want to pad them differently. I've tried the following:
table#mapTable > tr > td{
padding-left: 4px;
padding-bottom: 20px !important;
}
for table with the id 'mapTable', but it hasn't been working (nothing happens). Same result, when trying 'margin-bottom' rather than 'padding-bottom'.
Is it possible to change <td> padding of only one table? I have a custom <td> style that I don't want to mess with for all the other tables.
For completeness, here's the table:
<table id='mapTable'>
<tr><td>stuff</td><td>stuff</td></tr>
<tr><td>info</td><td>info</td></tr>
</table>
Thanks!
You are selecting the tds wrong. Do not use > just use spaces.
Spaces find elements that are children of the previous listed element.
table#mapTable tr td{
padding-left: 4px;
padding-bottom: 20px !important;
}
<table id='mapTable'>
<tr><td>stuff</td><td>stuff</td></tr>
<tr><td>info</td><td>info</td></tr>
</table>
<table id='noStyle'>
<tr><td>stuff</td><td>stuff</td></tr>
<tr><td>info</td><td>info</td></tr>
</table>
There is no need to select table#mapTable tr td
It's enough to write
#mapTable td {
padding-left: 4px;
padding-bottom: 20px !important;
}
(= all <td> elements inside id "mapTable")
You got an answer already, just some more explanation:
table > tr won’t ever match table rows – because table rows never are children of a table.
They are children of a tbody, thead or tfoot element. The fact that there is no such element in your HTML code is not relevant here – in that situation, browsers create a tbody element implicitly when creating the DOM – they have to, because the specification says so.
You can easily verify that using your browser’s DOM inspector. Even for your minimal table example above, you’ll see that there is a tbody.

How to align TH Header with TD in TBody

I'm having problems trying to embed a table in an existing HTML page with some CSS.
This CSS is hiding the header of the table by default with a style definition like:
.tablestuff thead {
display: none;
}
But I want the table to show, so I tried setting the style on the thead element with "display:block" (with javascript). That makes the header display, but the columns of the header don't line up with the td columns.
I have reduced my HTML to the following (hopefully with minimal typos) and showing the style on the thead element as set by javascript.
<div class="tablestuff">
<table border="1">
<thead style="display:block">
<tr>
<th id="th1" style="width: 20px"></th>
<th id="th2" style="width: 20px"></th>
</tr>
</thead>
<tbody>
<tr>
<td headers="th1" style="width: 20px"></td>
<td headers="th2" style="width: 20px"></td>
</tr>
</tbody>
</table>
</div>
How can I make both the header show and also align correctly with the td columns?
CSS includes more display modes than the commonly used none, inline, inline-block, and block. There are quite a few, in fact.
In this case, it appears what you want to use instead of display:block; is display:table-header-group;.
Here are some examples of the different styles, as applied to your table:
http://jsfiddle.net/CrYdz/1
The problem is caused by the display:block in the style attribute for the thead.
Change it to display:table-header-group
When you want to show the thead element use this value: display: table-header-group;
To set same width for table header and table body in table:
<table style="table-layout:fixed">
In case nothing fixes it. move your <tr> inside thead to tbody.
this was the only solution in my case since i had so many complications already.
Maybe the content of the THs is wider than the content of the TDs and in reality the width is not 20px as set.
So, because you first load the page without the thead, the table gets the width of the TDs. Then, when you display the THEAD by js, the table width continues being the same but probably the THs have different width.
By default, th and td should be aligned. If you want to leave it as default, just put display: unset:
.tablestuff thead {
display: unset;
}
Plain JavaScript:
document.querySelector("thead").style.display = "unset";
jQuery:
To make the jQuery's $(".tablestuff thead").show() method works, your css needs to be defined like this:
.tablestuff thead[style*='display: block'] {
display: unset !important;
}
This is because .show() will set the display to block by default. The above css will set it back to unset whenever it's set to block.
show and hide th instead of thead with the css
/* to hide */
.tablestuff thead th{
display: none;
}
/* to show */
.tablestuff thead th{
display: table-cell;
}

Keep table head visible [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
I need my html table's body to scroll and its head to stay put
I have a basic table:
<div>
<table>
<thead><tr><th>col 1</th><th>Col 2</th></tr></thead>
<tbody><tr><td>sweet</td><td>tooth</td></tr></tbody>
</table>
</div>
So I have 200 rows in the body section and want to make it so that when I scroll the thead section stays on top while everything else flows underneath it. Is there anyway to do this in CSS?
Following styles:
div {
max-height:400px;
overflow:auto;
}
I can't figure out how to do this. I tried to make the scroll part just tbody, but when I do that the max-height portion doesn't take effect for some odd reason. Also if I break it up into 2 tables then the columns won't be the correct widths. I also can't state what the widths are beforehand as the data changes rapidly so it needs to be able to be changeable.
Any ideas? I'm lost.
edit: Actually, this appears to break the connection between the header and the table, so the header columns don't line up. I'll leave this here though in case someone can get it to work.
How about this. The header is rendered position:absolute, so it won't move. But you have to explicitly position the table down to give it room.
.relative {
position:relative;
}
.table {
margin-top:18px;
max-height:400px;
overflow:auto;
}
thead {
position:absolute;
top: -18px;
}
​
<div class="relative">
<div class="table">
<table>
<thead><tr><th>col 1</th><th>Col 2</th></tr></thead>
<tbody>
<tr><td>sweet</td><td>tooth</td></tr>
</tbody>
</table>
</div>
</div>​
Change 18px to be whatever the height of your thead should be.
Working sample: http://jsfiddle.net/EYjd5/1/
One of the possible methods is to create another table inside the main tbody, limit its height, and make sure you get scrollbars on overflow by using overflow: scroll;. Of course, for the columns to line up, you need to imitate the effect of the table header, I did that by inserting a hidden row identical to the header in the end of the new table (you should hide it using visibility: hidden; opacity: 0; not using display: none; otherwise this won't work). Here's a sample:
HTML:
<table>
<thead><tr><th>Name of show</th><th>Greatness</th></tr></thead>
<tbody><table class = "limitedcontent">
<tr><td>Glee</td><td>100%</td></tr>
<tr><td>Glee</td><td>100%</td></tr>
<tr><td>Glee</td><td>100%</td></tr>
<tr><td>Glee</td><td>100%</td></tr>
<tr><td>Glee</td><td>100%</td></tr>
<tr><td>Glee</td><td>100%</td></tr>
<tr><td>Glee</td><td>100%</td></tr>
<tr class = "placehold"><th>Name of show</th><th>Greatness</th></tr>
</table></tbody>
</table>
CSS:
.limitedcontent {
height: 150px; /*or whatever your limit is*/
overflow-y: scroll;
overflow-x: hidden;
display: inline-block;
}
.placehold {
visibility: hidden;
opacity: 0;
height: 0px;
overflow: hidden;
}
And a little demo: little link.
I hope that helped in any manner!
In case you're a jQuery-lover, you can use the DataTables jQuery plug-in to achieve exactly that.

Trying to style the first tbody different than others without introducing another class

I have a table with multiple tbody's, each of which has a classed row, and I want it so that the classed row in the first tbody has style differences, but am unable to get tbody:first-child to work in any browser. Perhaps I am missing something, or maybe there is a workaround.
Ideally, I would like to provide the programmers with a single tbody section they can use as a template, but will otherwise have to add a class to the first tbody, making for an extra test in the programming.
The html is straightforward:
<tbody class="subGroup">
<tr class="subGroupHeader">
<th colspan="8">All Grades: Special Education</th>
<td class="grid" colspan="2"><!-- contains AMO line --></td>
<td><!-- right 100 --></td>
</tr>
<tr>...</tr> <!-- several more rows of data -->
</tbody>
There are several tbody's per table. I want to style the th and td's within tr.subGroupHeader in the very first tbody differently than the rest. Just to illustrate, I want to add a border-top to the tr.subGroupHeader cells.
The tr.subGroupHeader will be styled with a border-top, such as:
table.databargraph.continued tr.subGroupHeader th, table.databargraph.continued tr.subGroupHeader td {
border-top: 6px solid red;
}
For the first tbody, I am trying:
table.databargraph.continued tbody:first-child tr.subGroupHeader th {
border-top: 6px solid blue ;
}
However, this doesn't seem to work in any browser (I've tested in Safari, Opera, Firefox, and PrinceXML, all on my Mac)
Curiously, the usually excellent Xyle Scope tool indicates that the blue border should be taking precedence, though it obviously is not. See the screenshot at http://s3.amazonaws.com/ember/kUD8DHrz06xowTBK3qpB2biPJrLWTZCP_o.png
This screenshot shows (top left) the American Indian th is selected, and (bottom right), shows (via black instead of gray text for the css declaration), that, indeed, the blue border should be given precedence. Yet the border is red.
I may be missing something fundamental, like pseudo-classes not working for tbodys at all... This really only needs to work in PrinceXML, and maybe Safari so I can see what I'm doing with webkit-based css tools.
Note I did try a selector like tr.subGroupHeader:first-child, but such tr's apparently consider the tbody the parent (as I would suspect), thus made every border blue.
Thanks...
Sorry folks, but I'm gonna answer my own question. But I do appreciate the help.
Instead of:
table.databargraph.continued tbody:first-child tr.subGroupHeader th {
border-top: 6px solid blue ;
}
What I should have done was:
table.databargraph.continued > tbody:first-of-type tr.subGroupHeader th {
border-top: 2px solid blue !important ;
}
Is the tbody really the first child of the table? If there is any other element that is an earlier sibling (e.g. a thead?) than this will not work.
I've tried the following test code and it seems to work:
<html>
<head>
<style type="text/css">
table tbody tr th {
border-top: 6px solid red;
}
table tbody:first-child tr th {
border-top: 6px solid blue;
}
</style>
</head>
<body>
<table>
<tbody>
<tr><th colspan="2">Title</th></tr>
<tr><td>Data</td><td>Data</td></tr>
</tbody>
<tbody>
<tr><th colspan="2">Title</th></tr>
<tr><td>Data</td><td>Data</td></tr>
</tbody>
<tbody>
<tr><th colspan="2">Title</th></tr>
<tr><td>Data</td><td>Data</td></tr>
</tbody>
</table>
</body>
</html>
When adding a thead element, this stops working, because there is no tbody that is the first child of the table. What does seem to work in that case (at least in Opera) is the following:
table thead + tbody tr th {
border-top: 6px solid blue;
}
This selects all tbody that directly follow a thead.