873 votes

Est la recommandation d'inclure le CSS avant de JavaScript est-il invalide?

Dans d'innombrables endroits en ligne j'ai vu la recommandation d'inclure le CSS avant de JavaScript. Le raisonnement est généralement, de cette forme:

Quand il s'agit de la commande de votre CSS et JavaScript, vous voulez que votre CSS venir en premier. La raison en est que le thread de rendu a tous les les informations de style, il doit le rendu de la page. Si le JavaScript inclut vient en premier, le moteur JavaScript doit analyser tout cela avant continuer sur le prochain jeu de ressources. Cela signifie que le rendu thread ne peut pas complètement afficher la page, car il n'a pas toutes les styles dont il a besoin.

Mon test révèle quelque chose de tout à fait différent:

Mon atelier de test

J'utilise la suite script Ruby afin de générer certains retards pour diverses ressources:

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..."
}

Au-dessus de la mini serveur me permet de fixer arbitrairement les retards pour les fichiers JavaScript (serveur et client) et de l'arbitraire CSS retards. Par exemple, http://10.0.0.50:8081/test.css?delay=500 me donne 500 ms de retard transfert de la CSS.

J'utilise la page suivante pour tester.

<!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>

Quand je inclure le CSS d'abord, la page prend 1,5 secondes pour le rendu:

CSS first

Quand je inclure le JavaScript tout d'abord, la page prend 1,4 secondes pour le rendu:

JavaScript first

J'obtiens des résultats similaires dans Chrome, Firefox et Internet Explorer. À l'Opéra, toutefois, la commande ne peut tout simplement pas d'importance.

Ce qui semble se passer, c'est que l'interpréteur JavaScript refuse de démarrer jusqu'à ce que tout le CSS est téléchargé. Donc, il semble que le fait d'avoir JavaScript comprenant le premier est plus efficace que le JavaScript fil devient de plus en plus de l'exécution.

Ai-je raté quelque chose, est la recommandation de placer CSS comprend avant JavaScript comprend pas correct?

Il est clair que nous pourrions ajouter async ou utiliser setTimeout pour libérer le thread de rendu ou mettre le code JavaScript dans le pied de page, ou utiliser un JavaScript chargeur. Le point ici est sur l'ordre de l'essentiel JavaScript bits et CSS bits dans la tête.

694voto

josh3736 Points 41911

C'est une question très intéressante. J'ai toujours mis mon CSS <link href="...">s avant mon JS <script src="...">s parce que "j'ai lu une fois que c'est mieux." Donc, vous avez raison; il est grand temps de nous faire un peu de recherche!

J'ai monté mon propre atelier de test dans le Nœud (code ci-dessous). En Gros, J'Ai:

  • Fait sûr qu'il n'y a pas de mise en cache HTTP pour le navigateur aurait à faire un téléchargement complet à chaque fois qu'une page est chargée.
  • Pour simuler la réalité, j'ai inclus jQuery et le H5BP CSS (donc il y a une quantité décente de script/CSS à analyser)
  • Mis en place deux pages avec CSS avant de script, l'un avec CSS script après.
  • Enregistré combien de temps il a fallu pour que le script externe dans l' <head> d'exécuter
  • Enregistré combien de temps il a fallu pour que le script en ligne dans l' <body> à exécuter, qui est analogue DOMReady.
  • Envoi différé de CSS et/ou de script dans le navigateur par 500ms.
  • Exécuté le test de 20 fois dans les 3 principaux navigateurs.

Résultats

Tout d'abord, avec le fichier CSS retardée par 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

Ensuite, j'ai mis en jQuery pour retard de 500ms à la place de la CSS:

     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

Enfin, j'ai mis les deux jQuery et CSS de retard par 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

Conclusions

Tout d'abord, il est important de noter que je suis d'exploitation en vertu de l'hypothèse que vous avez des scripts situés dans l' <head> de votre document (par opposition à la fin de l' <body>). Il y a différents arguments de la raison pour laquelle vous pouvez accéder à vos scripts dans l' <head> par rapport à la fin du document, mais qui est en dehors de la portée de cette réponse. C'est strictement si <script>s doit aller de l'avant <link>s en <head>.

Dans les navigateurs de BUREAU moderne, il ressemble à la liaison aux feuilles de style CSS première jamais offre un gain de performance. Mettre CSS script après vous obtient une somme insignifiante de gain lorsque les deux CSS et javascript sont en retard, mais vous donne des gains importants lors de la CSS est retardée. (Illustré par l' last colonnes dans la première série de résultats.)

Étant donné que la liaison aux feuilles de style CSS dernier ne semble pas nuire à la performance, mais peut fournir des gains dans certaines circonstances, vous devriez avoir un lien avec des feuilles de style externes après vous lien de scripts externes uniquement sur les navigateurs de bureau, si la performance de vieux navigateurs n'est pas un sujet de préoccupation. Lire la suite pour les mobiles de la situation.

Pourquoi?

Historiquement, quand un navigateur rencontré un <script> balise pointant vers une ressource externe, le navigateur arrêter de parser le HTML, récupérer le script, exécutez-le, puis continuer de parser le HTML. En revanche, si le navigateur a rencontré un <link> pour une feuille de style externe, il serait continuer à parser le HTML alors qu'il a cherché le fichier CSS (en parallèle).

Par conséquent, l'opinion, largement répété des conseils pour mettre les feuilles de style de la première, ils seraient télécharger en premier, et le premier script de téléchargement peuvent être chargés en parallèle.

Cependant, les navigateurs modernes (y compris tous les navigateurs que j'ai testé avec ci-dessus) ont mis en œuvre l'analyse spéculative, où le navigateur "regarde vers l'avenir" dans le HTML et commence le téléchargement de ressources, avant de scripts télécharger et exécuter.

Dans les anciens navigateurs sans spéculative de l'analyse, de mettre des scripts première affectera les performances, car ils ne télécharge pas en parallèle.

Prise En Charge Du Navigateur

Spéculative d'analyse a été mise en oeuvre: (avec le pourcentage de monde navigateur de bureau des utilisateurs à l'aide de cette version ou plus à compter de janvier 2012)

  • Chrome 1 (WebKit 525) (100%)
  • IE 8 (75%)
  • Firefox 3.5 (96%)
  • Safari 4 (99%)
  • Opera 11.60 (85%)

Au total, environ 85% des navigateurs de bureau en usage aujourd'hui, le soutien spéculative de chargement. Mettre les scripts avant de CSS aura une performance pénalité de 15% des utilisateurs à l'échelle mondiale; YMMV basée sur votre site public spécifique. (Et n'oubliez pas que le nombre est en diminution.)

Sur les navigateurs mobiles, c'est un peu plus difficile à obtenir nombre définitif simplement en raison de la façon hétérogène, le navigateur mobile et OS paysage. Depuis spéculative rendu a été mis en œuvre dans WebKit 525 (sorti en mars 2008), et à peu près tous la peine navigateur mobile est basé sur WebKit, nous pouvons conclure que "la plupart" des navigateurs mobiles devraient la soutenir. Selon quirksmode, iOS 2.2/Android 1.0 utiliser WebKit 525. Je n'ai aucune idée de ce que Windows Phone ressemble.

Cependant, j'ai couru le test sur mon Android 4 appareil, et alors que j'ai vu des chiffres similaires pour le bureau des résultats, j'ai accroché jusqu'à la nouvelle fantastique débogueur distant dans Chrome pour Android, et dans l'onglet Réseau a montré que le navigateur a été réellement attendre de télécharger le fichier CSS jusqu'à ce que le Javascript complètement chargée – en d'autres termes, même la plus récente version de WebKit pour Android ne semble pas soutenir spéculative de l'analyse. Je soupçonne que c'est peut-être désactivée en raison de la CPU, de la mémoire et/ou du réseau, les contraintes inhérentes aux appareils mobiles.

Code

Pardonnez la médiocrité – c'était de la 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 a jquery-1.7.1.min.js

299voto

Steve Souders Points 1367

Il ya deux raisons principales à mettre les CSS avant de JavaScript.

  1. Les anciens navigateurs (Internet Explorer 6 Et 7, Firefox 2, etc.) pourrait bloquer tous les téléchargements quand ils ont commencé le téléchargement d'un script. Donc, si vous avez a.js suivie par b.css ils téléchargés de manière séquentielle: d'abord a, puis b. Si vous avez b.css suivie par a.js ils téléchargés en parallèle pour que la page se charge plus rapidement.

  2. Rien n'est rendu jusqu'à ce que toutes les feuilles de style sont téléchargés - cela est vrai dans tous les navigateurs. Les Scripts sont - ils bloquer le rendu de tous les éléments du DOM qui sont au-dessous de la balise script dans la page. Si vous mettez vos scripts dans la TÊTE, alors cela signifie que la page est bloquée, le rendu jusqu'à ce que toutes les feuilles de style et tous les scripts sont téléchargés. Alors qu'il fait sens pour bloquer tous de rendu pour les feuilles de style (de sorte que vous obtenez le bon style la première fois et d'éviter le flash de non stylé contenu FOUC), il n'est pas judicieux de bloquer le rendu de l'ensemble de la page pour les scripts. Souvent, les scripts n'affecte pas les éléments du DOM ou seulement une partie des éléments du DOM. Il est préférable de charger les scripts en bas de la page si possible, ou encore mieux, de les charger de manière asynchrone.

C'est amusant de créer des exemples avec Cuzillion. Par exemple, cette page a un script dans l'en-TÊTE de sorte que la totalité de la page est vide jusqu'à ce que le téléchargement terminé. Cependant, si nous déplaçons le script à la fin du bloc CORPS l'en-tête de page rend depuis ces éléments DOM se produire au-dessus de la balise de SCRIPT, comme vous pouvez le voir sur cette page.

41voto

defau1t Points 7014

Je ne voudrais pas trop insister beaucoup sur les résultats que vous avez obtenu, je crois que c'est subjectif, mais j'ai une raison de vous expliquer qu'il est préférable de le mettre dans le CSS avant de js.

Pendant le chargement de votre site web, il y a deux scénarios que vous pouvez voir:

CAS 1: écran blanc > non stylé site > style de site web > interaction > style de site web interactif

CAS 2: écran blanc > non stylé site > interaction > style de site web > style de site web interactif


Honnêtement, je ne peux pas imaginer ceux qui choisissent le Cas 2. Cela signifie que les visiteurs utilisant des connexions internet lentes seront confrontées à une non stylé site internet, qui leur permet d'interagir avec elle à l'aide de Javascript (puisque c'est déjà chargé). En outre, la quantité de temps passé à regarder un non stylé site web serait agrandie de cette façon. Pourquoi quelqu'un voudrait-il?

Il fonctionne mieux que jQuery unis

"Lors de l'utilisation de scripts qui s'appuient sur la valeur des propriétés de style CSS, il est important de référence des feuilles de style externes ou intégrer style les éléments avant de référencer les scripts".

Lors du chargement des fichiers dans le mauvais ordre (d'abord JS, puis CSS), tout code Javascript s'appuyant sur les propriétés définies dans les fichiers CSS (par exemple la largeur ou la hauteur d'un div) ne sera pas chargé correctement. Il semble qu'avec le mauvais ordre de chargement, les propriétés correctes sont "parfois" Javascript (c'est peut-être causée par une condition de concurrence?). Cet effet semble plus grand ou plus petit selon le navigateur utilisé.

25voto

dhira Points 530

Ont été vos tests effectués sur votre ordinateur personnel ou sur un serveur web? C'est une page vierge, ou est-ce un complexe système en ligne avec des images, bases de données, etc.? Sont vos scripts en effectuant une simple hover action d'événement, ou sont-ils une composante de base de la façon dont votre site s'affiche et interagit avec l'utilisateur? Il y a plusieurs choses à prendre en considération ici, et la pertinence de ces recommandations deviennent presque toujours les règles lorsque vous vous aventurez dans la haute-calibre de développement web.

Le but de "mettre les feuilles de style en haut et les scripts en bas" la règle est que, en général, c'est le meilleur moyen pour optimiser le rendu progressive, ce qui est essentiel à l'expérience de l'utilisateur.

Tout le reste de côté: en supposant que le test est valide, et vous êtes vraiment à produire des résultats contraires à la populaire règles, il faudrait venir en tant qu'aucune surprise, vraiment. Chaque site web (et tout ce qu'il faut pour rendre la chose apparaît sur l'écran) est différent et que l'Internet est en constante évolution.

21voto

hugomg Points 29789

- Je inclure des fichiers CSS avant de Javascript pour une raison différente.

Si mon Javascript doit faire redimensionnement dynamique de certains élément de la page (pour les cas particuliers où le CSS est vraiment une main dans le dos), puis de charger le CSS après le JS est russing peut conduire à des conditions de course, où l'élément est redimensionnée avant de styles CSS sont appliquées et donc un peu bizarre lors de l'styles enfin coup de pied dans. Si je charge le CSS à l'avance, je peux vous garantir que les choses se passent dans l'ordre prévu et que la mise en page finale est ce que je veux être.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: