【问题标题】:How can you figure out the highest z-index in your document?如何计算文档中的最高 z-index?
【发布时间】:2010-11-10 05:33:38
【问题描述】:

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

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

那么,有没有更科学的方法来确定 z-index 比所有其他元素的 z-index 高?

我尝试在 Firebug 中查找此指标,但找不到。

【问题讨论】:

  • 请注意,找到最大的 z-index 并不完全相关,但它会起作用。您需要的是构成堆叠上下文的元素的最大 z-index,这些元素与您要放置的元素位于同一堆叠上下文中。换句话说,如果你在 position: relative; z-index: 100; 元素中找到一个 position: relative; z-index: 10000; 元素,那么你需要击败的数字是 100,而不是 10,000。
  • z-index 基础知识:stackoverflow.com/a/32515284/3597276

标签: javascript html css 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;
  }));

【讨论】:

  • 这似乎是迄今为止我见过的获取 z-index 的最短和最有效的方法。
  • 我发现的唯一答案不限于特定元素类型的最大值。我希望我的 z-index 比 all 其他 z-index 更高,这是一个宝石。
  • 优雅但不可用,因为来自 Math.max 的 mdn:“如果数组元素过多,(...)apply 都将失败或返回错误结果”
  • ^ 话虽如此,Math.max 在 Chrome 上最多可以接受 100,000 个参数,在 Firefox 上可以接受 300,000 个参数,在 Edge 上可以接受 400,000 个参数,在 IE11 上可以接受 150,000 个参数(在 Win10 上测试,所有浏览器都是最新的)。
【解决方案2】:

您可以为特定元素类型(例如 <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;
}

【讨论】:

  • 解决 IE 缺少 getComputedStyle erik.eae.net/archives/2007/07/27/18.54.15
  • 为什么要将它限制为一种元素类型?
  • @ChristopherJamesCalo,这是一个通用的解决方案。如果您使用 '*' 作为 findHighestZIndex 的参数,它将适用于所有元素。
  • 目前无法正常工作,因为最高保存为字符串。相反,在您找到的 z-index 上调用 parseInt 后设置 zindex(注意:这意味着您应该检查 !isNaN() 而不是 != 'auto')。
  • 这仅在所有 z-index 都低于 999 时才有效。它正在比较字符串,因此它认为 999 > 1000。它还假设最高 z-index 高于零。最高的可能是负数。 devmunchies.com/tutorial/finding-highest-z-index-on-page
【解决方案3】:

使用 ES6 更简洁

function maxZIndex() {

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

【讨论】:

  • 排序需要一个比较器才能正常工作。考虑一下:[2 ,1, 100].sort() 给出结果[1, 100, 2] 这是错误的。改用比较器:[2 ,1, 100].sort((a,b) =&gt; a-b) 给出正确的[1, 2, 100]
  • 使用 sort 似乎会消耗大量不必要的 CPU 和内存
  • A reduce 只会遍历索引集一次,所以O = n,而sortO = n log(n)。因此,可以轻松地将sortpop 替换为reduce
  • 这个答案本身不起作用。添加.sort((a,b) =&gt; a-b) @AdamSzmyd 说让它工作。
  • 这并没有给我元素。那么如何获取 z-index 最高的元素呢?
【解决方案4】:

我想添加我在我的一个用户脚本中使用的 ECMAScript 6 实现。我正在使用这个来定义特定元素的z-index,以便它们始终出现在最高位置。

在 JS 中,您可以另外为您可能想要排除的元素设置某些属性或类名。例如,考虑您的脚本在要显示为最高元素(例如弹出窗口)的元素上设置 data-highest 属性;并考虑一个您无法控制的类名称为yetHigher 的元素,它应该更高(例如自定义上下文菜单)。我可以使用链式:not 选择器排除这些元素。请注意,:not([data-highest], .yetHigher) 是可能的,但 experimental,截至 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))
);

下面的五行可以多次运行并通过找出 当前 highestZIndex 值与所有其他计算的所有元素的 z-index 之间的最大值来重复更新变量 highestZIndexfilter 排除所有 "auto" 值。

【讨论】:

  • 根据 MDN,不能使用 Math.max 来执行此操作:“如果数组元素过多,(...)apply 都将失败或返回错误结果 [... ]reduce解决方案没有这个问题"
  • 话虽如此,这可能会涵盖大多数现实生活中的情况,因为 Chrome 支持高达 100k 的值,Firefox 300k,Edge 400k。
【解决方案5】:

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

【讨论】:

  • 虽然我同意这是一种最佳做法,并且在大多数情况下可能会有所帮助,但如果您正在构建一个可能在您的脚本不是私密的未知页面上运行的插件或脚本,这将无济于事到使用的 z-index 约定。 (很抱歉对你 9 年前的帖子发表评论。)
【解决方案6】:

我相信你正在观察的是巫毒教。如果无法访问您的完整样式表,我当然无法可靠地判断;但令我震惊的是,这里真正发生的事情可能是你忘记了只有定位元素才会受到z-index 的影响。

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

【讨论】:

  • 我将在您的第二段中展开,以解释只有 0 的 z-index 值,而不是 auto,实际上创建了一个新的堆叠上下文。
【解决方案7】:

我猜你必须自己做这个......

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;
}

【讨论】:

  • 当然,除了 any 元素可以定位和 z-indexed,而不仅仅是 div。
  • 问题是,element.style.zIndex 没有找到在外部样式表中设置的 z-indices。谷歌getComputedStyle 找到那个。
  • 跟我想的差不多。只有,我会改变几件事:有 2 个变量 - 一个记录最高的(如果它是一个数字),如果没有,将 +1 添加到一个变量。对于汽车等,返回声明的最高值 + 您找到的所有汽车的计数器。保证是最高的。
【解决方案8】:

没有默认属性或任何东西,但您可以编写一些 javascript 来遍历所有元素并找出答案。或者如果你使用像 jQuery 这样的 DOM 管理库,你可以扩展它的方法(或者找出它是否已经支持它),以便它从页面加载开始跟踪元素 z-indices,然后检索最高 z-indices 变得微不足道。索引。

【讨论】:

    【解决方案9】:

    上面的“ES6”版本比第一个解决方案效率低,因为它在整个阵列上进行了多次冗余传递。而是尝试:

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

    理论上在一个 reduce 步骤中会更快,但是一些快速的基准测试显示没有显着差异,并且代码更粗糙

    【讨论】:

    • 我更喜欢这种方式。如果“最高”不是 NaN,则稍作修改以涵盖。 + 我想增加 1 以将我的元素放在顶部。 isNaN(z) || z &lt; highest ? (isNaN(highest) ? 1 : highest + 1) : z
    • 我正要加入你额外的 isNaN 检查,但经过反思,我意识到最高被初始化为一个数字,并且从未设置为任何可能是 isNaN 的值。如果isNaN(z),最高不需要增加它已经是最高的了。因此,对于每个错误的 z 值,它都会不必要地增加最高值。
    • 您需要额外的isNaN(z) || z &lt; highest ? (isNaN(highest) ? 1 : highest) : z 检查,因为如果没有设置z-index,body 中的任何元素,highest 将是NaN,您可能希望至少返回1 从函数中可以将其用于element.style.zIndex = findHighestZ()
    • 啊,是的。 “汽车”。感谢您的跟进。
    • 更大的错误是参数的方式错误并且默认值被覆盖:) - 所以当我翻转比较时它变得更简单而不是更复杂,因为 NaN 永远不会 > 比实际值.
    【解决方案10】:

    使用 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;
    }
    

    【讨论】:

    • 为什么不使用 Math.max() ?
    • 我喜欢使用 jQuery 来确保跨 22 个浏览器的兼容性。我也喜欢 @serdar.sanri 的评论,用 Math.max() 改进它。
    【解决方案11】:

    我最近不得不为一个项目做这个,我发现我从@Philippe Gerber's great answer here和@flo's great answer(接受的答案)中受益匪浅。

    与上述答案的主要区别是:

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

    Here 是代码示例的 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>

    【讨论】:

      【解决方案12】:

      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)
      

      【讨论】:

      • 我假设这里使用前缀+ 而不是parseInt,因为it works fasterzIndex 可以返回'auto',这样就变成了NaN
      【解决方案13】:

      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;
      }
      
      

      【讨论】:

        【解决方案14】:

        如果您希望显示具有最高 z 索引的所有元素的 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
        }]
        

        【讨论】:

          【解决方案15】:

          @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>

          【讨论】:

            【解决方案16】:

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

            1. 您应该检查节点本身提供的getComputedStylestyle 对象
            2. 使用 Number.isNaN 而不是 isNaN 因为isNaN("") === false
            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 *"));
            

            【讨论】:

            • 我想在这里留下我的fiddle。我还在小提琴中添加了一些测试(不确定我是否涵盖了所有内容)。
            【解决方案17】:

            使用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>

            【讨论】:

              【解决方案18】:

              根据之前的回答:

              经过一些修改的函数

              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();
              

              【讨论】:

                猜你喜欢
                • 2011-05-29
                • 1970-01-01
                • 2013-01-03
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-01-19
                • 1970-01-01
                • 2010-10-13
                相关资源
                最近更新 更多