Why border is not visible with "position: sticky" when background-color exists?

CssGoogle ChromeSticky

Css Problem Overview


position: 'sticky' landed in Chrome 56, but it makes the border invisible in certain circumstances.

Consider the following example:

table {
  border-collapse: collapse;
}

thead {
  position: sticky;
  top: 0;
}

th {
  background-color: #fff;
  border-right: 5px solid red;
}

<table>
  <thead>
    <tr>
      <th>First</th>
      <th>Second</th>
      <th>Third</th>
    </tr>
  </thead>
</table>

In Chrome 56.0.2924.76, only the last <th>'s border is visible, and this is only when <th> has a background-color specified.

Is this a bug in Chrome?

Playground

Css Solutions


Solution 1 - Css

I faced the same problem. My workaround was to use the :after pseudo element to emulate a bottom border.

th:after{
  content:'';
  position:absolute;
  left: 0;
  bottom: 0;
  width:100%;
  border-bottom: 1px solid rgba(0,0,0,0.12);
}

Solution 2 - Css

seems like to force a reflow will partially help :

table {
  border-collapse: collapse;
}

thead {
  position: sticky;
  top: 0;
}

th {
  border-right: 5px solid red;
  transform:scale(0.999);
}

  <table>
    <thead>
      <tr>
        <th>First</th>
        <th>Second</th>
        <th>Third</th>
      </tr>
    </thead>
  </table>

background-clip seems also efficient and harmless:

table {
  margin-top: 1em;
  border-collapse: collapse;
  margin-bottom: 200vh
}

thead {
  position: sticky;
  top: 0;
}

th {
  border-right: 5px solid red;
  background:white; 
  background-clip: padding-box;
}

  <table>
    <thead>
      <tr>
        <th>First</th>
        <th>Second</th>
        <th>Third</th>
      </tr>
    </thead>
  </table>

Solution 3 - Css

if table contains border around columns and we add sticky position, when we scroll the table show overlapping effect to remove this effect and retains border we need to remove border and add outline instead of border

table tr th{
  outline: 1px solid #e9ecef;
  border:none;
  outline-offset: -1px;
}

Solution 4 - Css

I have solved with shadow

table tr th {
  position: -webkit-sticky;
  position: sticky;
  top: -1px;
  z-index: 2;
  background-color: white;
  -moz-box-shadow: 0 0 1px -1px #ccc;
  -webkit-box-shadow: 0 0 1px -1px #ccc;
  box-shadow: 0 0 1px -1px #ccc;
}

Solution 5 - Css

The next example currently works well under Chrome (65) and Firefox (59).

The SCSS code illustrates better the relationship between values. You can set the desired values by change the variables.

SCSS:

table {

	&.sticky-table-head {

		// Variables

		$border-width: 2px;

		$head-background-color: #ded;
		$head-border-color: #8a8;

		$background-color: #f8fff8;
		$border-color: #cdc;
		
		$color: #686;

		// Declarations

		margin-bottom: 1em;
		border-collapse: collapse;
		background-color: $background-color;
		color: $color;

		&:last-child {
			margin-bottom: 100vh;
		}

		th,
		td {
			border: $border-width solid $border-color;
		}

		thead {

			th {
				position: sticky;
				top: ($border-width / 2);
				background-color: $head-background-color;
				outline: $border-width solid $head-border-color;
				outline-offset: (- $border-width / 2);
			}
		}
	}
}

HTML and compiled CSS:

table.sticky-table-head {
	margin-bottom: 1em;
	border-collapse: collapse;
	background-color: #f8fff8;
	color: #686;
}

table.sticky-table-head:last-child {
	margin-bottom: 100vh;
}

table.sticky-table-head th,
table.sticky-table-head td {
	border: 2px solid #cdc;
}

table.sticky-table-head thead th {
	position: -webkit-sticky;
	position: sticky;
	top: 1px;
	background-color: #ded;
	outline: 2px solid #8a8;
	outline-offset: -1px;
}

<div>
	<!-- First table -->
	<table class="sticky-table-head">
		<thead>
			<tr>
				<th>Lorem</th>
				<th>Ipsum</th>
				<th>Dolor sit amet</th>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
		</tbody>
	</table>
	<!-- Second table -->
	<table class="sticky-table-head">
		<thead>
			<tr>
				<th>Lorem</th>
				<th>Ipsum</th>
				<th>Dolor sit amet</th>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
			<tr>
				<td>ipsum</td>
				<td>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</td>
				<td>sit</td>
			</tr>
		</tbody>
	</table>
</div>

Solution 6 - Css

Try this instead:

background-clip: padding-box;

Solution 7 - Css

Use ::after pseudo selector to emulate right border

Example:

th::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  border-right: 1px solid #e7e7e7;
}

Solution 8 - Css

thead::after {
  content: '';
  display: block;
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 1px;
  background-color: #333333;
}

I fixed this same problem with a pseudo element instead of a border. Not sure of why this happens in the first place, though.

Solution 9 - Css

I'm using only horizontal borders in my page so this may need to be adapted to your particular case. By using a half-transparent background colour for the table cells, I've discovered that it's the bottom end of the background that overlays the horizontal border. I guess it'll be the same with the right end for the vertical border. To avoid the border overlapping, I've set a linear gradient that fills everything but spares the last pixel. Unfortunately, this only works in Firefox and Chrome but not in Edge.

td:first-child {
  position: sticky;
  left: 0px;
  z-index: 2;
  background: linear-gradient(to bottom, white, white calc(100% - 1px),
                              transparent calc(100% - 1px), transparent);
}

Edge does paint a linear gradient but from white at the top to transparent at the bottom, ignoring the hard change at the stop at 100% - 1px.

Solution 10 - Css

Another option is to wrap your content in an element and put the border on that:

.th-inner {
  padding: 10px;
  border-bottom: 1px solid #ccc;
}

<th>
  <div class="th-inner">your content</div>
</th>

However I found that putting the border on the th worked without border-collapse: collapse on the table, so I went for that.

Solution 11 - Css

html {
  padding: 0px;
  margin: 0px;
}

body {
  padding: 0px;
  margin: 0px;
  width: 100%;
}

th,
td {
  padding: 10px;
  border: 0.1px solid #e8e0e0;
  padding-right: 10px;
}

th {
  text-align: center;
  background: #f3f3f3;
  background-clip: padding-box;
}

thead th:first-child {
  left: 0;
  z-index: 1;
}

tbody th:first-child {
  text-align: center;
  position: -webkit-sticky;
  /* for Safari */
  position: sticky;
  left: 0;
}

tbody th,
thead th:first-child {
  width: 30px;
  min-width: 30px;
  max-width: 30px;
  word-break: break-all;
}

.fixed_header {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
}


/* fixed header */

thead th {
  /* for Safari */
  text-align: center;
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}

.fixed_header th,
.fixed_header td {
  padding: 10px;
  width: 90px;
}

.table_container {
  position: relative;
  width: 100%;
  min-height: 500px;
  overflow: auto;
  background: cornsilk;
}

<table class="fixed_header">
  <thead>
    <tr>
      <th></th>
      <th>Col 1</th>
      <th>Col 2</th>
      <th>Col 3</th>
      <th>Col 4</th>
      <th>Col 5</th>
      <th>Col 1</th>
      <th>Col 2</th>
      <th>Col 3</th>
      <th>Col 4</th>
      <th>Col 5</th>
      <th>Col 1</th>
      <th>Col 2</th>
      <th>Col 3</th>
      <th>Col 4</th>
      <th>Col 5</th>
      <th>Col 1</th>
      <th>Col 2</th>
      <th>Col 3</th>
      <th>Col 4</th>
      <th>Col 5</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1</th>
      <td>row 1-1</td>
      <td>row 1-2</td>
      <td>row 1-3</td>
      <td>row 1-4</td>
      <td>row 1-1</td>
      <td>jhhhh-2</td>
      <td>row 1-3</td>
      <td>row 1-4</td>
      <td>row 1-1</td>
      <td>row 1-2</td>
      <td>row 1-3</td>
      <td>row 1-4</td>
      <td>row 1-1</td>
      <td>row 1-2</td>
      <td>row 1-3</td>
      <td>row 1-4</td>
      <td>row 1-1</td>
      <td>row 1-2</td>
      <td>row 1-3</td>
      <td>row 1-4</td>
    </tr>

  </tbody>
</table>
</div>

Solution 12 - Css

box-shadow: inset 0 0 0px 2px #555; instead of border: solid 2px #555; will work. But that is indeed a bug and should be fixed by the browsers.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMisha MoroshkoView Question on Stackoverflow
Solution 1 - CssEric GuanView Answer on Stackoverflow
Solution 2 - CssG-CyrillusView Answer on Stackoverflow
Solution 3 - CssshahidaView Answer on Stackoverflow
Solution 4 - CssProject MayhemView Answer on Stackoverflow
Solution 5 - CssHaász SándorView Answer on Stackoverflow
Solution 6 - CssJoão MendesView Answer on Stackoverflow
Solution 7 - CssAyanView Answer on Stackoverflow
Solution 8 - CssAlejandroView Answer on Stackoverflow
Solution 9 - CssygoeView Answer on Stackoverflow
Solution 10 - CssDominicView Answer on Stackoverflow
Solution 11 - CssßãlãjîView Answer on Stackoverflow
Solution 12 - CssFlaView Answer on Stackoverflow