[解決済み] CSSは常にJavascriptより優先されるべきか?
質問
ネット上では、JavaScriptの前にCSSを入れることを推奨しているのを数え切れないほど見かけました。その理由は一般的に この形式の :
CSSとJavaScriptの順番は、CSSを優先してください。 を先にします。その理由は、レンダリングスレッドがすべての スタイル情報は、ページをレンダリングするために必要です。もし、JavaScript が先にあると、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
では、CSSの転送に500msの遅延を与えています。
次のページを使ってテストしています。
<!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&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、Internet Explorerで同様の結果が得られます。しかし、Operaでは、順序は単に重要ではありません。
どうやら、CSSがすべてダウンロードされるまで、JavaScriptのインタプリタが起動を拒否しているようなのです。つまり、JavaScriptを先にインクルードしたほうが、JavaScriptスレッドの実行時間が長くなり、効率的なようです。
CSSインクルードをJavaScriptインクルードより先に配置するという推奨は正しくないのでしょうか?
<サブ 非同期を追加したり、レンダースレッドを解放するために setTimeout を使用したり、JavaScript コードをフッターに配置したり、JavaScript ローダーを使用したりできることは明らかです。ここでのポイントは、head内で必要不可欠なJavaScriptのビットとCSSのビットの順序についてです。
どのように解決する?
これは非常に興味深い質問です。 私はいつもCSSの
<link href="...">
はJSの前に
<script src="...">
というのも、以前その方がいいと書いてあったからです。
私はNodeで独自のテストハーネスをセットアップしました(コードは以下)。 基本的に、私は
- HTTPキャッシュがないことを確認し、ページが読み込まれるたびにブラウザが完全なダウンロードを行うようにしました。
- 現実をシミュレートするために、jQuery と H5BP CSS(なので、パースするスクリプト/CSSがちゃんとあります)
- スクリプトの前にCSSがあるページと、スクリプトの後にCSSがあるページの2つを設定します。
-
の外部スクリプトにどれくらいの時間がかかったかを記録。
<head>
を実行する。 -
のインラインスクリプトにかかった時間を記録。
<body>
を実行することであり、これはDOMReady
. - ブラウザへのCSSやスクリプトの送信を500ms遅延させました。
- 3大ブラウザで20回テストを実施。
結果
まず、CSSファイルを500ms遅延させた状態。
Browser: Chrome 18 | IE 9 | Firefox 9
CSS: first last | first last | first last
=======================================================
Header Exec | | |
Average | 583ms 36ms | 559ms 42ms | 565ms 49ms
St Dev | 15ms 12ms | 9ms 7ms | 13ms 6ms
------------|--------------|--------------|------------
Body Exec | | |
Average | 584ms 521ms | 559ms 513ms | 565ms 519ms
St Dev | 15ms 9ms | 9ms 5ms | 13ms 7ms
次に、CSSの代わりにjQueryで500msずつ遅延させるように設定しました。
Browser: Chrome 18 | IE 9 | Firefox 9
CSS: first last | first last | first last
=======================================================
Header Exec | | |
Average | 597ms 556ms | 562ms 559ms | 564ms 564ms
St Dev | 14ms 12ms | 11ms 7ms | 8ms 8ms
------------|--------------|--------------|------------
Body Exec | | |
Average | 598ms 557ms | 563ms 560ms | 564ms 565ms
St Dev | 14ms 12ms | 10ms 7ms | 8ms 8ms
最後に 両方 jQueryとCSSで500msずつ遅延させる。
Browser: Chrome 18 | IE 9 | Firefox 9
CSS: first last | first last | first last
=======================================================
Header Exec | | |
Average | 620ms 560ms | 577ms 577ms | 571ms 567ms
St Dev | 16ms 11ms | 19ms 9ms | 9ms 10ms
------------|--------------|--------------|------------
Body Exec | | |
Average | 623ms 561ms | 578ms 580ms | 571ms 568ms
St Dev | 18ms 11ms | 19ms 9ms | 9ms 10ms
結論
まず、重要なこととして、私は、スクリプトを
<head>
の末尾ではなく)。
<body>
). スクリプトにリンクする理由については、さまざまな議論があります。
<head>
しかし、それはこの答えの範囲外です。 これは、厳密に
<script>
の前に置く必要があります。
<link>
の中で
<head>
.
最近のDESKTOPブラウザでは。
は、最初にCSSにリンクしているように見えます。
決して
はパフォーマンスを向上させます。 CSSをスクリプトの後に配置すると、CSSとスクリプトの両方が遅延した場合はわずかな利益しか得られませんが、CSSが遅延した場合は大きな利益が得られます。 (これは
last
の列が表示されます)。
CSSを最後にリンクしてもパフォーマンスが落ちないことを考えると、しかし できる は、特定の状況下で利益をもたらします。 外部スタイルシートにリンクする必要があります。 後 外部スクリプトにリンクしている場合 デスクトップ・ブラウザーでのみ 古いブラウザのパフォーマンスが気にならない場合。 モバイル事情はこちらをお読みください。
なぜ?
歴史的に、ブラウザが
<script>
タグが外部リソースを指している場合、ブラウザは
停止
HTMLを解析してスクリプトを取得し、それを実行した後、HTMLの解析を続行します。 これに対して、ブラウザが
<link>
を外部スタイルシートのために使用する場合、それは
続ける
は、CSS ファイルを取得する間に HTML を解析します (並行して)。
したがって、スタイルシートを最初に置くようにという広く言われるアドバイスがあります。スタイルシートが最初にダウンロードされ、最初にダウンロードされたスクリプトが並行してロードされる可能性があるからです。
しかし、最近のブラウザ(上記でテストしたすべてのブラウザを含む)は、このような問題を解決するために 投機的構文解析 ブラウザが HTML の先を読み、リソースのダウンロードを開始することです。 以前 スクリプトがダウンロードされ、実行されます。
投機的解析のない古いブラウザでは、スクリプトを先に置くと並行してダウンロードできないため、パフォーマンスに影響があります。
対応ブラウザ
投機的構文解析が初めて実装されたのは (2012年1月現在、このバージョン以上を使用している世界中のデスクトップ ブラウザの割合も一緒に)
- Chrome 1 (WebKit 525) (100%)
- IE 8 (75%)
- Firefox 3.5 (96%)
- サファリ 4 (99%)
- オペラ 11.60 (85%)
現在使用されているデスクトップ用ブラウザのうち、合計で約85%が投機的ロードをサポートしています。 CSSよりスクリプトを優先させると、15%のユーザーにパフォーマンス上のペナルティが発生します。 グローバルに あなたのサイトの利用者層に応じて、ご利用ください。 (この数は減少していることを忘れないでください。)
モバイルブラウザの場合、モバイルブラウザとOSが異種混在しているため、明確な数字を出すのは少し難しいです。 投機的レンダリングは WebKit 525(2008 年 3 月リリース)で実装され、価値のあるモバイル ブラウザはほぼすべて WebKit をベースにしているので、次のように結論づけることができます。 すべき をサポートしています。 によると quirksmode iOS 2.2/Android 1.0 は WebKit 525 を使用しています。 Windows Phoneがどうなっているのか、まったくわかりません。
しかし Android 4端末でテストを行ったところ、デスクトップの結果と似たような数値が表示されましたが、この端末を素晴らしい新機能である リモートデバッガ ネットワークタブでは、JavaScriptが完全に読み込まれるまで、ブラウザが実際にCSSのダウンロードを待っていることがわかりました。 Android 用の WebKit の最新バージョンでも、投機的解析はサポートされていないようです。 モバイル機器特有のCPU、メモリ、ネットワークの制約により、オフになっているのではと思います。
コード
これはQ&Dである。
app.js
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
<!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
<!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
var jsload = Date.now();
$(function() {
$.post('/result' + location.pathname.replace('.html','') + '/' + (jsload - start) + '/' + (bodyexec - start));
});
jquery.jsは jquery-1.7.1.min.js
関連
-
Vueのフォームイベントのデータバインディングの説明
-
[解決済み】Node.js getaddrinfo ENOTFOUND
-
OSSアップロードエラーを解決する: net::ERR_SSL_PROTOCOL_ERROR
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] CSSの親セレクタはありますか?
-
[解決済み】JavaScriptの比較では、どちらの等号演算子(== vs ===)を使うべきですか?
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
-
[解決済み】HTML5入力のプレースホルダの色をCSSで変更する。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Vueの「データを聴く」原則を解説
-
[解決済み】gulp anythingを実行するたびに、アサーションエラーが発生します。- タスク関数を指定する必要があります
-
[解決済み】React - TypeError: 未定義のプロパティ 'props' を読み取ることができない。
-
[解決済み】 `string.split is not a function` というエラーの原因は何ですか?
-
[解決済み】React-Redux: アクションはプレーンオブジェクトでなければならない。非同期アクションにはカスタムミドルウェアを使用する
-
[解決済み】 env: node: macにそのようなファイルやディレクトリはありません
-
[解決済み】 Uncaught TypeError : undefined のプロパティ 'replace' を読み取れない In Grid
-
[解決済み】リクエストに失敗していないのに、「TypeError: failed to fetch」が表示される。
-
jq は html ページとデータを動的に分割する。
-
[解決済み】<script async="async" />をサポートしているブラウザはどれですか?