Solution for jumping Safari table caption? - css

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());

Related

stacking context on table element(head and body)

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>

border-collapse: collapse not working properly when scaling

I'm trying to remove the border of a table using border-collapse: collapse. It works great and as it should, but when I start doing transform: scale() to make it smaller, the borders magically appear again.
https://jsfiddle.net/ox11pvag/
table {
border-collapse: collapse;
-moz-transform: scale(0.6);
-moz-transform-origin: top left;
-o-transform: scale(0.6);
-o-transform-origin: top left;
-webkit-transform: scale(0.6);
-webkit-transform-origin: top left;
transform: scale(0.6);
transform-origin: top left;
}
Is there a way to force the borders to collapse no matter what? I assume overlapping them (negative margin) is a way, but it sounds so dirty.
When browser is scaling the table it is not making exact calculations for the width of td elements. As a result there is some gap between adjacent td elements and background of parent element is visible through this gap which looks like td elements have borders(But actually its gap, if you will apply some background-color on parent you will see it).
You can fix this by doing the following changes:
Remove background of tbody tr:nth-child(odd) and apply it to table.
Add 2px or 3px border-right having the color same as background on td inside even rows and inside thead.
Working snippet is below:
table {
border-collapse: collapse;
transform: scale(0.6);
transform-origin: top left;
background: #7892a1;
width: 70%;
}
thead {
height: 50px;
line-height: 50px;
}
tbody tr {
height: 50px;
line-height: 50px;
}
thead {
background: #d2dbe0;
}
thead th {
border-right: 2px solid #d2dbe0;
}
tbody tr:nth-child(even) {
background: #a5b7c0;
}
tbody tr:nth-child(even) td {
border-right: 2px solid #a5b7c0;
}
<table>
<thead>
<th>Something</th>
<th>Something 2</th>
<th>Something 3</th>
</thead>
<tbody>
<tr>
<td>Some data</td>
<td>Some more data</td>
<td>Most data</td>
</tr>
<tr>
<td>Some data</td>
<td>Some more data</td>
<td>Most data</td>
</tr>
<tr>
<td>Some data</td>
<td>Some more data</td>
<td>Most data</td>
</tr>
</tbody>
</table>

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.

Why do I need rotateX to make :after :before tooltips work?

I have a table with tool tips invoked from tr:hover and tr:action using :after and :before.
JsFiddle here
EDIT:
If I don't have the position: relative in the td or the rotateX(0) in tr:hover td the tooltips no longer appear...
Why is this required?
CSS
/*Striped background to show transparency */
body{
background-image: linear-gradient(black 10%, transparent 10%);
background-size: auto 10px;
}
/*Base format*/
table {
float: left;
table-layout: auto;
border-collapse: seperate;
border-spacing: 1px 0;
text-align: left;
cursor: default;
}
td {
/*Fix 1 ?????????????????????????????????????????????????????????????*/
position: relative;
/*???????????????????????????????????????????????????????????????????*/
/*Dynamic elements*/
background-image: linear-gradient(to top, #0033CC, #FFFFDB);
opacity: 0.5;
}
/* Header*/
th {
padding-left: 1%; /*not inherited from table*/
width: 50%;
color: #FFFF66;
background-color: #0000CC;
}
tr:active th {
opacity: 0.5;
color: red;
}
/* Tool tip base*/
/*body*/
tr:hover td:last-child:after, tr:active td:last-child:after {
white-space: nowrap;
position: absolute;
left: calc(100% + 6px);
border-radius: 5px;
color: black;
}
/*pointer*/
tr:hover td:last-child:before, tr:active td:last-child:before{
/*make a little arrow beside the tool tip */
content: '';
border: solid;
width: 0; height: 0;
border-color: transparent #cacae1 transparent transparent;
border-width: 6px 6px 6px 0;
bottom: calc(50% - 6px);
left: 100%;
position: absolute;
}
/*Row hover*/
tr:hover td {
/*transform background gradient*/
background: linear-gradient(to top,#4D70DB,#FFFF00);
/*transform opacity for the element*/
opacity: 0.8;
/*Fix 2 ?????????????????????????????????????????????????????????????*/
transform: rotateX(0);
/*???????????????????????????????????????????????????????????????????*/
}
/* adjust tool tip */
tr:hover td:last-child:after {
content: 'Click to SELECT';
box-shadow: 0 0 8px #FFFF00;
background-image: linear-gradient(to top,#4D70DB,#FFFF00);
}
/*Row select*/
tr:active td {
opacity: 1.0;
color: red;
background-image: linear-gradient(to top,#4D70DB,#FF8585);
}
/* adjust tool tip */
tr:active td:last-child:after {
content: 'SELECTED';
background-image: linear-gradient(to top,#4D70DB,#FF8585);
box-shadow: 0 0 8px red;
color: red;
}
HTML
<body>
<table border="0" width="75%" draggable="false">
<tr id="header">
<th><b>COL1</b></th>
<th><b>COL2</b></th>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>data</td>
<td>data</td>
</tr>
</table>
</body>
When an element is positioned absolutely, it is positioned in relation to its containing block, (generally its nearest positioned ancestor). Applying certain values of transform create a new containing block.
This is why (as mentioned in the comments) replacing the transform with position: relative has the same effect. It too creates a containing block, causing your absolute element to position in relation to it.
Using a relatively positioned ancestor is a much more standard practice than applying an unneeded transform when needing to create a new containing block. I suggest you replace your transform with position: relative.

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.

Resources