evkwan
evkwan

Reputation: 703

Div with overflow: auto appears in front when transform rotate(90deg) applied

I have a div called scrollable-container that holds an empty header div, and its scrollable content. Then, I have a div floating-button in front of the scrollable-container.

<div id="wrapper">
  <div id="scrollable-container">
    <div id="header">I am Header</div>
    <div id="scrollable-content">...</div>
  </div>
  <div id="floating-button">Float</div>
</div>

See fiddle below:

Normal appearance

The float button currently overlaps both the header and scrollable-content, and is in front as expected because it has a higher z-index value than scrollable-container. Also, scrollable-container has its own stacking context, so its children should never be able to go in front of anything outside of the parent.

However, what is unexpected to me was that if I applied transform: rotate(90deg) on the wrapper div, then the div scrollable-content now appears in front of floating-button!

After transform rotate(90) applied

Could anyone please point out to me why is it displaying as such when rotated 90deg?

If you look at the 2nd fiddle, notice how the floating button is still in front of the div header, which is expected, but only appears behind scrollable-content.

EDIT:

My original question asked if there were known methods to fix the issue such that any divs that was originally and intentionally placed in front of the scrollable-content could still appear in front even after rotated 90deg.

F.Muller has kindly provided some workarounds in his answer.

However, I would like to know why the div with property overflow: auto when inherits a transform: rotate(90deg) could superseded its parent's stacking context and appear in front of everything else that's supposed to have a z-index order higher than it.

Some interesting notes:

  1. This happens in the latest versions of Chrome and Safari, untested on other browsers.
  2. Interestingly, if you were to rotate wrapper to be 80deg, it would still display the floating-button in front correctly. Only when it reaches 90deg, it would disappear behind the scrollable-content.
  3. After doing some experiments and also as pointed out by F.Muller in comments below, it does seem that removing overflow: hidden at the wrapper div can remedy the situation... but why is that so?

Upvotes: 1

Views: 721

Answers (1)

F. M&#252;ller
F. M&#252;ller

Reputation: 4062

It is probably ignoring the z-index because the overlay-elements are not child-elements of the parent container: #scrollable-container.

I kinda fixed it by setting the z-index of #scrollable-container to -1. It seems to be working just fine in Firefox 83.0 (64-Bit) and in Chrome V. 87.0.4280.67 too, after the adjustments.

The overflow: auto property on the #scrollable-content and/or overflow: hidden property on the #wrapper element will cause this visual behaviour in Chrome.

Edit: It might just help, if you apply position: relative on the wrapper element. Relative containers will setup a layered stack. And we have 3 children now - the content and the two overlays. See: Alternative II.

Solution with negative z-index:

#wrapper {
  height: 300px;
  width: 400px;
  position: absolute;
  z-index: 0;
  top: 0px;
  left: 0px;
  margin: 20px;
  background-color: #E2DCDE;
  overflow: hidden;
  transform: rotate(90deg);
}

#scrollable-container {
  width: 100%;
  height: 100%;
  position: relative;
  z-index: -1;
}

#scrollable-content {
  height: 100%;
  overflow: auto;
}

#header {
  height: 50px;
  width: 100%;
  text-align: center;
  line-height: 50px;
}

#front-overlay1 {
  width: 100%;
  height: 100%;
  background-color: blue;
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  opacity: 0.5;
}

#front-overlay2 {
  width: 50%;
  height: 100%;
  background-color: #B97375;
  position: absolute;
  z-index: 3;
  top: 0;
  left: 0;
  opacity: 0.8;
}

.row1 {
  height: 100px;
  width: 100%;
  background-color: #2D2D34;
  color: white;
  text-align: center;
  line-height: 100px;
}

.row2 {
  height: 100px;
  width: 100%;
  background-color: #686878;
  color: white;
  text-align: center;
  line-height: 100px;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <div id="wrapper">
    <div id="scrollable-container">
      <div id="header">I am Header</div>
      <div id="scrollable-content">
        <div class="row1">Column 1</div>
        <div class="row2">Column 2</div>
        <div class="row1">Column 3</div>
        <div class="row2">Column 4</div>
        <div class="row1">Column 5</div>
        <div class="row2">Column 6</div>
      </div>
    </div>
    <div id="front-overlay1"></div>
    <div id="front-overlay2"></div>
  </div>
</body>

</html>

Alternative (removed an overflow property):

#wrapper {
  height: 300px;
  width: 400px;
  position: absolute;
  z-index: 0;
  top: 0px;
  left: 0px;
  margin: 20px;
  background-color: #E2DCDE;
  overflow: hidden;
  transform: rotate(90deg);
}

#scrollable-container {
  width: 100%;
  height: 100%;
  position: relative;
  z-index: 1;
}

#scrollable-content {
  height: 100%;
  /*overflow: auto;*/
}

#header {
  height: 50px;
  width: 100%;
  text-align: center;
  line-height: 50px;
}

#front-overlay1 {
  width: 100%;
  height: 100%;
  background-color: blue;
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  opacity: 0.5;
}

#front-overlay2 {
  width: 50%;
  height: 100%;
  background-color: #B97375;
  position: absolute;
  z-index: 3;
  top: 0;
  left: 0;
  opacity: 0.8;
}

.row1 {
  height: 100px;
  width: 100%;
  background-color: #2D2D34;
  color: white;
  text-align: center;
  line-height: 100px;
}

.row2 {
  height: 100px;
  width: 100%;
  background-color: #686878;
  color: white;
  text-align: center;
  line-height: 100px;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <div id="wrapper">
    <div id="scrollable-container">
      <div id="header">I am Header</div>
      <div id="scrollable-content">
        <div class="row1">Column 1</div>
        <div class="row2">Column 2</div>
        <div class="row1">Column 3</div>
        <div class="row2">Column 4</div>
        <div class="row1">Column 5</div>
        <div class="row2">Column 6</div>
      </div>
      <div id="front-overlay1"></div>
      <div id="front-overlay2"></div>
    </div>
  </div>
</body>

</html>

Alternative II (position: relative on the wrapper)

#wrapper {
  position: relative;
  height: 300px;
  width: 400px;
  margin: 20px;
  background-color: #E2DCDE;
  overflow: hidden;
  transform: rotate(90deg);
  z-index: 0;
}

#scrollable-container {
  width: 100%;
  height: 100%;
  z-index: 1;
}

#header {
  height: 50px;
  width: 100%;
  text-align: center;
  line-height: 50px;
}

#scrollable-content {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

#front-overlay1, #front-overlay2 {
  position: absolute;
  top: 0;
  left: 0;
}

#front-overlay1 {
  width: 100%;
  height: 100%;
  background-color: blue;
  opacity: 0.5;
  z-index: 2;
}

#front-overlay2 {
  width: 50%;
  height: 100%;
  background-color: #B97375;
  opacity: 0.8;
  z-index: 3;
}

.row1,
.row2 {
  height: 100px;
  width: 100%;
  color: white;
  text-align: center;
  line-height: 100px;
}

.row1 {
  background-color: #2D2D34;
}

.row2 {
  background-color: #686878;
}
<div id="wrapper">
  <div id="scrollable-container">
    <div id="header">I am Header</div>
    <div id="scrollable-content">
      <div class="row1">Column 1</div>
      <div class="row2">Column 2</div>
      <div class="row1">Column 3</div>
      <div class="row2">Column 4</div>
      <div class="row1">Column 5</div>
      <div class="row2">Column 6</div>
    </div>
  </div>
  <div id="front-overlay1"></div>
  <div id="front-overlay2"></div>
</div>

Upvotes: 1

Related Questions