tailwind1-5 Exercise 3: A Modal That Gets Trapped Under the Header ===================================================================
fixed header z-40
dialog
fixed inset-0 the overlay covers the whole viewport z-50 the overlay should be above everything (the header is z-40) grid place-items-center the dialog is centred relative z-0 (parent) this is the trap: it makes the parent a stacking context at level 0 First confirm the geometry (viewport 869 x 605 in the measuring browser): const R = id => document.getElementById(id).getBoundingClientRect(); const o = R('ovE'), d = R('dlgE'); console.log({ overlay: [o.left, o.top, o.width, o.height], dialogCentre: [d.left + d.width / 2, d.top + d.height / 2], viewportCentre: [document.documentElement.clientWidth / 2, innerHeight / 2] }); Output (measured in headless Chrome): { overlay: [0, 0, 869, 605], dialogCentre: [434.5, 302.5], viewportCentre: [434.5, 302.5] } Now find what is on top at the header's position, x 100, y 10: document.elementFromPoint(100, 10).id Output: as built (overlay inside relative z-0): hdrE (the HEADER is on top of the overlay, despite z-50 vs z-40) fix 1: remove z-0 from the parent: ovE (the overlay is on top) put z-0 back, then fix 2: move the overlay to be a child of : ovE (Between the fixes I restored z-0: with it back, and the overlay still inside the parent, the answer was hdrE again, so the second fix was measured on its own.) WHY THIS WORKS AS AN ANSWER --------------------------- z-index only competes between elements in the same stacking context. relative z-0 makes the parent its own context, painted at level 0 in the page. Everything inside it, including the overlay's z-50, is ordered only against its siblings in that box; the parent as a whole is below the header's level 40. So the header paints over the overlay, and no bigger number on the overlay can fix that. Fix 1 removes the cause: relative alone (z-index auto) does not create a stacking context, so the overlay's z-50 takes part in the page-level order and beats z-40. Fix 2 moves the overlay out of the trap: as a direct child of body there is no parent context above it. This is what dialog libraries do (they "portal" the dialog to the end of body), because they cannot know what stacking contexts their users' pages contain. The geometry is correct either way: fixed inset-0 fills the viewport exactly (0, 0, 869 x 605), and the dialog's centre is the viewport's centre. Remember that fixed and absolute only look at position; whether you SEE them is decided by stacking.