在网上无数的地方,我都看到过在JavaScript之前使用CSS的建议。推理一般是这样的:

当涉及到CSS和JavaScript的排序时,你需要你的CSS 先来。原因是呈现线程拥有所有的 样式显示页面所需的信息。如果JavaScript include首先出现,JavaScript引擎必须先解析所有内容 继续到下一组资源。这意味着渲染 线程不能完全显示页面,因为它没有所有的 它需要的样式。

我的实际测试揭示了一些完全不同的东西:

我的测试装备

我使用下面的Ruby脚本为各种资源生成特定的延迟:

require 'rubygems'
require 'eventmachine'
require 'evma_httpserver'
require 'date'

class Handler  < EventMachine::Connection
  include EventMachine::HttpServer

  def process_http_request
    resp = EventMachine::DelegatedHttpResponse.new( self )

    return unless @http_query_string

    path = @http_path_info
    array = @http_query_string.split("&").map{|s| s.split("=")}.flatten
    parsed = Hash[*array]

    delay = parsed["delay"].to_i / 1000.0
    jsdelay = parsed["jsdelay"].to_i

    delay = 5 if (delay > 5)
    jsdelay = 5000 if (jsdelay > 5000)

    delay = 0 if (delay < 0)
    jsdelay = 0 if (jsdelay < 0)

    # Block which fulfills the request
    operation = proc do
      sleep delay

      if path.match(/.js$/)
        resp.status = 200
        resp.headers["Content-Type"] = "text/javascript"
        resp.content = "(function(){
            var start = new Date();
            while(new Date() - start < #{jsdelay}){}
          })();"
      end
      if path.match(/.css$/)
        resp.status = 200
        resp.headers["Content-Type"] = "text/css"
        resp.content = "body {font-size: 50px;}"
      end
    end

    # Callback block to execute once the request is fulfilled
    callback = proc do |res|
        resp.send_response
    end

    # Let the thread pool (20 Ruby threads) handle request
    EM.defer(operation, callback)
  end
end

EventMachine::run {
  EventMachine::start_server("0.0.0.0", 8081, Handler)
  puts "Listening..."
}

上面的迷你服务器允许我为JavaScript文件(包括服务器和客户端)设置任意延迟和任意CSS延迟。例如,http://10.0.0.50:8081/test.css?delay=500给我一个500毫秒延迟传输CSS。

我使用下面的页面进行测试。

<!DOCTYPE html>
<html>
  <head>
      <title>test</title>
      <script type='text/javascript'>
          var startTime = new Date();
      </script>
      <link href="http://10.0.0.50:8081/test.css?delay=500" type="text/css" rel="stylesheet">
      <script type="text/javascript" src="http://10.0.0.50:8081/test2.js?delay=400&amp;jsdelay=1000"></script>
  </head>
  <body>
    <p>
      Elapsed time is:
      <script type='text/javascript'>
        document.write(new Date() - startTime);
      </script>
    </p>
  </body>
</html>

当我首先包含CSS时,页面需要1.5秒来呈现:

当我首先包含JavaScript时,页面需要1.4秒来呈现:

我在Chrome、Firefox和ie浏览器上得到了类似的结果。然而,在Opera中,顺序并不重要。

似乎发生的情况是,JavaScript解释器在下载所有CSS之前拒绝启动。因此,首先使用JavaScript包含似乎更有效,因为JavaScript线程获得了更多的运行时间。

我遗漏了什么吗?把CSS include放在JavaScript include之前的建议是不正确的吗?

显然,我们可以添加async或使用setTimeout来释放呈现线程,或将JavaScript代码放在页脚中,或使用JavaScript加载器。这里的重点是关于基本JavaScript位和CSS位在头部的排序。


当前回答

您的测试是在您的个人计算机上执行的,还是在web服务器上执行的?它是一个空白的页面,还是一个包含图像、数据库等的复杂在线系统?你的脚本是执行一个简单的悬停事件动作,还是你的网站呈现和与用户交互的核心组件?这里有几件事需要考虑,当你冒险进行高水平的web开发时,这些建议的相关性几乎总是成为规则。

“将样式表放在顶部,脚本放在底部”规则的目的是,在一般情况下,这是实现最佳渐进式呈现的最佳方法,这对用户体验至关重要。

撇开其他因素不谈:假设您的测试是有效的,并且您的测试结果确实与流行规则相反,这并不令人惊讶,真的。每个网站(以及让整个网站出现在用户屏幕上的所有内容)都是不同的,互联网也在不断发展。

其他回答

将CSS置于JavaScript之前有两个主要原因。

Old browsers (Internet Explorer 6-7, Firefox 2, etc.) would block all subsequent downloads when they started downloading a script. So if you have a.js followed by b.css they get downloaded sequentially: first a then b. If you have b.css followed by a.js they get downloaded in parallel so the page loads more quickly. Nothing is rendered until all stylesheets are downloaded - this is true in all browsers. Scripts are different - they block rendering of all DOM elements that are below the script tag in the page. If you put your scripts in the HEAD then it means the entire page is blocked from rendering until all stylesheets and all scripts are downloaded. While it makes sense to block all rendering for stylesheets (so you get the correct styling the first time and avoid the flash of unstyled content FOUC), it doesn't make sense to block rendering of the entire page for scripts. Often scripts don't affect any DOM elements or just a portion of DOM elements. It's best to load scripts as low in the page as possible, or even better load them asynchronously.

用Cuzillion创建例子很有趣。例如,这个页面在HEAD中有一个脚本,所以整个页面在下载完成之前都是空白的。然而,如果我们将脚本移动到BODY块的末尾,页面标题将呈现出来,因为这些DOM元素出现在script标记之上,正如您在此页上看到的那样。

我们必须记住,新的浏览器已经在它们的JavaScript引擎、解析器等方面进行了优化,优化了常见的代码和标记问题,而在Internet Explorer 8或之前的老式浏览器中遇到的问题已经不再相关,不仅涉及标记,还涉及JavaScript变量、元素选择器等的使用。

我可以预见在不久的将来,技术发展到一定程度,性能就不再是问题了。

史蒂夫·苏德斯已经给出了明确的答案,但是……

我想知道Sam的原始测试和Josh的重复测试是否都有问题。

这两个测试似乎都是在低延迟连接上执行的,其中建立TCP连接的开销很小。

我不确定这会如何影响测试结果,我想在“正常”延迟连接上查看测试的瀑布,但是……

下载的第一个文件将获得用于HTML页面的连接,下载的第二个文件将获得新的连接。(提前刷新<head>会改变动态,但这里没有这样做。)

在较新的浏览器中,第二个TCP连接是投机性地打开的,因此连接开销减少/消失了。在旧的浏览器中,这是不正确的,并且第二个连接将有被打开的开销。

我不确定这会如何/是否会影响测试结果。

以下是之前所有主要答案的总结:

对于现代浏览器,可以将CSS内容放在您喜欢的任何地方。他们会分析您的HTML文件(他们称之为推测性解析),并在HTML解析的同时开始下载CSS。

对于旧的浏览器,继续将CSS放在最上面(如果您不想首先显示一个裸露但交互式的页面)。

对于所有浏览器,请将JavaScript内容放在页面上尽可能靠后的位置,因为这会暂停HTML的解析。最好是异步下载(即Ajax调用)。

也有一些实验结果表明,JavaScript优先(与传统的CSS优先相反)可以提供更好的性能,但没有给出任何逻辑推理,也缺乏广泛适用性的验证,所以现在可以忽略它。

所以,回答这个问题:是的。在JavaScript之前包含CSS的建议对于现代浏览器是无效的。把CSS放在你喜欢的任何地方,尽可能把JavaScript放在最后。

您的测试是在您的个人计算机上执行的,还是在web服务器上执行的?它是一个空白的页面,还是一个包含图像、数据库等的复杂在线系统?你的脚本是执行一个简单的悬停事件动作,还是你的网站呈现和与用户交互的核心组件?这里有几件事需要考虑,当你冒险进行高水平的web开发时,这些建议的相关性几乎总是成为规则。

“将样式表放在顶部,脚本放在底部”规则的目的是,在一般情况下,这是实现最佳渐进式呈现的最佳方法,这对用户体验至关重要。

撇开其他因素不谈:假设您的测试是有效的,并且您的测试结果确实与流行规则相反,这并不令人惊讶,真的。每个网站(以及让整个网站出现在用户屏幕上的所有内容)都是不同的,互联网也在不断发展。