This is my HTML document. I have an image tag beneath my tags and everything looks good until adding an opacity-50
class to my img
tag. Now the image covers my other tags. (I tried to add opacity to other tags and even make my header my img
tag sibling but still the problem exists).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./fonts/fontawesome-free-6.4.2-web/css/all.css">
<title>Document</title>
<style>
@font-face {
font-family: "Ubunto";
src: url("./fonts/Ubuntu-Medium.ttf");
}
.fo-color {
color: white;
}
</style>
</head>
<body>
<div>
<header class="overflow-hidden text-white fixed">
<div class="grid grid-cols-2 w-screen h-14 bg-slate-600">
<div class="mt-2 ml-6 text-2xl" style="font-family: Ubunto;">Logo</div>
<nav class="flex justify-end ">
<a href="#" class="menu-open-btn absolute mt-3 mr-7">
<i class="fa-solid fa-bars fo-color fa-xl"></i>
</a>
<div
class="w-1/3 main-menu duration-300 h-screen bg-slate-600 fixed flex items-center top-0 right-0">
<a href="#" class="menu-close-btn absolute top-4 left-5">
<i class="fa-solid fa-x fa-xl fo-color"></i>
</a>
<ul class="">
<li class="hover:text-lime-600 duration-200 ml-5">Home</li>
<li class="hover:text-lime-600 duration-200 ml-5">About Us</li>
<li class="hover:text-lime-600 duration-200 ml-5">Contact</li>
<li class="hover:text-lime-600 duration-200 ml-5">Team</li>
</ul>
</div>
</nav>
</div>
</header>
<div class="overflow-hidden">
<div class="">
<img src="./img/businesspeople.avif" alt="photo" class="h-auto w-screen bg-indigo-500 opacity-50">
</div>
</div>
</div>
<script>
let main_menu = document.querySelector(".main-menu")
let menu_open_btn = document.querySelector(".menu-open-btn")
let menu_close_btn = document.querySelector(".menu-close-btn")
menu_open_btn.addEventListener("click", () => {
main_menu.classList.remove("translate-x-full")
main_menu.classList.add("translate-x-0")
})
menu_close_btn.addEventListener("click", () => {
main_menu.classList.remove("translate-x-0")
main_menu.classList.add("translate-x-full")
})
</script>
<script src="https://cdn.tailwindcss.com"></script>
</body>
</html>
This is because using opacity with a value less than 1 changes its painting order in the stacking context. One way to fix it is to adjust the z-index by adding a negative z index such as -z-10 relative
on the image. (Side note: The overflow-hidden
on the image container is not hiding any part of the image if that is what it's meant to do.)
<img src="./img/businesspeople.avif"
alt="photo" class="h-auto w-screen bg-indigo-500 opacity-50
-z-10 relative">
The reason why the image is behind everything originally is because within the same stacking context (and the only one in your case), non-positioned elements will appear behind z-index:auto
positioned elements (anything that is not position:static
.)
Since the image and its container div are both position:static
which are non-positioned, while the whole header
is set to position:fixed
, the image will be drawn behind the header.
However, if you set opacity to less than 1 on a non-positioned element, it will be painted on the same layer, within its parent stacking context, as positioned elements with stack level 0. Now, since the header and the image are both seen as positioned element without positive stack level in the same stacking context, the later appeared in the DOM (which is the image) will be drawn in the front.
In W3C Spec 3.2. Transparency: the ‘opacity’ property:
If an element with opacity less than 1 is not positioned, then it is painted on the same layer, within its parent stacking context, as positioned elements with stack level 0.