如何使用jQuery在元素渲染之前隐藏它们?

48
我希望能够生成带有区域(div、span)的html布局,这些区域可以根据条件显示/隐藏。这些区域默认情况下是隐藏的。
如果我在document.ready上调用jquery的.hide()方法,这些区域可能会闪烁(浏览器会部分渲染加载中的文档)。所以我在html布局中应用"display: none"样式。
我想知道避免闪烁的最佳实践是什么,因为应用"display:none"违反了封装规则 - 我了解jquery对于隐藏/显示做了哪些事情并使用它。如果jquery的隐藏/显示实现有一天改变,整个网站将无法工作。
提前致谢。
12个回答

34

@Andrew,

我知道答案已经被接受了,但是使用 display: none; 会给没有JavaScript的用户带来噩梦。

使用内联JavaScript,您可以隐藏一个元素而不会使其闪烁。没有JavaScript的用户仍然能够看到它。

考虑一下在页面加载时应该隐藏的几个div。

<head>
    <script type="text/javascript" src="jQuery.js"></script>
</head>
<body>
    <div id="hide-me">
        ... some content ...
    </div>
    <script type="text/javascript">
        $("#hide-me").hide();
    </script>

    <div id="hide-me-too">
        ... some content ...
    </div>
    <script type="text/javascript">
        $("#hide-me-too").hide();
    </script>
</body>

内联Javascript会在元素呈现时立即运行,因此将其隐藏在用户视野之外。


14
这种做法"without blinking"(在所有浏览器和任何页面上)将完美运行,简直是不真实的... 不同的浏览器根据它们的具体实现和页面大小可能会出现 "闪烁",甚至会在一段时间内显示内容。例如,在Chrome中会显示一段时间的示例(1 MB):http://www.architectshack.com/as/BlinkTest.ashx?2 - Tao
同意陶 - 这在一些浏览器中不起作用,包括Chrome。 - jimasp

6

我同意Boris Guéry的看法,这并不是过度工程,而是标准的最佳实践。我会与Boris略有不同,首先在html中添加一个no-js类,然后再用JavaScript将其删除。

这样你就无需等待文档准备就绪即可隐藏内容,并且没有任何JavaScript的情况下仍然可以看到内容。假设用户没有JavaScript更符合渐进增强的哲学。

例如:

<html class="no-js">
<body>
<div id="foo"></div>
</body>
</html>

我的CSS:

#foo {
    display: none;
}
html.no-js #foo {
    display: block;
}

以及JavaScript

$(document).ready(
   function()
   {
     $('html').removeClass('no-js');
   }
);

********* 或基于每个案例的情况 ***********

例如:

<div class="no-js" id="foo">foobar and stuff</div>

CSS:

.no-js {
  display:none;
}
#foo {
  display: block;
}
#foo.no-js {
  display: none;
}

js:

$(document).ready(function(){
  // remove the class from any element that has it.
  $('.no-js').removeClass('no-js');
});

+1 我非常喜欢这个想法。然而,使用 CMS 我不能仅仅编辑 HTML 标签。我在想是否有其他解决方案。 - Tom
它不需要是HTML标签,那只是覆盖面最广的方式。你能给任何东西添加类吗?如果可以,那么你可以根据情况进行操作,然后在JavaScript中从所有具有.no-js类的对象中删除该类。我会更新我的答案并提出建议。 - Ryan Ore
为了让它正常工作,我的脚本文件最终变成了这样,所以removeClass()会提前触发,而show()则会晚一些:$('html').removeClass('no-js');$(function () { $(window).load(function() { $('#foo').show(); }); }); - jimasp
隐藏/显示某些内容的原因取决于情况。如果 JS 没有启用,您可能希望提供静态图像,而不是一些漂亮的 Ajaxy 图库。否则,他们可能会看到一个空的 div... 或者只是一条消息告诉他们,如果他们启用 JavaScript,就会更有趣。 我认为 className“no-js”很令人困惑,因为它真正做的是通过删除类来显示替代内容,而不是添加它。无论如何,按照最符合您的方式对事物进行命名。 - Ryan Ore
我明白了。我现在添加了另一个答案(https://dev59.com/E3E85IYBdhLWcg3wYigB#36991047),它更加复杂,但希望能解决所有问题。 - robsch
显示剩余4条评论

4

当 JavaScript 启用时,我通常会给我的元素设置一个 .js 类来设置正确的属性。

然后,我可以根据 JavaScript 是否存在来设置 CSS。

例如:

<html class="js">
<body>
<div id="foo"></div>
</body>
</html>

我的 CSS:

html.js #foo
{
    display: none;
}

以及 JavaScript

$(document).ready(
   function()
   {
     $(html).addClass('js');
   }
);

谢谢,但我决定选择simple-css,并发现这种混合(css + javascript)方法对我的任务来说过于复杂了。 - Andrew Florko
1
我们的目标是保持可用性和无障碍性,让不会使用 Javascript 的用户也能正常使用。如果您匹配您的块与其 ID,那么没有启用 JavaScript 的人很可能无法看到它。您想知道最佳实践,它确实是一种最佳实践。 - Boris Guéry

3
为什么不只做这个呢?
// Hide HTML element ASAP
$('html').hide();

// DOM-ready function
$(function () {
   // Do stuff with the DOM, if needed
   // ...

   // Show HTML element
   $('html').show();
}

看起来它表现良好! 问候。

5
这种方法的问题在于,页面重新加载时会导致整个页面闪烁。如果你使用的是黑色背景,这一点尤为明显。 - meesern

3

在元素中设置初始显示属性没有任何问题,尤其是如果您将其封装在CSS类中。


25
如果您选择这条路,禁用JavaScript的浏览器将无法渲染这些元素。 - Stéphane
10
永远不要这样做。这是个不好的做法。 - Marko
1
“css类”这样的东西不存在。 - Johannes Pille
1
我不明白为什么这个被接受的答案甚至没有回答标题中的问题。而且,正如任何人可以在下面阅读到的那样,对于没有启用JavaScript的用户来说,这个解决方案是无意义的。所以,算了吧! - Manticore

3

1
这是我的建议。它利用这个解决方案创建一个新的CSS规则。主要是:如果JS可用,则会创建一个隐藏某些html的CSS类,否则不会。而且,这发生在处理主要内容(包含应最初隐藏的html部分)之前!
<html>
<head>
    <style>
        /* This class gets overwritten if JS is enabled. If a css file (bootstrap, ...) 
        gets loaded with such a class this would be also overwritten. This solution does 
        not require the class. It is here just to show that it has no effect 
        if JS is activated.*/
        .hidden {
            display: block;
            background: red;
        }
    </style>
    <script>
        // this is copied from the linked stackoverflow reply:
        function setStyle(cssText) {
            var sheet  = document.createElement('style');
            sheet.type = 'text/css';
            /* Optional */
            window.customSheet = sheet;
            (document.head || document.getElementsByTagName('head')[0]).appendChild(sheet);
            return (setStyle = function (cssText, node) {
                if (!node || node.parentNode !== sheet)
                    return sheet.appendChild(document.createTextNode(cssText));
                node.nodeValue = cssText;
                return node;
            })(cssText);
        }

        // And now: This class only gets defined if JS is enabled. Otherwise 
        // it will not be created/overwritten.
        setStyle('.hidden { display: none; }');

        // Attention: Now that the class is defined it could be overwritten 
        // in other CSS declarations (in style tags or with loaded CSS files).
    </script>
</head>
<body>

    <button>Show/Hide</button>

    <div class="">before</div>
    <div class="my-element hidden">
        Content that should be initially hidden if possible.
        You may want to multiply this div by some thousands
        so that you see the effect. With and without JS enabled.
    </div>
    <div class="">after</div>

    <script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
    <script>
        // Here is some 'normal' JS code. Very likely loaded as a JS file:
        $('button').click(function () {
            $('.my-element').toggleClass('hidden');
            // or setting display directly: 
            //   $('.my-element').toggle() 
            // but well, having class hidden though it is not 
            // hidden makes is not so nice...
        })
    </script>

</body>
</html>

这个方案有点复杂,但我认为这是一个合适的解决方案。优点是可以防止闪烁,并且在未启用JS时也可使用。而且不需要jQuery。

1

经过一段时间的思考,我得到了以下解决方案的想法。与我的其他方案相比,我将它简化为必要的部分(并使用this通过JS添加了一个类):

<html>
<head>
    <style>
        /* This could be also part of an css file: */
        .container-with-hidden-elements .element {
            display: none;
        }
    </style>
</head>
<body>
    <div class="container">
        <script>
            document.getElementsByClassName('container')[0]
                    .className += ' container-with-hidden-elements';
        </script>

        <div class="element">Content that should be initially hidden if possible.</div>
    </div>
</body>
</html>

脚本标签会立即执行并向容器添加一个类。在这个容器中,有一些嵌套的元素现在被隐藏了,因为容器已经得到了特殊的类,并且有一个CSS规则产生了影响。
同样,这发生在剩余的HTML被处理之前(防止闪烁)。而且,如果JS被禁用,所有元素默认情况下都是可见的 - 这可能被称为渐进增强
不确定这是否适用于每个浏览器。但在我看来,这将是一个简单而整洁的解决方案。

1

你可以在CSS类中应用"display: none"。

因为浏览器需要按照一定的顺序读取HTML代码,为了让JavaScript找到该元素。你需要在浏览器读取您的HTML时将元素标记为隐藏状态。

但是你也可以将HTML插入到你的JavaScript中,在呈现之前调用hide方法。


谢谢,我决定使用CSS的"display: none"。 - Andrew Florko

0

有很多答案,你可以使用show()方法并编写条件来显示或隐藏。这是示例代码在渲染完成时显示/隐藏

  <div id="banner-message">
  <p id="hello">Hello World!!!!!</p>
  <input id="statusconf" value="" type="checkbox">Show hello world text when i click this check box
  <button>Change color</button>
</div>

    // find elements
var banner = $("#banner-message")
var button = $("button")

// handle click and add class
button.on("click", function(){
  banner.addClass("alt")
})

//Set this up as part of document ready if you wish
//$(document).ready(function(e) {

    $("#statusconf").show(function(e) {
            if ($("#statusconf").is(':checked') === false) {
                $('#hello').hide();
            } else {
        $("#hello").show();
      }
  });

    $("#statusconf").on("click", function(e) {
    if ($("#statusconf").is(':checked') === false) {
                $('#hello').hide();
            } else {
        $("#hello").show();
      }
  });

//});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接