乐闻世界logo
搜索文章和话题

Web项目中引入CSS 应该总是在 javascript 文件之前吗?

7 个月前提问
3 个月前修改
浏览次数90

19个答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

将 CSS 放在 JavaScript 之前有两个主要原因。

  1. 旧浏览器(Internet Explorer 6-7、Firefox 2 等)在开始下载脚本时会阻止所有后续下载。因此,如果您a.js遵循,b.css它们将按顺序下载:先是 a,然后是 b。如果您b.css遵循,a.js它们会并行下载,因此页面加载速度更快。

  2. 在下载所有样式表之前不会呈现任何内容 - 在所有浏览器中都是如此。脚本是不同的 - 它们会阻止页面中_脚本标记下方_的所有 DOM 元素的渲染。如果将脚本放在 HEAD 中,则意味着整个页面将被阻止渲染,直到下载所有样式表和所有脚本。虽然阻止样式表的所有渲染是有意义的(以便您第一次获得正确的样式并避免无样式内容的闪现),但阻止脚本的整个页面的渲染是没有意义的。通常,脚本不会影响任何 DOM 元素或仅影响 DOM 元素的一部分。最好在页面尽可能低的位置加载脚本,或者更好地异步加载它们。

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

2024年6月29日 12:07 回复

This answer is useful

754

This answer is not useful

Save this answer.

Show activity on this post.

This is a very interesting question. I've always put my CSS <link href="...">s before my JavaScript <script src="...">s because "I read one time that it's better." So, you're right; it's high time we do some actual research!

I set up my own test harness in Node.js (code below). Basically, I:

  • Made sure there was no HTTP caching so the browser would have to do a full download each time a page is loaded.
  • To simulate reality, I included jQuery and the H5BP CSS (so there's a decent amount of script/CSS to parse)
  • Set up two pages - one with CSS before script, one with CSS after script.
  • Recorded how long it took for the external script in the <head> to execute
  • Recorded how long it took for the inline script in the <body> to execute, which is analogous to DOMReady.
  • Delayed sending CSS and/or script to the browser by 500 ms.
  • Ran the test 20 times in the three major browsers.

Results

First, with the CSS file delayed by 500 ms (the unit is milliseconds):

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 583 36 | 559 42 | 565 49 St Dev | 15 12 | 9 7 | 13 6 ------------|--------------|--------------|------------ Body Exec | | | Average | 584 521 | 559 513 | 565 519 St Dev | 15 9 | 9 5 | 13 7

Next, I set jQuery to delay by 500 ms instead of the CSS:

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 597 556 | 562 559 | 564 564 St Dev | 14 12 | 11 7 | 8 8 ------------|--------------|--------------|------------ Body Exec | | | Average | 598 557 | 563 560 | 564 565 St Dev | 14 12 | 10 7 | 8 8

Finally, I set both jQuery and the CSS to delay by 500 ms:

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 620 560 | 577 577 | 571 567 St Dev | 16 11 | 19 9 | 9 10 ------------|--------------|--------------|------------ Body Exec | | | Average | 623 561 | 578 580 | 571 568 St Dev | 18 11 | 19 9 | 9 10

Conclusions

First, it's important to note that I'm operating under the assumption that you have scripts located in the <head> of your document (as opposed to the end of the <body>). There are various arguments regarding why you might link to your scripts in the <head> versus the end of the document, but that's outside the scope of this answer. This is strictly about whether <script>s should go before <link>s in the <head>.

In modern DESKTOP browsers, it looks like linking to CSS first never provides a performance gain. Putting CSS after script gets you a trivial amount of gain when both CSS and script are delayed, but gives you large gains when CSS is delayed. (Shown by the last columns in the first set of results.)

Given that linking to CSS last does not seem to hurt performance but can provide gains under certain circumstances, you should link to external style sheets after you link to external scripts only on desktop browsers if the performance of old browsers is not a concern. Read on for the mobile situation.

Why?

Historically, when a browser encountered a <script> tag pointing to an external resource, the browser would stop parsing the HTML, retrieve the script, execute it, then continue parsing the HTML. In contrast, if the browser encountered a <link> for an external style sheet, it would continue parsing the HTML while it fetched the CSS file (in parallel).

Hence, the widely-repeated advice to put style sheets first – they would download first, and the first script to download could be loaded in parallel.

However, modern browsers (including all of the browsers I tested with above) have implemented speculative parsing, where the browser "looks ahead" in the HTML and begins downloading resources before scripts download and execute.

In old browsers without speculative parsing, putting scripts first will affect performance since they will not download in parallel.

Browser Support

Speculative parsing was first implemented in: (along with the percentage of worldwide desktop browser users using this version or greater as of Jan 2012)

In total, roughly 85% of desktop browsers in use today support speculative loading. Putting scripts before CSS will have a performance penalty on 15% of users globally; your mileage may vary based on your site's specific audience. (And remember that number is shrinking.)

On mobile browsers, it's a little harder to get definitive numbers simply due to how heterogeneous the mobile browser and OS landscape is. Since speculative rendering was implemented in WebKit 525 (released Mar 2008), and just about every worthwhile mobile browser is based on WebKit, we can conclude that "most" mobile browsers should support it. According to quirksmode, iOS 2.2/Android 1.0 use WebKit 525. I have no idea what Windows Phone looks like.

However, I ran the test on my Android 4 device, and while I saw numbers similar to the desktop results, I hooked it up to the fantastic new remote debugger in Chrome for Android, and Network tab showed that the browser was actually waiting to download the CSS until the JavaScript code completely loaded – in other words, even the newest version of WebKit for Android does not appear to support speculative parsing. I suspect it might be turned off due to the CPU, memory, and/or network constraints inherent to mobile devices.

Code

Forgive the sloppiness – this was Q&D.

File app.js

shell
var express = require('express') , app = express.createServer() , fs = require('fs'); app.listen(90); var file={}; fs.readdirSync('.').forEach(function(f) { console.log(f) file[f] = fs.readFileSync(f); if (f != 'jquery.js' && f != 'style.css') app.get('/' + f, function(req,res) { res.contentType(f); res.send(file[f]); }); }); app.get('/jquery.js', function(req,res) { setTimeout(function() { res.contentType('text/javascript'); res.send(file['jquery.js']); }, 500); }); app.get('/style.css', function(req,res) { setTimeout(function() { res.contentType('text/css'); res.send(file['style.css']); }, 500); }); var headresults={ css: [], js: [] }, bodyresults={ css: [], js: [] } app.post('/result/:type/:time/:exec', function(req,res) { headresults[req.params.type].push(parseInt(req.params.time, 10)); bodyresults[req.params.type].push(parseInt(req.params.exec, 10)); res.end(); }); app.get('/result/:type', function(req,res) { var o = ''; headresults[req.params.type].forEach(function(i) { o+='\n' + i; }); o+='\n'; bodyresults[req.params.type].forEach(function(i) { o+='\n' + i; }); res.send(o); });

File css.html

shell
<!DOCTYPE html> <html> <head> <title>CSS first</title> <script>var start = Date.now();</script> <link rel="stylesheet" href="style.css"> <script src="jquery.js"></script> <script src="test.js"></script> </head> <body> <script>document.write(jsload - start);bodyexec=Date.now()</script> </body> </html>

File js.html

shell
<!DOCTYPE html> <html> <head> <title>CSS first</title> <script>var start = Date.now();</script> <script src="jquery.js"></script> <script src="test.js"></script> <link rel="stylesheet" href="style.css"> </head> <body> <script>document.write(jsload - start);bodyexec=Date.now()</script> </body> </html>

File test.js

shell
var jsload = Date.now(); $(function() { $.post('/result' + location.pathname.replace('.html','') + '/' + (jsload - start) + '/' + (bodyexec - start)); });

jQuery was jquery-1.7.1.min.js

Share

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 4.0

Edit

Follow

Follow this answer to receive notifications

edited Sep 3, 2022 at 17:40

[

Peter Mortensen's user avatar

](/users/63550/peter-mortensen)

Peter Mortensen

30.9k2222 gold badges107107 silver badges131131 bronze badges

answered Feb 14, 2012 at 6:37

[

josh3736's user avatar

](/users/201952/josh3736)

josh3736josh3736

141k3333 gold badges220220 silver badges268268 bronze badges

9

  • 146

    this is a fantastic answer, thanks for using the science! Per your result "in modern browsers, it looks like linking to CSS first never provides a performance gain", I think the answer to the question title is yes, the old advice of CSS first is clearly invalid.

    – Jeff Atwood

    Feb 14, 2012 at 7:54

  • Regarding @josh3736's update about the inverse on mobile... this is a case in point to not to jump the gun on this significant change. I'd be curious how other mobile browser behave (webkit, gecko, presto, trident, etc.) as performance in mobile is often more important.

    – scunliffe

    Feb 14, 2012 at 19:17

  • 1

    You should also try adding some slowness to printing out the css/js, to simulate speeds of a slow server.

    – kirb

    Feb 14, 2012 at 21:19

  • How about if you use defer or async? Does that change? (try with inline scripts and without inline scripts) Does that change?

    – brunoais

    Dec 25, 2012 at 18:28

  • 1

    "First, it's important to note that I'm operating under the assumption that you have scripts located in the <head> of your document (as opposed to the end of the <body>)." I would highlight that much earlier in the answer, like at the top. Including a script in head that refers to an external file is almost never correct, from almost any perspective (certainly not a performance one). I don't recall ever having had to do it in real life. The odd line or two of inline script maybe, but that's all. The default, without very good contrary reasons, should be the end of the body.

    – T.J. Crowder

    Dec 12, 2018 at 11:46

 |  Show 4 more comments

2024年6月29日 12:07 回复

This answer is useful

313

This answer is not useful

Save this answer.

Show activity on this post.

There are two main reasons to put CSS before JavaScript.

  1. 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.

  2. 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.

It's fun to create examples with Cuzillion. For example, this page has a script in the HEAD so the entire page is blank until it's done downloading. However, if we move the script to the end of the BODY block the page header renders since those DOM elements occur above the SCRIPT tag, as you can see on this page.

Share

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 3.0

Edit

Follow

Follow this answer to receive notifications

edited Feb 15, 2012 at 7:06

[

Jeff Atwood's user avatar

](/users/1/jeff-atwood)

Jeff Atwood

63.6k4848 gold badges150150 silver badges153153 bronze badges

answered Feb 14, 2012 at 6:27

[

Steve Souders's user avatar

](/users/1208454/steve-souders)

Steve SoudersSteve Souders

1,89711 gold badge1010 silver badges33 bronze badges

7

 |  Show 2 more comments

2024年6月29日 12:07 回复

This answer is useful

48

This answer is not useful

Save this answer.

Show activity on this post.

I would not emphasize too much on the results that you have got. I believe that it is subjective, but I have a reason to explain you that it is better to put in CSS before JavaScript.

During the loading of your website, there are two scenarios that you would see:

Case 1: white screen → unstyled website → styled website → interaction → styled and interactive website

Case 2: white screen → unstyled website → interaction → styled website → styled and interactive website

I honestly can't imagine anyone choosing Case 2. This would mean that visitors using slow Internet connections will be faced with an unstyled website, that allows them to interact with it using JavaScript (since that is already loaded). Furthermore, the amount of time spend looking at an unstyled website would be maximized this way. Why would anyone want that?

It also works better, as jQuery states:

"When using scripts that rely on the value of CSS style properties, it's important to reference external stylesheets or embed style elements before referencing the scripts".

When the files are loaded in the wrong order (first JavaScript, then CSS), any JavaScript code relying on properties set in CSS files (for example, the width or height of a div) won't be loaded correctly. It seems that with the wrong loading order, the correct properties are 'sometimes' known to JavaScript (perhaps this is caused by a race condition?). This effect seems bigger or smaller depending on the browser used.

Share

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 4.0

Edit

Follow

Follow this answer to receive notifications

edited Sep 3, 2022 at 19:31

[

Peter Mortensen's user avatar

](/users/63550/peter-mortensen)

Peter Mortensen

30.9k2222 gold badges107107 silver badges131131 bronze badges

answered Feb 14, 2012 at 7:55

[

defau1t's user avatar

](/users/724764/defau1t)

defau1tdefau1t

10.6k22 gold badges3535 silver badges4747 bronze badges

2

  • 2

    How would you go about guaranteeing all the css was loaded before the javascript executes? Can you? or should your javascript be robust enough to deal with the situation where the styles might not necessarily be loaded.

    – Jonnio

    Feb 15, 2012 at 12:13

  • @Jonnio If your JS has a dependency, then you should make that dependency explicit. Otherwise, you will always have rare timing issues. ES6 modules are a good way to make that happen, but there are many libraries that could be used as well.

    – kmkemp

    Nov 9, 2018 at 19:24

Add a comment  | 

2024年6月29日 12:07 回复

This answer is useful

30

This answer is not useful

Save this answer.

Show activity on this post.

Were your tests performed on your personal computer, or on a web server? It is a blank page, or is it a complex online system with images, databases, etc.? Are your scripts performing a simple hover event action, or are they a core component to how your website renders and interacts with the user? There are several things to consider here, and the relevance of these recommendations almost always become rules when you venture into high-caliber web development.

The purpose of the "put stylesheets at the top and scripts at the bottom" rule is that, in general, it's the best way to achieve optimal progressive rendering, which is critical to the user experience.

All else aside: assuming your test is valid, and you really are producing results contrary to the popular rules, it'd come as no surprise, really. Every website (and everything it takes to make the whole thing appear on a user's screen) is different and the Internet is constantly evolving.

Share

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 3.0

Edit

Follow

Follow this answer to receive notifications

edited Feb 14, 2012 at 6:54

community wiki

11 revs
sunday

2

  • 1

    I appreciate the point you are making in bold, but the OP is talking about what happens when you vary the order with both at the top, neither at the bottom.

    – nnnnnn

    Feb 14, 2012 at 5:35

  • 1

    Thus, "assuming [his] test is valid."

    – skippr

    Feb 14, 2012 at 5:40

Add a comment  | 

2024年6月29日 12:07 回复

This answer is useful

24

This answer is not useful

Save this answer.

Show activity on this post.

I include CSS files before JavaScript for a different reason.

If my JavaScript code needs to do dynamic sizing of some page element (for those corner cases where CSS is really a main in the back) then loading the CSS after the JS is russing can lead to race conditions, where the element is resized before CSS styles are applied and thus looks weird when the styles finally kick in. If I load the CSS beforehand I can guarantee that things run in the intended order and that the final layout is what I want it to be.

Share

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 4.0

Edit

Follow

Follow this answer to receive notifications

edited Sep 3, 2022 at 17:43

[

Peter Mortensen's user avatar

](/users/63550/peter-mortensen)

Peter Mortensen

30.9k2222 gold badges107107 silver badges131131 bronze badges

answered Feb 14, 2012 at 13:31

[

hugomg's user avatar

](/users/90511/hugomg)

hugomghugomg

68.9k2525 gold badges161161 silver badges247247 bronze badges

7

  • 3

    this will break one day on some browser. I am not guessing.

    – jcolebrand

    Feb 15, 2012 at 18:14

  • 1

    jcolebrand: Yes, I think I hadn't drunk enough coffee when I wrote this. (In retrospect, I guess the important things are just to avoid dynamic loading of CSS and putting the JS inside a domReady event if you need to do dynamic sizing)

    – hugomg

    Feb 15, 2012 at 18:25

  • Scripts should should not change any display. That's the CSS job. HTML = content, CSS = How to display content, javascript change content dynamically. Also js should only act after (or while) the DOMContentLoaded is fired with some little but very specific situations.

    – brunoais

    Dec 25, 2012 at 18:36

  • @brunoais: Some layouts can only be created with Javascript though. For example, anything that needs to be dynamically resized must be made via Javascript and some things (like having a size be 100% - 20px) need Javascript to be done portably in old browsers.

    – hugomg

    Dec 25, 2012 at 21:04

  • @missingno In those cases, just use the DOMContentLoaded event, anyway. But I understand what you mean. (Stupid IE!)

    – brunoais

    Dec 25, 2012 at 21:10

 |  Show 2 more comments

2024年6月29日 12:07 回复

This answer is useful

第754章

This answer is not useful

Save this answer.

Show activity on this post.

这是一个非常有趣的问题。我总是把 CSS<link href="...">放在 JavaScript 之前,<script src="...">因为“我曾经读到过它更好”。所以,你是对的;现在是我们进行一些实际研究的时候了!

我在Node.js中设置了自己的测试工具(代码如下)。基本上,我:

  • 确保没有 HTTP 缓存,因此浏览器每次加载页面时都必须执行完整下载。
  • 为了模拟现实,我添加了 jQuery 和H5BP CSS(因此需要解析大量的脚本/CSS)
  • 设置两个页面 - 一个在脚本之前使用 CSS,另一个在脚本之后使用 CSS。
  • **<head>**记录外部脚本执行的时间
  • 记录了 中的内联脚本执行的时间**<body>**,类似于DOMReady.
  • 将 CSS 和/或脚本发送到浏览器的时间延迟了 500 毫秒。
  • 在三大主流浏览器中运行测试20次。

结果

首先,CSS文件延迟500毫秒(单位是毫秒):

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 583 36 | 559 42 | 565 49 St Dev | 15 12 | 9 7 | 13 6 ------------|--------------|--------------|------------ Body Exec | | | Average | 584 521 | 559 513 | 565 519 St Dev | 15 9 | 9 5 | 13 7

接下来,我将 jQuery 设置为延迟 500 毫秒,而不是 CSS:

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 597 556 | 562 559 | 564 564 St Dev | 14 12 | 11 7 | 8 8 ------------|--------------|--------------|------------ Body Exec | | | Average | 598 557 | 563 560 | 564 565 St Dev | 14 12 | 10 7 | 8 8

最后,我将jQuery 和 CSS都设置为延迟 500 毫秒:

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 620 560 | 577 577 | 571 567 St Dev | 16 11 | 19 9 | 9 10 ------------|--------------|--------------|------------ Body Exec | | | Average | 623 561 | 578 580 | 571 568 St Dev | 18 11 | 19 9 | 9 10

结论

首先,需要注意的是,我的操作假设您的脚本位于<head>文档的 中(而不是位于 的末尾<body>)。关于为什么您可以在<head>文档末尾链接到脚本有各种争论,但这超出了本答案的范围。这严格来说是关于s 中<script>s 是否应该位于<link>s之前<head>

在现代桌面浏览器中,看起来首先链接到 CSS永远不会带来性能提升。当 CSS 和脚本都延迟时,将 CSS 放在脚本后面会给你带来微不足道的收益,但当 CSS 延迟时会给你带来很大的收益。 (由last第一组结果中的列显示。)

鉴于最后链接到 CSS 似乎不会损害性能,但在某些情况下_可以_提供增益,因此如果不关心旧浏览器的性能, 则应**仅在桌面浏览器上链接到外部脚本****链接到外部样式表。**请继续阅读移动设备的情况。

为什么?

从历史上看,当浏览器遇到<script>指向外部资源的标签时,浏览器将停止解析 HTML,检索脚本,执行它,然后继续解析 HTML。相反,如果浏览器遇到<link>外部样式表,它将在获取 CSS 文件的同时_继续_解析 HTML(并行)。

因此,广泛重复的建议是首先放置样式表——首先下载它们,并且可以并行加载第一个下载的脚本。

然而,现代浏览器(包括我上面测试的所有浏览器)已经实现了推测性解析,其中浏览器在 HTML 中“向前看”并在脚本下载和执行_之前开始下载资源。_

在没有推测性解析的旧浏览器中,将脚本放在第一位会影响性能,因为它们不会并行下载。

浏览器支持

推测性解析首次实现于:(以及截至 2012 年 1 月使用此版本或更高版本的全球桌面浏览器用户的百分比)

目前使用的桌面浏览器总共大约有 85% 支持推测加载。将脚本放在 CSS 之前会给_全球_15% 的用户带来性能损失;您的里程可能会根据您网站的特定受众而有所不同。 (请记住,这个数字正在减少。)

在移动浏览器上,由于移动浏览器和操作系统环境的异构性,获得明确的数字有点困难。由于推测渲染是在 WebKit 525(2008 年 3 月发布)中实现的,并且几乎所有有价值的移动浏览器都基于 WebKit,因此我们可以得出结论,“大多数”移动浏览器_应该_支持它。根据quirksmode 的说法,iOS 2.2/Android 1.0 使用 WebKit 525。我不知道 Windows Phone 是什么样子。

**然而,**我在 Android 4 设备上运行了测试,虽然我看到的数字与桌面结果类似,但我将其连接到Android 版 Chrome 中出色的新远程调试器, _“网络”_选项卡显示浏览器实际上正在等待下载CSS 直到 JavaScript 代码完全加载 - 换句话说,即使是 Android 版 WebKit 的最新版本似乎也不支持推测性解析。 我怀疑它可能由于移动设备固有的 CPU、内存和/或网络限制而被关闭。

代码

请原谅我的草率——这是 Q&D。

文件_app.js_

shell
var express = require('express') , app = express.createServer() , fs = require('fs'); app.listen(90); var file={}; fs.readdirSync('.').forEach(function(f) { console.log(f) file[f] = fs.readFileSync(f); if (f != 'jquery.js' && f != 'style.css') app.get('/' + f, function(req,res) { res.contentType(f); res.send(file[f]); }); }); app.get('/jquery.js', function(req,res) { setTimeout(function() { res.contentType('text/javascript'); res.send(file['jquery.js']); }, 500); }); app.get('/style.css', function(req,res) { setTimeout(function() { res.contentType('text/css'); res.send(file['style.css']); }, 500); }); var headresults={ css: [], js: [] }, bodyresults={ css: [], js: [] } app.post('/result/:type/:time/:exec', function(req,res) { headresults[req.params.type].push(parseInt(req.params.time, 10)); bodyresults[req.params.type].push(parseInt(req.params.exec, 10)); res.end(); }); app.get('/result/:type', function(req,res) { var o = ''; headresults[req.params.type].forEach(function(i) { o+='\n' + i; }); o+='\n'; bodyresults[req.params.type].forEach(function(i) { o+='\n' + i; }); res.send(o); });

文件_css.html_

shell
<!DOCTYPE html> <html> <head> <title>CSS first</title> <script>var start = Date.now();</script> <link rel="stylesheet" href="style.css"> <script src="jquery.js"></script> <script src="test.js"></script> </head> <body> <script>document.write(jsload - start);bodyexec=Date.now()</script> </body> </html>

文件_js.html_

shell
<!DOCTYPE html> <html> <head> <title>CSS first</title> <script>var start = Date.now();</script> <script src="jquery.js"></script> <script src="test.js"></script> <link rel="stylesheet" href="style.css"> </head> <body> <script>document.write(jsload - start);bodyexec=Date.now()</script> </body> </html>

文件_test.js_

shell
var jsload = Date.now(); $(function() { $.post('/result' + location.pathname.replace('.html','') + '/' + (jsload - start) + '/' + (bodyexec - start)); });

jQueryjquery-1.7.1.min.js

分享

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 4.0

编辑

跟随

Follow this answer to receive notifications

编辑于 2022 年 9 月 3 日 17:40

[

彼得·莫滕森的用户头像

](/users/63550/peter-mortensen)

彼得·莫滕森

30.9k2222枚金徽章107107 银徽章131131枚青铜徽章

回复于 2012 年 2 月 14 日 6:37

[

josh3736 的用户头像

](/users/201952/josh3736)

乔什3736josh3736

141k3333枚金色徽章220220枚银质徽章268268枚青铜徽章

9

  • 146

    这是一个很棒的答案,感谢您使用科学!根据你的结果**“在现代浏览器中,看起来首先链接到 CSS 永远不会提供性能增益”**,我认为问题标题的答案是_肯定的_,CSS 首先的旧建议显然是无效的。

    – 杰夫·阿特伍德

    2012 年 2 月 14 日 7:54

  • 关于 @josh3736 关于移动设备上的逆的更新...这是一个很好的例子,不要在这个重大变化上操之过急。我很好奇其他移动浏览器的行为(webkit、gecko、presto、trident 等),因为移动设备的性能通常更重要。

    – 斯肯利夫

    2012 年 2 月 14 日 19:17

  • 1

    您还应该尝试添加一些慢速来打印 css/js,以模拟慢速服务器的速度。

    – 柯布

    2012 年 2 月 14 日 21:19

  • 如果使用 defer 或 async 怎么样?这会改变吗? (尝试使用内联脚本和不使用内联脚本)这会改变吗?

    – 布鲁诺埃

    2012 年 12 月 25 日 18:28

  • 1

    _“首先,需要注意的是,我的操作假设您的脚本位于<head>文档的末尾(而不是末尾<body>)。”_我会在答案的较早部分强调这一点**,例如在顶部。从几乎任何角度(当然不是性能角度)来看,包含引用外部文件的scriptin几乎从来都不正确。head我不记得在现实生活中曾经必须这样做过。_内联_脚本可能有一两行奇数,但仅此而已。如果没有很好**的相反理由,默认值应该是正文的结尾。

    – TJ·克劳德

    2018 年 12 月 12 日 11:46

 |  显示另外4条评论

2024年6月29日 12:07 回复

This answer is useful

313

This answer is not useful

Save this answer.

Show activity on this post.

将 CSS 放在 JavaScript 之前有两个主要原因。

  1. 旧浏览器(Internet Explorer 6-7、Firefox 2 等)在开始下载脚本时会阻止所有后续下载。因此,如果您a.js遵循,b.css它们将按顺序下载:先是 a,然后是 b。如果您b.css遵循,a.js它们会并行下载,因此页面加载速度更快。

  2. 在下载所有样式表之前不会呈现任何内容 - 在所有浏览器中都是如此。脚本是不同的 - 它们会阻止页面中_脚本标记下方_的所有 DOM 元素的渲染。如果将脚本放在 HEAD 中,则意味着整个页面将被阻止渲染,直到下载所有样式表和所有脚本。虽然阻止样式表的所有渲染是有意义的(以便您第一次获得正确的样式并避免无样式内容的闪现),但阻止脚本的整个页面的渲染是没有意义的。通常,脚本不会影响任何 DOM 元素或仅影响 DOM 元素的一部分。最好在页面尽可能低的位置加载脚本,或者更好地异步加载它们。

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

分享

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 3.0

编辑

跟随

Follow this answer to receive notifications

2012 年 2 月 15 日 7:06编辑

[

杰夫·阿特伍德的用户头像

](/users/1/jeff-atwood)

杰夫·阿特伍德

63.6k4848枚金色徽章150150 枚银质徽章153153枚青铜徽章

回复于 2012 年 2 月 14 日 6:27

[

Steve Souders 的用户头像

](/users/1208454/steve-souders)

史蒂夫·苏德斯Steve Souders

1,89711 个金色徽章1010 枚银色徽章33枚青铜徽章

7

 |  显示另外2条评论

2024年6月29日 12:07 回复

This answer is useful

48

This answer is not useful

Save this answer.

Show activity on this post.

我不会过多强调你所得到的结果。我相信这是主观的,但我有理由向你解释,最好在 JavaScript 之前放入 CSS。

在加载网站期间,您会看到两种情况:

案例1:白屏→无样式网站→有样式的网站→交互→有样式的交互式网站

案例2:白屏→无样式网站→交互→有样式的网站→有样式和交互式的网站

老实说,我无法想象有人会选择案例 2。这意味着使用慢速 Internet 连接的访问​​者将面临一个无样式的网站,该网站允许他们使用 JavaScript 与其进行交互(因为该网站已加载)。此外,通过这种方式,花在浏览无样式网站上的时间将会最大化。为什么有人想要那个?

正如jQuery 所说,它也能更好地工作:

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

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

分享

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 4.0

编辑

跟随

Follow this answer to receive notifications

编辑于 2022 年 9 月 3 日 19:31

[

彼得·莫滕森的用户头像

](/users/63550/peter-mortensen)

彼得·莫滕森

30.9k2222枚金徽章107107 银徽章131131枚青铜徽章

回复于2012 年 2 月 14 日 7:55

[

defau1t的用户头像

](/users/724764/defau1t)

默认值defau1t

10.6k22 个金色徽章3535 枚银质徽章4747枚青铜徽章

2

  • 2

    How would you go about guaranteeing all the css was loaded before the javascript executes? Can you? or should your javascript be robust enough to deal with the situation where the styles might not necessarily be loaded.

    – Jonnio

    Feb 15, 2012 at 12:13

  • @Jonnio If your JS has a dependency, then you should make that dependency explicit. Otherwise, you will always have rare timing issues. ES6 modules are a good way to make that happen, but there are many libraries that could be used as well.

    – kmkemp

    Nov 9, 2018 at 19:24

Add a comment  | 

2024年6月29日 12:07 回复

This answer is useful

30

This answer is not useful

Save this answer.

Show activity on this post.

Were your tests performed on your personal computer, or on a web server? It is a blank page, or is it a complex online system with images, databases, etc.? Are your scripts performing a simple hover event action, or are they a core component to how your website renders and interacts with the user? There are several things to consider here, and the relevance of these recommendations almost always become rules when you venture into high-caliber web development.

The purpose of the "put stylesheets at the top and scripts at the bottom" rule is that, in general, it's the best way to achieve optimal progressive rendering, which is critical to the user experience.

All else aside: assuming your test is valid, and you really are producing results contrary to the popular rules, it'd come as no surprise, really. Every website (and everything it takes to make the whole thing appear on a user's screen) is different and the Internet is constantly evolving.

Share

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 3.0

Edit

Follow

Follow this answer to receive notifications

edited Feb 14, 2012 at 6:54

community wiki

11 revs
sunday

2

  • 1

    I appreciate the point you are making in bold, but the OP is talking about what happens when you vary the order with both at the top, neither at the bottom.

    – nnnnnn

    Feb 14, 2012 at 5:35

  • 1

    Thus, "assuming [his] test is valid."

    – skippr

    Feb 14, 2012 at 5:40

Add a comment  | 

2024年6月29日 12:07 回复

This answer is useful

24

This answer is not useful

Save this answer.

Show activity on this post.

I include CSS files before JavaScript for a different reason.

If my JavaScript code needs to do dynamic sizing of some page element (for those corner cases where CSS is really a main in the back) then loading the CSS after the JS is russing can lead to race conditions, where the element is resized before CSS styles are applied and thus looks weird when the styles finally kick in. If I load the CSS beforehand I can guarantee that things run in the intended order and that the final layout is what I want it to be.

Share

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 4.0

Edit

Follow

Follow this answer to receive notifications

edited Sep 3, 2022 at 17:43

[

彼得·莫滕森的用户头像

](/users/63550/peter-mortensen)

Peter Mortensen

30.9k2222 gold badges107107 silver badges131131 bronze badges

answered Feb 14, 2012 at 13:31

[

Hugomg 的用户头像

](/users/90511/hugomg)

hugomghugomg

68.9k2525 gold badges161161 silver badges247247 bronze badges

7

  • 3

    this will break one day on some browser. I am not guessing.

    – jcolebrand

    Feb 15, 2012 at 18:14

  • 1

    jcolebrand: Yes, I think I hadn't drunk enough coffee when I wrote this. (In retrospect, I guess the important things are just to avoid dynamic loading of CSS and putting the JS inside a domReady event if you need to do dynamic sizing)

    – hugomg

    Feb 15, 2012 at 18:25

  • Scripts should should not change any display. That's the CSS job. HTML = content, CSS = How to display content, javascript change content dynamically. Also js should only act after (or while) the DOMContentLoaded is fired with some little but very specific situations.

    – brunoais

    Dec 25, 2012 at 18:36

  • @brunoais: Some layouts can only be created with Javascript though. For example, anything that needs to be dynamically resized must be made via Javascript and some things (like having a size be 100% - 20px) need Javascript to be done portably in old browsers.

    – hugomg

    Dec 25, 2012 at 21:04

  • @missingno In those cases, just use the DOMContentLoaded event, anyway. But I understand what you mean. (Stupid IE!)

    – brunoais

    Dec 25, 2012 at 21:10

 |  Show 2 more comments

2024年6月29日 12:07 回复

This answer is useful

754

This answer is not useful

Save this answer.

Show activity on this post.

This is a very interesting question. I've always put my CSS <link href="...">s before my JavaScript <script src="...">s because "I read one time that it's better." So, you're right; it's high time we do some actual research!

I set up my own test harness in Node.js (code below). Basically, I:

  • Made sure there was no HTTP caching so the browser would have to do a full download each time a page is loaded.
  • To simulate reality, I included jQuery and the H5BP CSS (so there's a decent amount of script/CSS to parse)
  • Set up two pages - one with CSS before script, one with CSS after script.
  • Recorded how long it took for the external script in the <head> to execute
  • Recorded how long it took for the inline script in the <body> to execute, which is analogous to DOMReady.
  • Delayed sending CSS and/or script to the browser by 500 ms.
  • Ran the test 20 times in the three major browsers.

Results

First, with the CSS file delayed by 500 ms (the unit is milliseconds):

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 583 36 | 559 42 | 565 49 St Dev | 15 12 | 9 7 | 13 6 ------------|--------------|--------------|------------ Body Exec | | | Average | 584 521 | 559 513 | 565 519 St Dev | 15 9 | 9 5 | 13 7

Next, I set jQuery to delay by 500 ms instead of the CSS:

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 597 556 | 562 559 | 564 564 St Dev | 14 12 | 11 7 | 8 8 ------------|--------------|--------------|------------ Body Exec | | | Average | 598 557 | 563 560 | 564 565 St Dev | 14 12 | 10 7 | 8 8

Finally, I set both jQuery and the CSS to delay by 500 ms:

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 620 560 | 577 577 | 571 567 St Dev | 16 11 | 19 9 | 9 10 ------------|--------------|--------------|------------ Body Exec | | | Average | 623 561 | 578 580 | 571 568 St Dev | 18 11 | 19 9 | 9 10

Conclusions

First, it's important to note that I'm operating under the assumption that you have scripts located in the <head> of your document (as opposed to the end of the <body>). There are various arguments regarding why you might link to your scripts in the <head> versus the end of the document, but that's outside the scope of this answer. This is strictly about whether <script>s should go before <link>s in the <head>.

In modern DESKTOP browsers, it looks like linking to CSS first never provides a performance gain. Putting CSS after script gets you a trivial amount of gain when both CSS and script are delayed, but gives you large gains when CSS is delayed. (Shown by the last columns in the first set of results.)

Given that linking to CSS last does not seem to hurt performance but can provide gains under certain circumstances, you should link to external style sheets after you link to external scripts only on desktop browsers if the performance of old browsers is not a concern. Read on for the mobile situation.

Why?

Historically, when a browser encountered a <script> tag pointing to an external resource, the browser would stop parsing the HTML, retrieve the script, execute it, then continue parsing the HTML. In contrast, if the browser encountered a <link> for an external style sheet, it would continue parsing the HTML while it fetched the CSS file (in parallel).

Hence, the widely-repeated advice to put style sheets first – they would download first, and the first script to download could be loaded in parallel.

However, modern browsers (including all of the browsers I tested with above) have implemented speculative parsing, where the browser "looks ahead" in the HTML and begins downloading resources before scripts download and execute.

In old browsers without speculative parsing, putting scripts first will affect performance since they will not download in parallel.

Browser Support

Speculative parsing was first implemented in: (along with the percentage of worldwide desktop browser users using this version or greater as of Jan 2012)

目前使用的桌面浏览器总共大约有 85% 支持推测加载。将脚本放在 CSS 之前会给_全球_15% 的用户带来性能损失;您的里程可能会根据您网站的特定受众而有所不同。 (请记住,这个数字正在减少。)

在移动浏览器上,由于移动浏览器和操作系统环境的异构性,获得明确的数字有点困难。由于推测渲染是在 WebKit 525(2008 年 3 月发布)中实现的,并且几乎所有有价值的移动浏览器都基于 WebKit,因此我们可以得出结论,“大多数”移动浏览器_应该_支持它。根据quirksmode 的说法,iOS 2.2/Android 1.0 使用 WebKit 525。我不知道 Windows Phone 是什么样子。

**然而,**我在 Android 4 设备上运行了测试,虽然我看到的数字与桌面结果类似,但我将其连接到Android 版 Chrome 中出色的新远程调试器, _“网络”_选项卡显示浏览器实际上正在等待下载CSS 直到 JavaScript 代码完全加载 - 换句话说,即使是 Android 版 WebKit 的最新版本似乎也不支持推测性解析。 我怀疑它可能由于移动设备固有的 CPU、内存和/或网络限制而被关闭。

代码

请原谅我的草率——这是 Q&D。

文件_app.js_

shell
var express = require('express') , app = express.createServer() , fs = require('fs'); app.listen(90); var file={}; fs.readdirSync('.').forEach(function(f) { console.log(f) file[f] = fs.readFileSync(f); if (f != 'jquery.js' && f != 'style.css') app.get('/' + f, function(req,res) { res.contentType(f); res.send(file[f]); }); }); app.get('/jquery.js', function(req,res) { setTimeout(function() { res.contentType('text/javascript'); res.send(file['jquery.js']); }, 500); }); app.get('/style.css', function(req,res) { setTimeout(function() { res.contentType('text/css'); res.send(file['style.css']); }, 500); }); var headresults={ css: [], js: [] }, bodyresults={ css: [], js: [] } app.post('/result/:type/:time/:exec', function(req,res) { headresults[req.params.type].push(parseInt(req.params.time, 10)); bodyresults[req.params.type].push(parseInt(req.params.exec, 10)); res.end(); }); app.get('/result/:type', function(req,res) { var o = ''; headresults[req.params.type].forEach(function(i) { o+='\n' + i; }); o+='\n'; bodyresults[req.params.type].forEach(function(i) { o+='\n' + i; }); res.send(o); });

文件_css.html_

shell
<!DOCTYPE html> <html> <head> <title>CSS first</title> <script>var start = Date.now();</script> <link rel="stylesheet" href="style.css"> <script src="jquery.js"></script> <script src="test.js"></script> </head> <body> <script>document.write(jsload - start);bodyexec=Date.now()</script> </body> </html>

文件_js.html_

shell
<!DOCTYPE html> <html> <head> <title>CSS first</title> <script>var start = Date.now();</script> <script src="jquery.js"></script> <script src="test.js"></script> <link rel="stylesheet" href="style.css"> </head> <body> <script>document.write(jsload - start);bodyexec=Date.now()</script> </body> </html>

文件_test.js_

shell
var jsload = Date.now(); $(function() { $.post('/result' + location.pathname.replace('.html','') + '/' + (jsload - start) + '/' + (bodyexec - start)); });

jQueryjquery-1.7.1.min.js

分享

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 4.0

编辑

跟随

Follow this answer to receive notifications

编辑于 2022 年 9 月 3 日 17:40

[

彼得·莫滕森的用户头像

](/users/63550/peter-mortensen)

彼得·莫滕森

30.9k2222枚金徽章107107 银徽章131131枚青铜徽章

回复于 2012 年 2 月 14 日 6:37

[

josh3736 的用户头像

](/users/201952/josh3736)

乔什3736josh3736

141k3333枚金色徽章220220枚银质徽章268268枚青铜徽章

9

  • 146

    这是一个很棒的答案,感谢您使用科学!根据你的结果**“在现代浏览器中,看起来首先链接到 CSS 永远不会提供性能增益”**,我认为问题标题的答案是_肯定的_,CSS 首先的旧建议显然是无效的。

    – 杰夫·阿特伍德

    2012 年 2 月 14 日 7:54

  • 关于 @josh3736 关于移动设备上的逆的更新...这是一个很好的例子,不要在这个重大变化上操之过急。我很好奇其他移动浏览器的行为(webkit、gecko、presto、trident 等),因为移动设备的性能通常更重要。

    – 斯肯利夫

    2012 年 2 月 14 日 19:17

  • 1

    您还应该尝试添加一些慢速来打印 css/js,以模拟慢速服务器的速度。

    – 柯布

    2012 年 2 月 14 日 21:19

  • 如果使用 defer 或 async 怎么样?这会改变吗? (尝试使用内联脚本和不使用内联脚本)这会改变吗?

    – 布鲁诺埃

    2012 年 12 月 25 日 18:28

  • 1

    _“首先,需要注意的是,我的操作假设您的脚本位于<head>文档的末尾(而不是末尾<body>)。”_我会在答案的较早部分强调这一点**,例如在顶部。从几乎任何角度(当然不是性能角度)来看,包含引用外部文件的scriptin几乎从来都不正确。head我不记得在现实生活中曾经必须这样做过。_内联_脚本可能有一两行奇数,但仅此而已。如果没有很好**的相反理由,默认值应该是正文的结尾。

    – TJ·克劳德

    2018 年 12 月 12 日 11:46

 |  显示另外4条评论

2024年6月29日 12:07 回复

This answer is useful

313

This answer is not useful

Save this answer.

Show activity on this post.

将 CSS 放在 JavaScript 之前有两个主要原因。

  1. 旧浏览器(Internet Explorer 6-7、Firefox 2 等)在开始下载脚本时会阻止所有后续下载。因此,如果您a.js遵循,b.css它们将按顺序下载:先是 a,然后是 b。如果您b.css遵循,a.js它们会并行下载,因此页面加载速度更快。

  2. 在下载所有样式表之前不会呈现任何内容 - 在所有浏览器中都是如此。脚本是不同的 - 它们会阻止页面中_脚本标记下方_的所有 DOM 元素的渲染。如果将脚本放在 HEAD 中,则意味着整个页面将被阻止渲染,直到下载所有样式表和所有脚本。虽然阻止样式表的所有渲染是有意义的(以便您第一次获得正确的样式并避免无样式内容的闪现),但阻止脚本的整个页面的渲染是没有意义的。通常,脚本不会影响任何 DOM 元素或仅影响 DOM 元素的一部分。最好在页面尽可能低的位置加载脚本,或者更好地异步加载它们。

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

分享

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 3.0

编辑

跟随

Follow this answer to receive notifications

2012 年 2 月 15 日 7:06编辑

[

杰夫·阿特伍德的用户头像

](/users/1/jeff-atwood)

杰夫·阿特伍德

63.6k4848枚金色徽章150150 枚银质徽章153153枚青铜徽章

回复于 2012 年 2 月 14 日 6:27

[

Steve Souders 的用户头像

](/users/1208454/steve-souders)

史蒂夫·苏德斯Steve Souders

1,89711 个金色徽章1010 枚银色徽章33枚青铜徽章

7

 |  Show 2 more comments

2024年6月29日 12:07 回复

This answer is useful

48

This answer is not useful

Save this answer.

Show activity on this post.

I would not emphasize too much on the results that you have got. I believe that it is subjective, but I have a reason to explain you that it is better to put in CSS before JavaScript.

During the loading of your website, there are two scenarios that you would see:

Case 1: white screen → unstyled website → styled website → interaction → styled and interactive website

Case 2: white screen → unstyled website → interaction → styled website → styled and interactive website

I honestly can't imagine anyone choosing Case 2. This would mean that visitors using slow Internet connections will be faced with an unstyled website, that allows them to interact with it using JavaScript (since that is already loaded). Furthermore, the amount of time spend looking at an unstyled website would be maximized this way. Why would anyone want that?

It also works better, as jQuery states:

"When using scripts that rely on the value of CSS style properties, it's important to reference external stylesheets or embed style elements before referencing the scripts".

When the files are loaded in the wrong order (first JavaScript, then CSS), any JavaScript code relying on properties set in CSS files (for example, the width or height of a div) won't be loaded correctly. It seems that with the wrong loading order, the correct properties are 'sometimes' known to JavaScript (perhaps this is caused by a race condition?). This effect seems bigger or smaller depending on the browser used.

Share

Share a link to this answer (Includes your user id)

Copy linkCC BY-SA 4.0

Edit

Follow

Follow this answer to receive notifications

edited Sep 3, 2022 at 19:31

[

彼得·莫滕森的用户头像

](/users/63550/peter-mortensen)

Peter Mortensen

30.9k2222 gold badges107107 silver badges131131 bronze badges

answered Feb 14, 2012 at 7:55

[

defau1t的用户头像

](/users/724764/defau1t)

defau1tdefau1t

10.6k22 gold badges3535 silver badges4747 bronze badges

2

  • 2

    How would you go about guaranteeing all the css was loaded before the javascript executes? Can you? or should your javascript be robust enough to deal with the situation where the styles might not necessarily be loaded.

    – Jonnio

    Feb 15, 2012 at 12:13

  • @Jonnio If your JS has a dependency, then you should make that dependency explicit. Otherwise, you will always have rare timing issues. ES6 modules are a good way to make that happen, but there are many libraries that could be used as well.

    – kmkemp

    Nov 9, 2018 at 19:24

Add a comment  | 

2024年6月29日 12:07 回复

这是一个非常有趣的问题。我总是把 CSS<link href="...">放在 JavaScript 之前,<script src="...">因为“我曾经读到过它更好”。所以,你是对的;现在是我们进行一些实际研究的时候了!

我在Node.js中设置了自己的测试工具(代码如下)。基本上,我:

  • 确保没有 HTTP 缓存,因此浏览器每次加载页面时都必须执行完整下载。
  • 为了模拟现实,我添加了 jQuery 和H5BP CSS(因此需要解析大量的脚本/CSS)
  • 设置两个页面 - 一个在脚本之前使用 CSS,另一个在脚本之后使用 CSS。
  • **<head>**记录外部脚本执行的时间
  • 记录了 中的内联脚本执行的时间**<body>**,类似于DOMReady.
  • 将 CSS 和/或脚本发送到浏览器的时间延迟了 500 毫秒。
  • 在三大主流浏览器中运行测试20次。

结果

首先,CSS文件延迟500毫秒(单位是毫秒):

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 583 36 | 559 42 | 565 49 St Dev | 15 12 | 9 7 | 13 6 ------------|--------------|--------------|------------ Body Exec | | | Average | 584 521 | 559 513 | 565 519 St Dev | 15 9 | 9 5 | 13 7

接下来,我将 jQuery 设置为延迟 500 毫秒,而不是 CSS:

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 597 556 | 562 559 | 564 564 St Dev | 14 12 | 11 7 | 8 8 ------------|--------------|--------------|------------ Body Exec | | | Average | 598 557 | 563 560 | 564 565 St Dev | 14 12 | 10 7 | 8 8

最后,我将jQuery 和 CSS都设置为延迟 500 毫秒:

shell
Browser: Chrome 18 | IE 9 | Firefox 9 CSS: first last | first last | first last ======================================================= Header Exec | | | Average | 620 560 | 577 577 | 571 567 St Dev | 16 11 | 19 9 | 9 10 ------------|--------------|--------------|------------ Body Exec | | | Average | 623 561 | 578 580 | 571 568 St Dev | 18 11 | 19 9 | 9 10

结论

首先,需要注意的是,我的操作假设您的脚本位于<head>文档的 中(而不是位于 的末尾<body>)。关于为什么您可以在<head>文档末尾链接到脚本有各种争论,但这超出了本答案的范围。这严格来说是关于s 中<script>s 是否应该位于<link>s之前<head>

在现代桌面浏览器中,看起来首先链接到 CSS永远不会带来性能提升。当 CSS 和脚本都延迟时,将 CSS 放在脚本后面会给你带来微不足道的收益,但当 CSS 延迟时会给你带来很大的收益。 (由last第一组结果中的列显示。)

鉴于最后链接到 CSS 似乎不会损害性能,但在某些情况下_可以_提供增益,因此如果不关心旧浏览器的性能, 则应**仅在桌面浏览器上链接到外部脚本****链接到外部样式表。**请继续阅读移动设备的情况。

为什么?

从历史上看,当浏览器遇到<script>指向外部资源的标签时,浏览器将停止解析 HTML,检索脚本,执行它,然后继续解析 HTML。相反,如果浏览器遇到<link>外部样式表,它将在获取 CSS 文件的同时_继续_解析 HTML(并行)。

因此,广泛重复的建议是首先放置样式表——首先下载它们,并且可以并行加载第一个下载的脚本。

然而,现代浏览器(包括我上面测试的所有浏览器)已经实现了推测性解析,其中浏览器在 HTML 中“向前看”并在脚本下载和执行_之前开始下载资源。_

在没有推测性解析的旧浏览器中,将脚本放在第一位会影响性能,因为它们不会并行下载。

浏览器支持

推测性解析首次实现于:(以及截至 2012 年 1 月使用此版本或更高版本的全球桌面浏览器用户的百分比)

目前使用的桌面浏览器总共大约有 85% 支持推测加载。将脚本放在 CSS 之前会给_全球_15% 的用户带来性能损失;您的里程可能会根据您网站的特定受众而有所不同。 (请记住,这个数字正在减少。)

在移动浏览器上,由于移动浏览器和操作系统环境的异构性,获得明确的数字有点困难。由于推测渲染是在 WebKit 525(2008 年 3 月发布)中实现的,并且几乎所有有价值的移动浏览器都基于 WebKit,因此我们可以得出结论,“大多数”移动浏览器_应该_支持它。根据quirksmode 的说法,iOS 2.2/Android 1.0 使用 WebKit 525。我不知道 Windows Phone 是什么样子。

**然而,**我在 Android 4 设备上运行了测试,虽然我看到的数字与桌面结果类似,但我将其连接到Android 版 Chrome 中出色的新远程调试器, _“网络”_选项卡显示浏览器实际上正在等待下载CSS 直到 JavaScript 代码完全加载 - 换句话说,即使是 Android 版 WebKit 的最新版本似乎也不支持推测性解析。 我怀疑它可能由于移动设备固有的 CPU、内存和/或网络限制而被关闭。

代码

请原谅我的草率——这是 Q&D。

文件_app.js_

shell
var express = require('express') , app = express.createServer() , fs = require('fs'); app.listen(90); var file={}; fs.readdirSync('.').forEach(function(f) { console.log(f) file[f] = fs.readFileSync(f); if (f != 'jquery.js' && f != 'style.css') app.get('/' + f, function(req,res) { res.contentType(f); res.send(file[f]); }); }); app.get('/jquery.js', function(req,res) { setTimeout(function() { res.contentType('text/javascript'); res.send(file['jquery.js']); }, 500); }); app.get('/style.css', function(req,res) { setTimeout(function() { res.contentType('text/css'); res.send(file['style.css']); }, 500); }); var headresults={ css: [], js: [] }, bodyresults={ css: [], js: [] } app.post('/result/:type/:time/:exec', function(req,res) { headresults[req.params.type].push(parseInt(req.params.time, 10)); bodyresults[req.params.type].push(parseInt(req.params.exec, 10)); res.end(); }); app.get('/result/:type', function(req,res) { var o = ''; headresults[req.params.type].forEach(function(i) { o+='\n' + i; }); o+='\n'; bodyresults[req.params.type].forEach(function(i) { o+='\n' + i; }); res.send(o); });

文件_css.html_

shell
<!DOCTYPE html> <html> <head> <title>CSS first</title> <script>var start = Date.now();</script> <link rel="stylesheet" href="style.css"> <script src="jquery.js"></script> <script src="test.js"></script> </head> <body> <script>document.write(jsload - start);bodyexec=Date.now()</script> </body> </html>

文件_js.html_

shell
<!DOCTYPE html> <html> <head> <title>CSS first</title> <script>var start = Date.now();</script> <script src="jquery.js"></script> <script src="test.js"></script> <link rel="stylesheet" href="style.css"> </head> <body> <script>document.write(jsload - start);bodyexec=Date.now()</script> </body> </html>

文件_test.js_

shell
var jsload = Date.now(); $(function() { $.post('/result' + location.pathname.replace('.html','') + '/' + (jsload - start) + '/' + (bodyexec - start)); });

jQueryjquery-1.7.1.min.js

2024年6月29日 12:07 回复

我不会过多强调你所得到的结果。我相信这是主观的,但我有理由向你解释,最好在 JavaScript 之前放入 CSS。

在加载网站期间,您会看到两种情况:

案例1:白屏→无样式网站→有样式的网站→交互→有样式的交互式网站

案例2:白屏→无样式网站→交互→有样式的网站→有样式和交互式的网站

老实说,我无法想象有人会选择案例 2。这意味着使用慢速 Internet 连接的访问​​者将面临一个无样式的网站,该网站允许他们使用 JavaScript 与其进行交互(因为该网站已加载)。此外,通过这种方式,花在浏览无样式网站上的时间将会最大化。为什么有人想要那个?

正如jQuery 所说,它也能更好地工作:

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

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

2024年6月29日 12:07 回复

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

**“将样式表放在顶部,将脚本放在底部”规则的目的是,一般来说,这是实现最佳_渐进式渲染的_最佳方式,**这对用户体验至关重要。

抛开其他一切不谈:假设您的测试是有效的,并且您确实产生了与流行规则相反的结果,那么这并不奇怪,真的。每个网站(以及使整个内容出现在用户屏幕上所需的一切)都是不同的,并且互联网在不断发展。

2024年6月29日 12:07 回复

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

如果我的 JavaScript 代码需要动态调整某些页面元素的大小(对于那些 CSS 在后面确实是主要元素的极端情况),那么在 JS 调用之后加载 CSS 可能会导致竞争条件,即元素在 CSS 之前调整大小应用了样式,因此当样式最终启动时看起来很奇怪。如果我事先加载 CSS,我可以保证事情按预期顺序运行,并且最终布局就是我想要的。

2024年6月29日 12:07 回复

在大多数情况下,将CSS放在JavaScript之前确实有几个明显的好处,主要是关于页面加载性能和用户体验方面的考虑。

1. 改善渲染性能

加载CSS之前的优先级是因为浏览器在解析HTML并构建DOM(文档对象模型)的同时,会并行下载CSS文件,并构建CSSOM(CSS对象模型)。一旦CSSOM和DOM都准备好了,浏览器将它们结合起来渲染页面。如果CSS加载被推迟,或者在JavaScript文件之后加载,浏览器可能无法立即渲染页面,因为它没有完成CSSOM的构建。这会导致页面显示不完整或者布局闪烁,影响用户体验。

例如,在实际项目中,如果CSS延迟加载,用户可能会看到未经样式处理的HTML内容(也称为FOUC——无样式内容的闪烁),直到CSS文件被加载和解析后,页面才会正常显示。

2. JavaScript操作CSS

另一个理由是,JavaScript经常会操作DOM并依赖于特定的CSS完成布局和功能。如果CSS在JavaScript之后加载,那么JavaScript在执行时可能无法正确查询或应用样式,因为相应的CSS规则还未就绪。

例如,如果一个JavaScript脚本试图动态调整元素的大小或位置,但相应的CSS尚未加载,脚本可能无法正确执行,因为它依赖的样式尚未应用于元素上。

3. 例外情况

尽管通常建议先加载CSS,但在某些情况下,可能需要优先加载JavaScript。例如,当JavaScript用于加载关键内容或功能时(如动态内容生成或提前获取数据),可能需要优先加载JavaScript。在这种情况下,开发者需要确保JavaScript的执行不会对页面渲染造成不良影响。

总结

总的来说,将CSS置于JavaScript之前可以优化页面渲染过程,减少页面内容闪烁,确保JavaScript能正确操作已经应用样式的DOM元素。这种做法符合Web性能优化的最佳实践。但也有例外,需要根据具体需求和场景特定地调整资源加载顺序。

2024年6月29日 12:07 回复

你的答案