在网上无数的地方,我都看到过在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位在头部的排序。


当前回答

就我个人而言,我不会过分强调这种“民间智慧”。过去可能是正确的事情现在很可能不正确。我认为所有与网页解释和呈现相关的操作都是完全异步的(“获取”和“对其进行操作”是两件完全不同的事情,可能由不同的线程处理,等等),并且在任何情况下都完全超出你的控制或关注。

我将CSS引用放在文档的“头部”部分,以及对外部脚本的任何引用。(有些脚本可能要求放在主体中,如果是这样,就满足他们的要求。)

除此之外……如果您观察到“在这个/那个浏览器上,这个似乎比那个更快/更慢”,请将此观察视为有趣但无关紧要的好奇心,不要让它影响您的设计决策。太多的事情变化太快。(有人想打赌Firefox团队会在多长时间内发布他们产品的另一个临时版本吗?是的,我也是。)

其他回答

出于不同的原因,我在JavaScript之前包含了CSS文件。

如果我的JavaScript代码需要做一些页面元素的动态大小(对于那些角落的情况下,CSS是真正的主要在后面),然后在JS是russing后加载CSS可能会导致竞争条件,其中元素是在CSS样式应用之前调整大小,因此,当样式最终启动时看起来很奇怪。如果我提前加载CSS,我可以保证事情按照预期的顺序运行,最终的布局是我想要的。

将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标记之上,正如您在此页上看到的那样。

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

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

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

我不会过分强调你们已经取得的成果。我相信这是主观的,但我有理由向你解释,在JavaScript之前放CSS更好。

在你的网站加载过程中,你会看到两种情况:

案例1:白屏→无风格网站→风格网站→互动→风格互动网站

案例2:白屏→无风格网站→互动→有风格网站→有风格和互动网站

我真的无法想象有人会选择情形二。这意味着使用慢速互联网连接的访问者将面对一个无风格的网站,允许他们使用JavaScript与之交互(因为JavaScript已经加载了)。此外,花在看一个无风格的网站上的时间将以这种方式最大化。为什么会有人想要那样?

它还可以更好地工作,正如jQuery所述:

“当使用依赖于CSS样式属性值的脚本时, 引用外部样式表或嵌入样式非常重要 元素”。

当文件以错误的顺序加载时(首先是JavaScript,然后是CSS),依赖于CSS文件中设置的属性的任何JavaScript代码(例如,div的宽度或高度)将无法正确加载。似乎在错误的加载顺序下,JavaScript“有时”知道正确的属性(也许这是由竞态条件引起的?)根据使用的浏览器,这种效果似乎更大或更小。

在JavaScript之前包含CSS的建议是无效的吗?

如果你只是把它当作一个建议就不会了。但如果你把它当做一个硬性规定呢?是的,是无效的。

从窗口:DOMContentLoaded事件:

样式表加载块脚本执行,因此如果您有一个<script> 在<link rel="stylesheet"…>页面将不会完成解析 和DOMContentLoaded将不会触发—直到样式表被加载。

似乎您需要知道每个脚本依赖于什么,并确保脚本的执行延迟到正确的完成事件之后。如果脚本只依赖于DOM,它可以在ondomready/domcontentloaded中恢复。如果它依赖于要加载的图像或要应用的样式表,那么如果我正确地阅读了上面的引用,那么该代码必须延迟到onload事件。

我不认为一个尺码的袜子适合所有人,尽管这是他们销售的方式,我知道一个尺码的鞋子不适合所有人。我不认为有一个明确的答案,首先加载样式或脚本。它更多的是一个个案决定,什么必须以什么顺序加载,什么可以推迟到以后,因为不是在“关键路径”上。

To speak to the observer that commented that it is better to delay the users ability to interact until the sheet is pretty. There are many of you out there and you annoy your counterparts that feel the opposite. They came to a site to accomplish a purpose and delays to their ability to interact with a site while waiting for things that don't matter to finish loading are very frustrating. I am not saying that you are wrong, only that you should be aware that there is another faction that exists that does not share your priority.

这个问题尤其适用于所有放在网站上的广告。如果网站作者只渲染广告内容的占位符div,并确保他们的网站在注入广告在onload事件之前是加载和交互式的,我将会很喜欢。即使这样,我也希望看到广告是连续加载的,而不是一次性加载,因为它们会影响我在加载臃肿的广告时甚至滚动网站内容的能力。但这只是一个人的观点。

Know your users and what they value. Know your users and what browsing environment they use. Know what each file does, and what its prerequisites are. Making everything work will take precedence over both speed and pretty. Use tools that show you the network time line when developing. Test in each of the environments that your users use. It may be needed to dynamically (server side, when creating the page) alter the order of loading based on the users environment. When in doubt, alter the order and measure again. It is possible that intermixing styles and scripts in the load order will be optimal; not all of one then all of the other. Experiment not just what order to load the files but where. head? In body? After body? DOM Ready/Loaded? Loaded? Consider async and defer options when appropriate to reduce the net delay the user will experience before being able to interact with the page. Test to determine if they help or hurt. There will always be trade-offs to consider when evaluating the optimal load order. Pretty vs. responsive being just one.