如何计算文档中最高的 z 索引?

为了将包含透明文本图像的 div 设置为文档中 z-index 的最高值,我选择了数字10,000,它解决了我的问题。

之前我用数字3猜测,但是没有效果。

那么,有没有一种更科学的方法来计算出什么 z 指数比其他所有元素的 z 指数都高呢?

我试着在 Firebug 中寻找这个度量,但是找不到。

46827 次浏览

没有默认属性之类的东西,但是您可以编写一些 javascript 来遍历所有元素并解决这个问题。或者,如果您使用像 jQuery 这样的 DOM 管理库,您可以扩展它的方法(或者查看它是否已经支持它) ,以便它开始从页面加载跟踪元素 z 索引,然后检索最高的 z 索引就变得很简单了。

在我看来,解决这个问题的最佳方法就是为不同类型的元素使用哪些类型的 z-index设置约定。然后,通过回顾文档,您将找到要使用的正确 z-index

我相信你观察到的是巫毒。如果没有访问您的完整样式表,我当然不能可靠地告诉您; 但是我觉得这里真正发生的事情很可能是您忘记了只有定位元素受到 z-index的影响。

此外,z-indexes 不会自动分配,只有在样式表中才会分配,这意味着在没有其他 z-indexed 元素的情况下,z-index:1;将位于所有其他元素之上。

为了清楚起见,从 abcoder 网站窃取一些代码:

  var maxZ = Math.max.apply(null,
$.map($('body *'), function(e,n) {
if ($(e).css('position') != 'static')
return parseInt($(e).css('z-index')) || 1;
}));

我想你得自己来。

function findHighestZIndex()
{
var divs = document.getElementsByTagName('div');
var highest = 0;
for (var i = 0; i < divs .length; i++)
{
var zindex = divs[i].style.zIndex;
if (zindex > highest) {
highest = zindex;
}
}
return highest;
}

您可以像下面这样为特定的元素类型(如 <div>)调用 findHighestZIndex:

findHighestZIndex('div');

假设一个定义如下的 findHighestZindex函数:

function findHighestZIndex(elem)
{
var elems = document.getElementsByTagName(elem);
var highest = Number.MIN_SAFE_INTEGER || -(Math.pow(2, 53) - 1);
for (var i = 0; i < elems.length; i++)
{
var zindex = Number.parseInt(
document.defaultView.getComputedStyle(elems[i], null).getPropertyValue("z-index"),
10
);
if (zindex > highest)
{
highest = zindex;
}
}
return highest;
}

使用 jQuery:

如果没有提供元素,则检查所有元素。

function maxZIndex(elems)
{
var maxIndex = 0;
elems = typeof elems !== 'undefined' ? elems : $("*");


$(elems).each(function(){
maxIndex = (parseInt(maxIndex) < parseInt($(this).css('z-index'))) ? parseInt($(this).css('z-index')) : maxIndex;
});


return maxIndex;
}

我想添加我的 ECMAScript 6实现,我在我的一个用户脚本中使用。我用这个来定义特定元素的 z-index,这样它们总是出现在最高处。

在 JS 中,您还可以将某些属性或类名设置为您可能希望排除的元素。例如,考虑你的脚本在一个你想显示为最高元素的元素上设置一个 data-highest属性(例如弹出窗口) ; 考虑一个你不能控制的类名为 yetHigher的元素,它应该更高(例如自定义上下文菜单)。我可以用链式 :not选择器排除这些元素。请注意,:not([data-highest], .yetHigher)是可能的,但 实验性的,只有有限的浏览器支持截至2021年1月。

let highestZIndex = 0;


// Then later, potentially repeatedly
highestZIndex = Math.max(
highestZIndex,
...Array.from(document.querySelectorAll("body *:not([data-highest]):not(.yetHigher)"), (elem) => parseFloat(getComputedStyle(elem).zIndex))
.filter((zIndex) => !isNaN(zIndex))
);

下面的5行可以运行多次,并通过计算出 目前 highestZIndex值与所有元素的所有其他计算 z 索引之间的最大值来重复更新变量 highestZIndexfilter排除了所有的 "auto"值。

我最近不得不为一个项目这样做,我发现我受益于 @ Philippe Gerber的伟大答案在这里,和 @ flo的伟大答案(公认的答案)。

上述答案的主要区别是:

  • 计算 CSS z-index和任何内联 z-index样式,并使用两者中较大的样式进行比较和计算。
  • 将值强制转换为整数,并忽略任何字符串值(autostatic等)。

这里 是代码示例的 CodePen,但是它也包含在这里。

(() => {
/**
* Determines is the value is numeric or not.
* See: https://stackoverflow.com/a/9716488/1058612.
* @param {*} val The value to test for numeric type.
* @return {boolean} Whether the value is numeric or not.
*/
function isNumeric(val) {
return !isNaN(parseFloat(val)) && isFinite(val);
}


  

/**
* Finds the highest index in the current document.
* Derived from the following great examples:
*  [1] https://stackoverflow.com/a/1118216/1058612
*  [2] https://stackoverflow.com/a/1118217/1058612
* @return {number} An integer representing the value of the highest z-index.
*/
function findHighestZIndex() {
let queryObject = document.querySelectorAll('*');
let childNodes = Object.keys(queryObject).map(key => queryObject[key]);
let highest = 0;
    

childNodes.forEach((node) => {
// Get the calculated CSS z-index value.
let cssStyles = document.defaultView.getComputedStyle(node);
let cssZIndex = cssStyles.getPropertyValue('z-index');
      

// Get any inline z-index value.
let inlineZIndex = node.style.zIndex;


// Coerce the values as integers for comparison.
cssZIndex = isNumeric(cssZIndex) ? parseInt(cssZIndex, 10) : 0;
inlineZIndex = isNumeric(inlineZIndex) ? parseInt(inlineZIndex, 10) : 0;
      

// Take the highest z-index for this element, whether inline or from CSS.
let currentZIndex = cssZIndex > inlineZIndex ? cssZIndex : inlineZIndex;
      

if ((currentZIndex > highest)) {
highest = currentZIndex;
}
});


return highest;
}


console.log('Highest Z', findHighestZIndex());
})();
#root {
background-color: #333;
}


.first-child {
background-color: #fff;
display: inline-block;
height: 100px;
width: 100px;
}


.second-child {
background-color: #00ff00;
display: block;
height: 90%;
width: 90%;
padding: 0;
margin: 5%;
}


.third-child {
background-color: #0000ff;
display: block;
height: 90%;
width: 90%;
padding: 0;
margin: 5%;
}


.nested-high-z-index {
position: absolute;
z-index: 9999;
}
<div id="root" style="z-index: 10">
<div class="first-child" style="z-index: 11">
<div class="second-child" style="z-index: 12"></div>
</div>
<div class="first-child" style="z-index: 13">
<div class="second-child" style="z-index: 14"></div>
</div>
<div class="first-child" style="z-index: 15">
<div class="second-child" style="z-index: 16"></div>
</div>
<div class="first-child" style="z-index: 17">
<div class="second-child" style="z-index: 18">
<div class="third-child" style="z-index: 19">
<div class="nested-high-z-index">Hello!!! </div>
</div>
</div>
</div>
<div class="first-child">
<div class="second-child"></div>
</div>
<div class="first-child">
<div class="second-child"></div>
</div>
<div class="first-child">
<div class="second-child"></div>
</div>
</div>

使用 ES6的清洁方法

function maxZIndex() {


return Array.from(document.querySelectorAll('body *'))
.map(a => parseFloat(window.getComputedStyle(a).zIndex))
.filter(a => !isNaN(a))
.sort()
.pop();
}

这个解决方案的灵感来自于 @ Rajkeshwar Prasad的优秀思想。

	/**
returns highest z-index
@param {HTMLElement} [target] highest z-index applyed to target if it is an HTMLElement.
@return {number} the highest z-index.
*/
var maxZIndex=function(target) {
if(target instanceof HTMLElement){
return (target.style.zIndex=maxZIndex()+1);
}else{
var zi,tmp=Array.from(document.querySelectorAll('body *'))
.map(a => parseFloat(window.getComputedStyle(a).zIndex));
zi=tmp.length;
tmp=tmp.filter(a => !isNaN(a));
return tmp.length?Math.max(tmp.sort((a,b) => a-b).pop(),zi):zi;
}
};
#layer_1,#layer_2,#layer_3{
position:absolute;
border:solid 1px #000;
width:100px;
height:100px;
}
#layer_1{
left:10px;
top:10px;
background-color:#f00;
}
#layer_2{
left:60px;
top:20px;
background-color:#0f0;
z-index:150;
}
#layer_3{
left:20px;
top:60px;
background-color:#00f;
}
<div id="layer_1" onclick="maxZIndex(this)">layer_1</div>
<div id="layer_2" onclick="maxZIndex(this)">layer_2</div>
<div id="layer_3" onclick="maxZIndex(this)">layer_3</div>

如果你正在寻找 显示 z 指数最高的 < em > 所有 元素的 ID:

function show_highest_z() {
z_inds = []
ids = []
res = []
$.map($('body *'), function(e, n) {
if ($(e).css('position') != 'static') {
z_inds.push(parseFloat($(e).css('z-index')) || 1)
ids.push($(e).attr('id'))
}
})
max_z = Math.max.apply(null, z_inds)
for (i = 0; i < z_inds.length; i++) {
if (z_inds[i] == max_z) {
inner = {}
inner.id = ids[i]
inner.z_index = z_inds[i]
res.push(inner)
}
}
return (res)
}

用法 :

show_highest_z()

结果 :

[{
"id": "overlay_LlI4wrVtcuBcSof",
"z_index": 999999
}, {
"id": "overlay_IZ2l6piwCNpKxAH",
"z_index": 999999
}]

Array reduce ()

下面是另一个使用 Array.reduce()来确定最上面的 z-index的解决方案:

const max_zindex = [...document.querySelectorAll('body *')].reduce((accumulator, current_value) => {
current_value = +getComputedStyle(current_value).zIndex;


if (current_value === current_value) { // Not NaN
return Math.max(accumulator, current_value)
}


return accumulator;
}, 0); // Default Z-Index Rendering Layer 0 (Zero)

在 NodeList 中寻找最大 zIndex 的稳健解决方案

  1. 应该同时检查节点本身提供的 getComputedStylestyle对象
  2. 由于 isNaN("") === false的原因,使用 Number.isNaN 代替 isNaN
function convertToNumber(value) {
const asNumber = parseFloat(value);
return Number.isNaN(asNumber) ? 0 : asNumber;
}


function getNodeZIndex(node) {
const computedIndex = convertToNumber(window.getComputedStyle(node).zIndex);
const styleIndex = convertToNumber(node.style.zIndex);


if (computedIndex > styleIndex) {
return computedIndex;
}


return styleIndex;
}


function getMaxZIndex(nodeList) {
const zIndexes = Array.from(nodeList).map(getNodeZIndex);
return Math.max(...zIndexes);
}


const maxZIndex = getMaxZIndex(document.querySelectorAll("body *"));

ShadowRoot 解决方案

我们不能忘记自定义元素和影子根内容。

function computeMaxZIndex() {
function getMaxZIndex(parent, current_z = 0) {
const z = parent.style.zIndex != "" ? parseInt(parent.style.zIndex, 10) : 0;
if (z > current_z)
current_z = z;
const children = parent.shadowRoot ? parent.shadowRoot.children : parent.children;
for (let i = 0; i < children.length; i++) {
const child = children[i];
current_z = getMaxZIndex(child, current_z);
}
return current_z;
}
return getMaxZIndex(document.body) + 1;
}


上面的“ ES6”版本比第一个解决方案效率低,因为它在整个数组中进行多次冗余传递。相反,你可以试试:

findHighestZ = () =>
[...document.querySelectorAll('body *')]
.map(elt => parseFloat(getComputedStyle(elt).zIndex))
.reduce((highest, z) => z > highest ? z : highest, 1)

理论上,在一个 reduce 步骤中执行这个操作会更快,但是一些快速的基准测试没有显示出明显的差异,而且代码更加复杂

使用 mapfilter的非常简单的代码

function calMaxZIndex() {
return Array.from(document.querySelectorAll('body *'))
.map(a => parseFloat(window.getComputedStyle(a).zIndex || a.style.zIndex))
.filter(a => !isNaN(a))
.sort()
.pop()
}


function getMax() {
const max = calMaxZIndex() ?? 0
console.log({
max
})
}


getMax()
#ticket-box {
text-align: center;
position: fixed;
top: 0;
right: 0;
width: 100%;
background-color: #e9d295;
padding: 5px;
z-index: 6;
}
<div id="menu">
<a href="javascript:void(0);" onclick="closeMenu();" style="color: #ffffff; position: absolute; top: 15px; right: 15px;text-decoration: none;">CLOSE</a>


<ul style="text-align:center;list-style-type:none;">
<li><a href="#">FILM</a></li>
<li><a href="#">MUSIC</a></li>
<li><a href="#">SPORTS</a></li>
<li><a href="#">FINANCE</a></li>
</ul>
</div>


<div id="ticket-box">Have you bought your tickets for friday's event? No?! <a href="#">Grab yours now!</a></div>


<center><a href="javascript:void(0);" onclick="revealMenu();" style="display: inline-block; color: #333333; margin-top: 90px;">MENU</a></center>

基于以前的答案:

经过一些修改后仍能正常工作

let zIndexMax = () =>
[...document.querySelectorAll('body > *')]
.map(elem => parseInt(getComputedStyle(elem).zIndex, 10) || 0)
.reduce((prev, curr) => curr > prev ? curr : prev, 1);

原型机

HTMLElement.prototype.zIndexMax = function () {
return [...this.children]
.map(elem => parseInt(getComputedStyle(elem).zIndex, 10) || 0)
.reduce((prev, curr) => curr > prev ? curr : prev, 1);
}

用途

document.querySelector('body').zIndexMax();

在浏览了 StackOverflow 上的许多解决方案之后,我发现没有一个能够正确工作,并且要考虑 zIndex 实际上是如何工作的。我已经编写了一个解决方案,它也考虑到了堆叠上下文。您可以参考 这篇文章来理解在 CSS 中堆叠上下文是如何工作的。

const getZIndex = el => {
const computedStyle = getComputedStyle(el, null)
const zIndex = computedStyle.getPropertyValue('z-index')
return zIndex !== 'auto' ? parseInt(zIndex) : null
}


const getZIndexWithinStackingContext = (el, context) => {
let zIndex = getZIndex(el)
if (!zIndex) return null


let result = zIndex


while (el.parentElement !== context) {
el = el.parentElement
zIndex = getZIndex(el)
if (zIndex) {
result = zIndex
}
}


return result
}


const createZIndex = (overVisibleOnly = false, context = document.body) => {
const elements = [...document.querySelectorAll('body *')]
let highestZIndex = 0


elements.forEach(el => {
if (overVisibleOnly) {
const isVisible = !!el.offsetParent
if (!isVisible) return
}


const zIndex = getZIndexWithinStackingContext(el, context)


if (zIndex && zIndex > highestZIndex) {
highestZIndex = zIndex
}
})


return highestZIndex + 1
}

请注意,此解决方案考虑所有元素,而不仅仅是定位元素,因为它们可以在添加某个类之后定位。但是您可以通过添加位置计算样式属性的检查来轻松地解决这个问题。

我发现,当页面上有动态更改的 z-index 时,所提供的方法不起作用(当前方法只获取原始设置的 z-index)。

该函数还可以使用动态添加的 z 索引:

function find_max_z_index() {
const all_z = [];
document.querySelectorAll("*").forEach(function(elem) {
all_z.push(elem.style.zIndex)
})
const max_index = Math.max.apply(null, all_z.map((x) => Number(x)));
return(max_index)
}

下面是我的两行函数:

const getMaxZIndex = function () {
const elements = [...document.querySelectorAll("body *")];
return Math.max(...elements.map(x => parseInt(getComputedStyle(x, null).zIndex) || 0));
};
console.log(getMaxZIndex());

很短

[...document.querySelectorAll`*`]
.reduce((a,e,i,t,z=+window.getComputedStyle(e).zIndex||0) => z>a ? z:a ,0);

let z = [...document.querySelectorAll`*`].reduce((a,e,i,t,z=+window.getComputedStyle(e).zIndex||0) => z>a ? z:a ,0);


console.log(z);
<div style="z-index: 100"></div>
<div style="z-index: 3000"></div>
<div style="z-index: 200"></div>