2

I just found a very strange HTML behaviour: a checkbox normally hidden behind another element (like a div) becomes visible if its opacity or the opacity of its container is set below 1.

Here is the basic setup, we have a set of checkboxes behind a grey div:

.checkboxes {
  display: flex;
}

.tooltip {
  position: absolute;
  width: 300px;
  height: 20px;
  background-color: #ccc;
}
<div class="container">
  <div class="tooltip"></div>
  <div class="checkboxes">
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Foo</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Bar</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Baz</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>FooBar</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>FooBaz</span>
      </label>
    </div>
  </div>
</div>

As expected, you cannot see the checkboxes. But if we change their opacity or the opacity of their containers, they do become visible:

.checkboxes {
  display: flex;
}

.tooltip {
  position: absolute;
  width: 300px;
  height: 20px;
  background-color: #ccc;
}
<div class="container">
  <div class="tooltip"></div>
  <div class="checkboxes">
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Foo</span>
      </label>
    </div>
    <div class="checkbox" style="opacity: 0.5">
      <label>
        <input type="checkbox">
        <span>Bar</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Baz</span>
      </label>
    </div>
    <div class="checkbox" style="opacity: 0.5">
      <label>
        <input type="checkbox">
        <span>FooBar</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>FooBaz</span>
      </label>
    </div>
  </div>
</div>

Of course we can avoid this by setting the z-index of the grey div:

.checkboxes {
  display: flex;
}

.tooltip {
  position: absolute;
  width: 300px;
  height: 20px;
  background-color: #ccc;
  z-index: 10;
}
<div class="container">
  <div class="tooltip"></div>
  <div class="checkboxes">
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Foo</span>
      </label>
    </div>
    <div class="checkbox" style="opacity: 0.5">
      <label>
        <input type="checkbox">
        <span>Bar</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Baz</span>
      </label>
    </div>
    <div class="checkbox" style="opacity: 0.5">
      <label>
        <input type="checkbox">
        <span>FooBar</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>FooBaz</span>
      </label>
    </div>
  </div>
</div>

Therefore, the solution is obvious, but nevertheless I still have a question: why did that happen in the first place? What's the reason for the difference between the first and second snippets?

By the way, as I mentioned in the first paragraph, it's worth mentioning that the checkbox keeps hidden if the opacity is set to 1:

.checkboxes {
  display: flex;
}

.tooltip {
  position: absolute;
  width: 300px;
  height: 20px;
  background-color: #ccc;
}
<div class="container">
  <div class="tooltip"></div>
  <div class="checkboxes">
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Foo</span>
      </label>
    </div>
    <div class="checkbox" style="opacity: 1">
      <label>
        <input type="checkbox">
        <span>Bar</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Baz</span>
      </label>
    </div>
    <div class="checkbox" style="opacity: 1">
      <label>
        <input type="checkbox">
        <span>FooBar</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>FooBaz</span>
      </label>
    </div>
  </div>
</div>
  • position: absolute is given to tooltip class so it is overlapping checkbox so you have to manage with z-index. Its not strange it happen becuase checkbox dont have position absolute and tooltip has position absolute so it is overlapping – RRRGGG Apr 16 '20 at 07:22
  • Well... you can see stuff through transparent things, but you can't see stuff through opaque things. What's the problem here? You can see stuff through glass, but not through a wall, because the glass is transparent. – TorNato Apr 16 '20 at 07:52
  • @TorNato if you set the opacity of the div to 1 you cannot see it, but if you set it to 0.9 you can see it. It's exactly the opposite of what you said. –  Apr 16 '20 at 07:53
  • @TemaniAfif thanks for the duplicate targets, the second one (*Stacking order of elements affected by opacity*) is exactly my question here. –  Apr 16 '20 at 08:27

2 Answers2

0

This is caused because opacity causes a new stacking context. This can also happen with the following CSS properties:

Rule 8.2: All opacity descendants with opacity less than 1, in tree order, create a stacking context generated atomically.

.checkboxes {
  display: flex;
}

.tooltip {
  position: absolute;
  width: 300px;
  height: 20px;
  background-color: #ccc;
}
<div class="container">
  <div class="tooltip"></div><!-- own stack context and above the other elements -->
  <div class="checkboxes">
    <div class="checkbox" style="opacity:0.5"><!-- own stack context and later on the painting order than position -->
      <label>
        <input type="checkbox">
        <span>Bar</span>
      </label>
    </div>
    <div class="checkbox">
      <label>
        <input type="checkbox">
        <span>Bar</span>
      </label>
    </div>
  </div>
</div>
Sebastian Brosch
  • 42,106
  • 15
  • 72
  • 87
  • I'm aware of the stacking order, thanks for your answer. However, setting the opacity to 1 keeps the element hidden, while setting it to 0.99 or any other value displays it (please check the edit in my question). That's the behaviour I'm trying to understand. –  Apr 16 '20 at 07:41
  • Now I have an answer (rule 8.2). Thanks. –  Apr 16 '20 at 07:55
0

To understand what happened I have to simplify your example much more :

.checkbox{
    opacity: 0.5;
}
.tooltip {
  position: absolute;
  width: 300px;
  height: 20px;
  background-color: #ccc;
}
  <div class="tooltip"></div>
  <div class="checkbox">
    <span>Foo</span>
  </div>

Now it looks not related to checkbox any more. It just how position elements works :

according to your document flow The .checkbox element comes after .checkbox what means a higher position for .checkbox

why? because you didn't set z-index property for .tooltip what means z-index still auto . and the value of auto does not establish a new local stacking context

see the MDN about z-index auto here

so to resolve this whiteout using z-index :

  • you need to move the div you want to be at the top at the end and use top:0

.checkbox{
    opacity: 0.5;
}
.tooltip {
  position: absolute;
  width: 300px;
  height: 20px;
  background-color: #ccc;
  top:0;
}
  <div class="checkbox">
    <span>Foo</span>
  </div>
  <div class="tooltip"></div>
  • or using z-index as you mentioned with positive value to create a new local stacking context
Ayman Morsy
  • 1,279
  • 1
  • 10
  • 28