stacking context on table element(head and body) - css

I was stuck with one CSS stacking context issue, I simplified it to following simple case.
A simple table as following code, I translated header in order to achieve scrolling effect, while the header was always covered by those translated td cells.
I have read several articles, including that famous one "What No One Told You About Z-Index", and try to add both translate and z-index css properties on thead and tbody, and I 'guess' they should be in the same stacking context, so z-index will work, while I failed, does the failure due to table has some special constraints on stacking context? The only solution I can find now is switching thead and tbody position in the html by putting thead after tbody tag.
Full Case is here.
.m-table {
width: 40%;
font-size: 14px;
text-align: center;
border: 1px solid #e6eaf9;
background: #fafbff;
transform: translateY(0);
}
.m-table th,
.m-table td {
padding: 16px;
border: 1px solid #ddd;
background: #effff0;
}
.m-table th {
background: #e6eaf9;
}
.m-table thead {
transform: translateY(25px);
margin-bottom: 10px;
}
td label.u-angle {
display: inline-block;
width: 10px;
height: 10px;
background: #79c5ff;
transform: rotate(45deg);
}
<table class="m-table">
<thead>
<tr>
<th>Price</th>
<th>Algorithm Factor</th>
<th>Links</th>
</tr>
</thead>
<tbody>
<tr>
<td>$1,326</td>
<td>
<label class="u-angle"></label>
</td>
<td>
Detail
</td>
</tr>
</tbody>
</table>

Related

Solution for jumping Safari table caption?

anyone has a solution for what appears to be a Safari bug? When a transform CSS is applied to a table content, the caption jumps to the end of table.
There was a hint using "will-change: transform" for the caption with similar case, but unfortunately it does not work here.
See codepen:
https://codepen.io/anon/pen/GxVWzV
HTML:
<table>
<caption>
Caption
</caption>
<thead>
<tr>
<th></th>
<th>Header</th>
</tr>
</thead>
<tbody>
<tr onclick="collapse(this)">
<td></td>
<td>Cell</td>
</tr>
</tbody>
</table>
CSS
tbody tr > td:first-child:before {
content: ' ';
display: inline-block;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 6px solid black;
vertical-align: middle;
margin-right: .7rem;
transform: translateY(-2px);
transition: transform .2s ease-out;
pointer-events:auto;
}
tbody tr.collapsed > td:first-child:before {
content: ' ';
transform: rotate(90deg) translateX(-3px);
}
JS:
function collapse(e) {
e.classList.toggle("collapsed");
}
NOTE: Fixed in Safari 15.1
I encountered a similar issue with caption-side: top; in iOS Safari.
Try add the following CSS:
caption {
display: block;
}
I can't believe this isn't fixed by now.
What I did, in jQuery, is detach the caption and then reattach:
$('table').prepend($('caption').detach());

How can I get wkhtmltopdf to display th and td background gradients?

I need to add background gradients to some td and th elements in page which gets converted to PDF, however I'm getting some very strange behavior from wkhtmltopdf, so when I do this:
table {
width: 100%;
border-collapse: collapse;
}
th {
height: 60px;
border: 1px solid Black;
}
td {
height: 100px;
background: -webkit-linear-gradient(top, #ccc 0%, #888 100%);
border: 1px solid Black;
}
<table>
<tr>
<th></th>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td></td>
</tr>
</table>
The height of the th seems to encroach on each subsequent td somehow. All is well if I remove the th or set its height to a whole multiple of the td height.
Anyone got any insight into what's going on here? My HTML is hard to change so I'm hoping to be able to get this working using CSS alone, or wkhtmltopdf settings.
Edit:
Some screenshots before the bounty expires:
Here's how it looks in a webkit browser:
Here's what wkhtmltopdf does to it:
And one further observation: it doesn't have to be a th to cause the problem, as changing it to a similarly targeted <td class='th'> will cause the same effect.
wkhtmltopdf still uses the old (deprecated) webkit gradient syntax. Try this:
-webkit-gradient(linear, left top, left bottom, from(#ccc), to(#888));
For me it was as simple as adding
background-repeat: no-repeat !important;
What you think about this?
<style>
.table {
width: 100%;
display:table;
border-collapse: collapse;
}
.tr {
height: 60px;
display:table-row;
border: 1px solid Black;
}
.td, .th{
height: 60px;
border: 1px solid Black;
display:table-cell;
background: -webkit-linear-gradient(top, #ccc 0%, #888 100%);
}
</style>
<div class="table">
<div class="tr">
<div class="th"></div>
</div>
<div class="tr">
<div class="td"></div>
</div>
<div class="tr">
<div class="td"></div>
</div>
</div>
Is better to use DIV instead of the tables. You can do same thing with small changes.
And is better for you to add CSS inline to HTML if you work PDF or send on email like template.
UPDATE:
You can do this:
<style>
table {
width: 100%;
border-collapse: collapse;
}
th {
height: 60px;
}
td{height: 100px;}
td, th {
background: -webkit-linear-gradient(top, #ccc 0%, #888 100%);
border: 1px solid Black;
}
</style>
<table>
<tr>
<th></th>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td></td>
</tr>
</table>
or jQuery to replace tables with nested divs:
<style>
.table {
width: 100%;
display:table;
border-collapse: collapse;
}
.table .tr{
display:table-row;
}
.table .th{
height: 60px;
font-weight:bold;
}
.table .td{height: 100px;}
.table .th,
.table .td {
border: 1px solid Black;
display:table-cell;
background: -webkit-linear-gradient(top, #ccc 0%, #888 100%);
}
</style>
<table>
<tr>
<th>a</th>
</tr>
<tr>
<td>b</td>
</tr>
<tr>
<td>c</td>
</tr>
</table>
<script>
$(document).ready(function(){
$("table").each(function(a,table){
var i=a;
$(table).after('<div class="table" id="table-'+i+'"></div>');
var currentTH = $(this).parent().find('th');
$(currentTH).each(function(){
var content=$(this).html();
$('#table-'+i).append(' <div class="tr"><div class="th">'+content+'</div></div>');
});
var currentTD = $(this).parent().find('td');
$(currentTD).each(function(){
var content=$(this).html();
$('#table-'+i).append(' <div class="tr"><div class="td">'+content+'</div></div>');
});
$(this).remove();
});
});
</script>
We had to upgrade wkhtmltopdf due to security reasons and we experienced the same problem, however after struggling with CSS I managed to find a solution that worked for us, for example, the following CSS:
.TableRecords_Header {
color:#EAEAEA;
font-weight: normal;
background: #0F5D85 url(/RichWidgets/img/bar_gradient.png);
white-space: nowrap;
line-height: 18px;
padding: 4px 6px 4px 6px;
border-right: 1px solid white;
font-size: 14px;
}
Applied to any table <th> or <tr> cells, renders something like this:
Gradient Bug
It turns out that this version of webkit has problems handling "repeat-x" CSS property, so, to solve this issue I have used this CSS3 Equivalent:
.TableRecords_Header {
background-repeat: no-repeat !important;
background-size: 100% 23px !important;
}
Where background-repeat: no-repeat !important; tells webkit not to use background repetition eliminating the problem.
As for background-size, the value 100% does the same as the original repeat-x, and the 23px is the height of the image that produces your gradient. in this case is the height of /RichWidgets/img/bar_gradient.png.
When we added this CSS3 style the PDF rendered correctly as shown in the following image:
Gradient problem solved
Best Regards,
Nuno Guedes
Use inline css for this page which convert to pdf.

How can you center text (vertically and horizontally) in a table, and prevent cell resizing?

Overall what I'm aiming for is a table where all the text is centred, and when text is entered, the cells won't resize.
Originally my code was like this:
HTML
<table id="main_table">
<tr>
<td><div/></td>
<td><div/></td>
<td><div/></td>
<td><div/></td>
<td><div/></td>
</tr>
<!--several more rows here-->
</table>
CSS
#table-main
{
height:1000px;
width: 100%;
border-collapse: collapse;
border-spacing: 0;
table-layout:fixed;
}
#table-main td
{
background-color: #F3F5EF;
border: 1px #bbb solid;
color: #333;
font-family: sans-serif;
font-size: 100%;
-webkit-user-select: none; /* Chrome/Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+ */
cursor: default;
}
#table-main td > div {
overflow: hidden;
text-align: center;
vertical-align: middle;
height: 100%;
line-height: 20px;
}
Which appears like this. Not that the rows with text in them are higher than rows without text.
I read that you can stop this resizing by adding:
display: inline-block;
This does stop the resizing, but it then prevents the text from being centered:
Is there any way to have the best of both worlds? And in addition, is there any way to centre the text vertically as well?
Posted an example on Fiddle
CSS
table {width:100%;;}
table, th, td
{
border: 1px solid #eee;
}
table td{ padding:10px;
width:19% !important;
vertical-align: middle;
height: 80px !important;
overflow:visible;
line-height: 40px;
}
td > div {
overflow: hidden;
text-align: center;
line-height: 14px;
display:inline-block
}
HTML
<table id="main_table">
<tr>
<td align="center"><div>1</div></td>
<td align="center"><div>Please note, the easing function names changed in version 1.2.Please note, the easing function names changed in version 1.2. </div></td>
<td align="center"><div>3</div></td>
<td align="center"><div>4</div></td>
<td align="center"><div>5</div></td>
</tr>
</table>
EDIT
CSS update for better vertical align (please note rest of text is hidden ... Fiddle and old one
Okay while hsobhy posted some working code, I think a better solution is to explain how to fix the original code. Adding display: inline-block; to the div worked fine to get rid of the cell resizing, but then:
The table cells (not the div) needed to be specified as centered in order to get the horizontal centering:
#main_table td, #main_table th{
/*All the other properties*/
text-align: center;
}
I was setting the height of the div, which I shouldn't have. Removing it gave me vertical centering as well:
#table-main td > div {
/*Other stuff/*
height: 100%; /*This needed to go/*
}

Spacing between thead and tbody

I have a simple html table like this:
<table>
<thead>
<tr><th>Column 1</th><th>Column 2</th></tr>
</thead>
<tbody>
<tr class="odd first-row"><td>Value 1</td><td>Value 2</td></tr>
<tr class="even"><td>Value 3</td><td>Value 4</td></tr>
<tr class="odd"><td>Value 5</td><td>Value 6</td></tr>
<tr class="even last-row"><td>Value 7</td><td>Value 8</td></tr>
</tbody>
</table>
And I would like to style it the following way:
header row with a box-shadow
whitespace between the header row and the first body row
I have tried different things:
table {
/* collapsed, because the bottom shadow on thead tr is hidden otherwise */
border-collapse: collapse;
}
/* Shadow on the header row*/
thead tr { box-shadow: 0 1px 10px #000000; }
/* Background colors defined on table cells */
th { background-color: #ccc; }
tr.even td { background-color: yellow; }
tr.odd td { background-color: orange; }
/* I would like spacing between thead tr and tr.first-row */
tr.first-row {
/* This doesn't work because of border-collapse */
/*border-top: 2em solid white;*/
}
tr.first-row td {
/* This doesn't work because of border-collapse */
/*border-top: 2em solid white;*/
/* This doesn't work because of the td background-color */
/*padding-top: 2em;*/
/* Margin is not a valid property on table cells */
/*margin-top: 2em;*/
}
See also: http://labcss.net/#8AVUF
Does anyone have any tips on how I could do this? Or achieve the same visual effect (i.e. bod-shadow + spacing)?
I think I have it in this fiddle and I updated yours:
tbody:before {
content: "-";
display: block;
line-height: 1em;
color: transparent;
}
EDIT better & simpler:
tbody:before {
content:"#";
display:block;
line-height:10px;
text-indent:-99999px;
}
This way text is really invisible
Moreover you can use Zero-Width Non-Joiner to minimize sinsedrix CSS:
tbody:before {line-height:1em; content:"\200C"; display:block;}
This will give you some white space between the header and table content
thead tr {
border-bottom: 10px solid white;
}
Although setting the border colour is a bit of a cheat method, it will work fine.
Form investigation, you can't set box-shadow to a table row, but you can to table cells:
th {
box-shadow: 5px 5px 5px 0px #000000 ;
}
(I'm not sure how you want the shadow to look like, so just adjust the above.)
This worked for me on Chrome (for other browsers I don't know).
.theTargethead::after
{
content: "";
display: block;
height: 1.5em;
width: 100%;
background: white;
}
Such css code creates an empty white space between the thead and the tbody of the table.
If I set the background to transparent, the first column of the above tr > th elements shows its own color (green in my case) making about the first 1 cm of the ::after element green too.
Also using the "-" sign in the row content : "-"; instead of the empty string "" can create problems when exporting the printed pages to file, i.e. pdf. Of course this is parser/exporter dependent.
Such exported file opened with a pdf editor (for ex.: Ms word, Ms Excel, OpenOffice, LibreOffice, Adobe Acrobat Pro) could still contain the minus sign. The empty string doesn't have the same issue.
No problems in both cases if the printed html table is exported as image: nothing is rendered.
I didn't notice any issue even using
content : "\200C";
So box-shadow doesn't work well on the tr element... but it does work on a pseudo content element; sinsedrix put me on the right track and this is what I ended up with:
table {
position: relative;
}
td,th {padding: .5em 1em;}
tr.even td { background-color: yellow; }
tr.odd td { background-color: orange; }
thead th:first-child:before {
content: "-";
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: -1;
box-shadow: 0 1px 10px #000000;
padding: .75em 0;
background-color: #ccc;
color: #ccc;
}
thead th {
padding-bottom: 2em;
}
While all the solutions above are great, the result is inconsistent across browsers, so I figured out a better way to do it based on my heinous experience with email templates.
Just add a dummy tbody in-between the actual tbody and the thead, nested in the dummy tbody should be a td with height set to the desired spacing. Example below
<table>
<thead>
<tr>
<td>
</td>
</tr>
</thead>
// Dummy tbody
<tbody>
<tr>
<td class="h-5"></td>
</tr>
</tbody>
// Actual tbody
<tbody class="rounded shadow-outline">
<tr v-for="(tableRow, i) in tableBody" :key="`tableRow-${i}`">
<td v-for="tableRowItem in tableRow" :key="tableRowItem" class="table-body">
{{ tableRowItem }}
</td>
</tr>
</tbody>
</table>
This should do the trick:
table {
position: relative;
}
thead th {
// your box shadow here
}
tbody td {
position: relative;
top: 2rem; // or whatever space you want between the thead th and tbody td
}
And this should play nice with most browsers.

How to apply padding to a column using <col> and CSS in Firefox?

Example:
<style type="text/css">
table {
border: 1px solid red;
border-collapse: collapse;
text-align: left;
}
#col-1 {
padding-left: 20px;
background-color: tan;
}
#specific-cell {
padding-left: 20px;
}
</style>
<table>
<col id="col-1">
<col id="col-2">
<tr>
<th>foo</th>
<th>bar</th>
</tr>
<tr>
<td>data1</th>
<td>data2</th>
</tr>
<tr>
<td id="specific-cell">data1</th>
<td>data2</th>
</tr>
<tr>
<td>data1</th>
<td>data2</th>
</tr>
</table>
The color is applied to the column but not the padding. If I use classes/ids on cells directly, it works.
Am I forced to use them, or is there a way taking advantage of the <col> tag?
It's not supposed to work, at least with CSS 2.1. You may have a look at the CSS 2.1 table columns specification.
You can circumvent this by using :first-child and +:
/* first column */
td:first-child {
padding-left: 20px;
}
/* second column */
td:first-child + td {
padding-left: 10px;
}
/* third columns */ {
td:first-child + td + td {
padding-left: 0;
}
This works for me in IE with the following DOCTYPE
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
and the styles
#col-1 {
padding-left: 50px;
background-color: tan;
}
#col-2 {
padding-left: 100px;
background-color: lightgreen;
}
What doctype are you using... and what browser are you using...
hmm... just checked doesn't seem to work in Firefox
Alex's answer works for me, except it's not very scalable for lots of columns and quickly becomes hard to read. I ended up using :nth-of-type(n) instead, however this selector was introduced in CSS3.
Selector: :nth-of-type(n)
Example: p:nth-of-type(2)
Result: Selects every <p> element that is the second <p> element of its parent
Example:
/*column 1*/
#myTable td:nth-of-type(1)
{
padding-left: 20px;
background-color: tan;
}
/*column 2*/
#myTable td:nth-of-type(2)
{
padding-left: 10px;
}

Resources