Last active
April 29, 2020 11:44
-
-
Save trungdq88/d873666a6f9101906b08a81dc9685c13 to your computer and use it in GitHub Desktop.
debug z-index and stacking context
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Usage: | |
* Paste this into your dev tools console (or even better as a snippet) | |
* It will parse the page and find all the things that create a new stacking context | |
and dump some info about them to the console. It will also outline them on the page. | |
* This is pretty rough and probably misses heaps of bugs and edge cases. | |
*/ | |
function run() { | |
function highlight(el) { | |
el.style.border = '3px solid #ff19bd'; | |
} | |
function css(el, property) { | |
return window.getComputedStyle(el)[property]; | |
} | |
function log(el, reason) { | |
console.group('New Stacking context'); | |
console.log(el); | |
reason && console.log('Reason:', reason); | |
console.log('z-index: ', css(el, 'z-index')); | |
console.log('position: ', css(el, 'position')); | |
console.log('opacity:', css(el, 'opacity')); | |
console.log('transform:', css(el, 'transform')); | |
console.log('filter:', css(el, 'filter')); | |
console.log('perspective:', css(el, 'perspective')); | |
console.log('clip-path', css(el, 'clip-path')); | |
console.log('mask', css(el, 'mask')); | |
console.groupEnd(); | |
} | |
Array.from(document.querySelectorAll('*')).forEach(function(el) { | |
var tagName = el.tagName; | |
var parentEl = el.parentElement; | |
var parentDisplay = parentEl ? css(parentEl, 'display') : null; | |
function p(property) { | |
return css(el, property); | |
} | |
// Tests | |
function mark(el, reason) { | |
highlight(el); | |
log(el, reason); | |
} | |
// Check the rules: | |
// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context | |
// 1. Root element of document (HTML). | |
if (tagName === 'HTML') { | |
mark(el, 1); | |
} | |
// 2. Element with a position value "absolute" or "relative" and z-index value other than "auto". | |
if ( | |
p('z-index') !== 'auto' && | |
(p('position') === 'absolute' || p('position') === 'relative') | |
) { | |
mark(el, 2); | |
} | |
// 3. Element with a position value "fixed" or "sticky" (sticky for all mobile browsers, but not older desktop). | |
if (p('position') === 'fixed' || p('position') === 'sticky') { | |
mark(el, 3); | |
} | |
// 4. Element that is a child of a flex (flexbox) container, with z-index value other than "auto". | |
if (parentDisplay === 'flex' && p('z-index') !== 'auto') { | |
mark(el, 4); | |
} | |
// 5. Element with a opacity value less than 1. | |
if (parseFloat(p('opacity')) < 1) { | |
mark(el, 5); | |
} | |
// 6. Element with a mix-blend-mode value other than "normal". | |
if (p('mix-blend-mode') !== 'normal') { | |
mark(el, 6); | |
} | |
/* | |
7. Element with any of the following properties with value other than "none": | |
- transform | |
- filter | |
- perspective | |
- clip-path | |
- mask / mask-image / mask-border | |
*/ | |
// TODO: account for vendor prefixes? | |
if ( | |
p('transform') !== 'none' || | |
p('filter') !== 'none' || | |
p('perspective') !== 'none' || | |
p('clip-path') !== 'none' || | |
p('mask') !== 'none' | |
) { | |
mark(el, 7); | |
} | |
// 8. Element with a isolation value "isolate". | |
if (p('isolation') === 'isolate') { | |
mark(el, 8); | |
} | |
// 9. Element with a -webkit-overflow-scrolling value "touch". | |
if (p('-webkit-overflow-scrolling') === 'touch') { | |
mark(el, 9); | |
} | |
// 10. Element with a will-change value specifying any property that would create a stacking context on non-initial value | |
// TODO | |
}); | |
} | |
run(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment