Using Translatey on Thead and Tbody Messes Up Z-Index

Using translateY on thead and tbody messes up z-index

When you specify transform, you create a new stacking context. Your z-index for thead and tbody no longer share a common context (which is why tbody is above thead, regardless of the specified z-index). Here's are a couple articles that discusses z-index and stacking context:

http://philipwalton.com/articles/what-no-one-told-you-about-z-index/

The other article with a demo.

http://benfrain.com/z-index-stacking-contexts-experimental-css-and-ios-safari/

And a snippet from the spec itself:

Any computed value other than none for the transform results in the creation of both a stacking context and a containing block. The object acts as a containing block for fixed positioned descendants.

http://www.w3.org/TR/css3-transforms/#transform-property

Unfortunately, you'll probably need to re-think your use of transform to work around the stacking context issue.

Why z-index does not work for element having transform: translateY()

  1. For z-index to work position must be applied as absolute, relative or fixed. Add position: relative; to the .down element
  2. As there is no parent-child hierarchy, negative z-index should be applied to make the element go behind.

Demo

.up {

background-color: red;

opacity: .5; /* For DEMO Purpose */

height: 100px;

/* z-index: 100; /* Not required. Not work #1 */

}

.down {

background-color: yellow;

height: 100px;

width: 50%;

margin: 0 auto;

z-index: -1; /* Update this */

transform: translateY(-50%);

position: relative; /* Add this */

}
<div class="up"></div>

<div class="down"></div>

z-index is canceled by setting transform(rotate)

Let's walk through what is occurring. To start, note that z-index on positioned elements and transform by itself create new "stacking contexts" on elements. Here's what's going on:

Your .test element has transform set to something other than none, which gives it its own stacking context.

You then add a .test:after pseudo-element, which is a child of .test. This child has z-index: -1, setting the stack level of .test:after within the stacking context of .test Setting z-index: -1 on .test:after does not place it behind .test because z-index only has meaning within a given stacking context.

When you remove -webkit-transform from .test it removes its stacking context, causing .test and .test:after to share a stacking context (that of <html>) and making .test:after go behind .test. Note that after removing .test's -webkit-transform rule you can, once again, give it its own stacking context by setting a new z-index rule (any value) on .test (again, because it is positioned)!

So how do we solve your problem?

To get z-index working the way you expect, make sure that .test and .test:after share the same stacking context. The problem is that you want .test rotated with transform, but to do so means creating its own stacking context. Fortunately, placing .test in a wrapping container and rotating that will still allow its children to share a stacking context while also rotating both.

  • Here's what you started with: http://jsfiddle.net/fH64Q/

  • And here's a way you can get around the stacking-contexts and keep
    the rotation (note that the shadow gets a bit cut off because of .test's white background):

.wrapper {

-webkit-transform: rotate(10deg);

}

.test {

width: 150px;

height: 40px;

margin: 30px;

line-height: 40px;

position: relative;

background: white;

}

.test:after {

width: 100px;

height: 35px;

content: "";

position: absolute;

top: 0;

right: 2px;

-webkit-box-shadow: 0 5px 5px #999; /* Safari and Chrome */

-webkit-transform: rotate(3deg); /* Safari and Chrome */

transform: rotate(3deg);

z-index: -1;

}
<div class="wrapper">

<div class="test">z-index is canceled.</div>

</div>

-ms-transform won't work on table header group (thead) in IE10 (and below, presumably)

Turns out the transform does work on individual table cells, so I managed to fix this by applying -ms-transform specifically to all the td-children of thead, rather than the header itself.

In the simplified example used in the question, all it would take, then, is to add this:

#move-thead td {
-ms-transform: translate(10px, 10px);
}

Updated Fiddle. My header now scrolls along happily in IE, too.

table with fixed thead and scrollable tbody

This solution fulfills all 5 requirements:

table {

width: 100%;

}

table, td {

border-collapse: collapse;

border: 1px solid #000;

}

thead {

display: table; /* to take the same width as tr */

width: calc(100% - 17px); /* - 17px because of the scrollbar width */

}

tbody {

display: block; /* to enable vertical scrolling */

max-height: 200px; /* e.g. */

overflow-y: scroll; /* keeps the scrollbar even if it doesn't need it; display purpose */

}

th, td {

width: 33.33%; /* to enable "word-break: break-all" */

padding: 5px;

word-break: break-all; /* 4. */

}

tr {

display: table; /* display purpose; th's border */

width: 100%;

box-sizing: border-box; /* because of the border (Chrome needs this line, but not FF) */

}

td {

text-align: center;

border-bottom: none;

border-left: none;

}
<table> 

<thead>

<tr>

<th>Table Header 1</th>

<th>Table Header 2</th>

<th>Table Header 3</th>

</tr>

</thead>

<tbody>

<tr>

<td>Data1111111111111111111111111</td>

<td>Data</td>

<td>Data</td>

</tr>

<tr>

<td>Data</td>

<td>Data2222222222222222222222222</td>

<td>Data</td>

</tr>

<tr>

<td>Data</td>

<td>Data</td>

<td>Data3333333333333333333333333</td>

</tr>

<tr>

<td>Data</td>

<td>Data</td>

<td>Data</td>

</tr>

<tr>

<td>Data</td>

<td>Data</td>

<td>Data</td>

</tr>

<tr>

<td>Data</td>

<td>Data</td>

<td>Data</td>

</tr>

<tr>

<td>Data</td>

<td>Data</td>

<td>Data</td>

</tr>

<tr>

<td>Data</td>

<td>Data</td>

<td>Data</td>

</tr>

<tr>

<td>Data</td>

<td>Data</td>

<td>Data</td>

</tr>

<tr>

<td>Data</td>

<td>Data</td>

<td>Data</td>

</tr>

</tbody>

</table>


Related Topics



Leave a reply



Submit