I don\'t know why my border style do not work with position: sticky;
attribute. I would like to set border styles on my sticky table header. But I don\'t want t
<td style="position: sticky;
top: 0;
left: 0;
right: 0;
padding: 4px 3px;
background-color: #d3d3d3;
box-shadow: inset 0 1px 0 black, inset 0 -1px 0 black;">
</td>
use this 100% worked
Now I can set the border styles with psuedo classes
as user @soulshined suggested. Belows are css changes to work and here is JSFiddle Link. Already tested on chrome and firefox.
#wrapper {
width: 400px;
height: 200px;
overflow: auto;
padding: 1px;
}
table {
width: 100%;
text-align: center;
border-collapse: collapse;
}
table tr th {
border: 1px solid green;
}
table tr th:first-child {
border-left: 1px solid green;
}
table tr td {
border: 1px solid green;
}
table thead th {
position: -webkit-sticky;
position: sticky;
top: 0;
background-color: #edecec;
}
th::before {
content: '';
position: absolute;
left: 0;
width: 100%;
height: 100%;
border-right: 1px solid green;
display: block;
top : 1px;
}
th::after {
content: '';
position: absolute;
left: 0;
width: 100%;
height: 100%;
border-bottom: 1px solid green;
border-top: 1px solid green;
display: block;
top : -1px;
}
Tried some of the existing answers, but as comments have mentioned, they result in a one pixel gap between the borders.
Made a workaround, though it requires JavaScript. It places a <div>
in each <th>
, on resize it fits the <div>
to the <th>
. The <th>
border is then instead applied to the <div>
.
Note that as of writing this, position: sticky
is not working in Chromium on <thead>
, it works in Firefox. However, the position: sticky
related CSS does not affect the page, if the JavaScript is not executed.
Click Run code snippet to see if it works, in your browser.
function onResize() {
$("thead th div").each(function () {
var width = $(this).parent().outerWidth() - 2; // -2 * border-width
$(this).css("width", width + "px");
});
}
$("thead th").each(function () {
$(this).append($("<div>"));
});
$(window).on("resize", onResize);
onResize();
table {
width: 100%;
border-collapse: collapse;
}
th {
text-align: left;
}
th, td {
padding: 12px 20px;
border: 1px solid rgba(0, 0, 0, 0.125);
}
table thead {
position: sticky;
top: 0;
background: #FFF;
}
/* Used as a workaround for position: sticky not rendering the border */
thead th div {
width: 30px;
margin: 0 -20px; /* -20px to negate the 20px from the padding */
position: absolute;
top: 0;
bottom: 0;
z-index: -1;
border-right: 1px solid rgba(0, 0, 0, 0.125);
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<table>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
</tbody>
</table>
Wrap the previous JavaScript in the following, to limit it to Firefox.
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
// ...
}
Screenshot (Firefox 71):
How about replacing border
with outline
? I dare to say that especially for table elements the outline
acts almost the same as border
. I know it is not out of the box model etc. but visually is identical here. Try this:
table tr th,
table tr td {
border: 0;
outline: 2px solid;
}
Bear in mind, outline
is always rendered around the whole element, there is nothing like outline-left
, so it is not silver bullet. See outline on MDN for further details.
UPDATE: Well I overlooked one detail, the outline is not properly aligned with tbody
borders. You have to eiter swap border
and outline
for the whole table or use transform
and nudge the thead
, but perhaps it is not good way to go (it depends, of course).
This is, I believe the simplest answer.
The accepted answer don't provide a solution for a 1px border.
Note: this is a work around, so don't gripe me.
If you remove the border-top
from the table header, the table has nothing to collapse, so no space is created to see through to the underlying cells. Replace the border-top
with a border of the same style in a holding DIV.
css:
table thead tr:nth-child(1) th {
position: sticky;
border-top:0;
}
.table_holder {
border-top:1px solid black;
}
html:
<div id="table_holder">
<table> ... </table>
</div>