Le CSS doit-il toujours précéder Javascript?

897

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

Quand il s'agit de commander votre CSS et JavaScript, vous voulez que votre CSS vienne en premier. La raison en est que le thread de rendu possède toutes les informations de style dont il a besoin pour rendre la page. Si JavaScript inclut la priorité, le moteur JavaScript doit tout analyser avant de passer à l'ensemble de ressources suivant. Cela signifie que le fil de rendu ne peut pas afficher complètement la page, car il n'a pas tous les styles dont il a besoin.

Mes tests réels révèlent quelque chose de tout à fait différent:

Mon harnais de test

J'utilise le script Ruby suivant pour générer des retards spécifiques 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..."
}

Le mini-serveur ci-dessus me permet de définir des retards arbitraires pour les fichiers JavaScript (serveur et client) et des retards CSS arbitraires. Par exemple, http://10.0.0.50:8081/test.css?delay=500me donne un délai de 500 ms pour transférer le 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>

Lorsque j'inclus le CSS en premier, la page prend 1,5 seconde pour s'afficher:

CSS d'abord

Lorsque j'inclus le JavaScript en premier, la page prend 1,4 seconde pour s'afficher:

JavaScript d'abord

J'obtiens des résultats similaires dans Chrome, Firefox et Internet Explorer. Dans Opera cependant, la commande n'a tout simplement pas d'importance.

Ce qui semble se produire, c'est que l'interpréteur JavaScript refuse de démarrer tant que tout le CSS n'est pas téléchargé. Il semble donc qu'avoir JavaScript inclut d'abord est plus efficace car le thread JavaScript obtient plus de temps d'exécution.

Suis-je en train de manquer quelque chose, la recommandation de placer les inclusions CSS avant les inclusions JavaScript n'est-elle pas correcte?

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 chargeur JavaScript. Le point ici concerne la commande des bits JavaScript essentiels et des bits CSS dans la tête.

Sam Saffron
la source
120
1511 vs 1422 est-il une différence statistiquement significative? C'est 6%. Le seuil général de différence de performance humaine notable à moyenne est d'environ 20%.
Jeff Atwood
15
le fait est que la réorganisation élimine ce retard arbitraire, vous pouvez définir le retard à tout ce que vous voulez, c'est juste une démonstration du problème.
Sam Saffron
3
était votre retard de 100 ms? la différence dans vos captures d'écran est de 89 ms. Dans votre URL, c'est le cas delay=400&amp;jsdelay=1000et delay=500qui est loin de 100 ms ou 89 ms. Je suppose que je ne sais pas à quels chiffres vous faites référence.
Jeff Atwood
4
"Si le Javascript inclut la priorité, le moteur Javascript doit tout analyser avant de passer à l'ensemble de ressources suivant. Cela signifie que le thread de rendu ne peut pas afficher complètement la page, car il n'a pas tous les styles dont il a besoin . " - si l'inclusion JS est dans la tête, alors le JS sera exécuté avant le rendu de la page, que l'inclusion CSS soit antérieure ou postérieure.
nnnnnn
162
Je ne sais pas si vous y avez pensé, mais la perception du temps de chargement est également importante. Ainsi, par exemple, si le chargement du CSS vous donne d'abord juste la couleur / texture d'arrière-plan de la page, cela semble être plus rapide. Les temps de chargement absolus peuvent ne pas en être la preuve.
Rakesh Pai

Réponses:

712

C'est une question très intéressante. J'ai toujours mis mes CSS <link href="...">avant mes JS <script src="...">parce que "j'ai lu une fois que c'était mieux." Vous avez donc raison; il est grand temps de faire des recherches!

J'ai configuré mon propre faisceau de test dans Node (code ci-dessous). Fondamentalement, je:

  • Assurez-vous qu'il n'y avait pas de mise en cache HTTP afin que le navigateur doive effectuer un téléchargement complet chaque fois qu'une page est chargée.
  • Pour simuler la réalité, j'ai inclus jQuery et le CSS H5BP (donc il y a une quantité décente de script / CSS à analyser)
  • Configurez deux pages - une avec CSS avant script, une avec CSS après script.
  • Enregistré le temps nécessaire au script externe <head>pour s'exécuter
  • Enregistré combien de temps il a fallu au script en ligne <body>pour s'exécuter, ce qui est analogue à DOMReady.
  • Retard de l'envoi de CSS et / ou de script au navigateur de 500 ms.
  • A effectué le test 20 fois dans les 3 principaux navigateurs.

Résultats

Tout d'abord, avec le fichier CSS retardé de 500 ms:

     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 défini jQuery pour qu'il retarde de 500 ms au lieu du 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, je mets à la fois jQuery et le CSS pour retarder 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 fonctionne en supposant que vous avez des scripts situés dans le <head>de votre document (par opposition à la fin du <body>). Il existe différents arguments concernant la raison pour laquelle vous pouvez créer un lien vers vos scripts dans <head>la fin du document par rapport à la fin du document, mais cela sort du cadre de cette réponse. Il s'agit strictement de savoir si <script>s doit précéder <link>s dans le <head>.

Dans les navigateurs DESKTOP modernes, il semble que la liaison avec CSS n'offre d' abord aucun gain de performances. Mettre CSS après le script vous apporte un gain trivial lorsque le CSS et le script sont retardés, mais vous donne des gains importants lorsque le CSS est retardé. (Montré par les lastcolonnes du premier ensemble de résultats.)

Étant donné que la dernière liaison vers CSS ne semble pas nuire aux performances mais peut fournir des gains dans certaines circonstances, vous devez lier à des feuilles de style externes après avoir lié à des scripts externes uniquement sur les navigateurs de bureau si les performances des anciens navigateurs ne sont pas un problème. Lisez la suite pour la situation mobile.

Pourquoi?

Historiquement, lorsqu'un navigateur rencontrait une <script>balise pointant vers une ressource externe, le navigateur arrêtait d' analyser le HTML, récupérait le script, l'exécutait, puis continuait d'analyser le HTML. En revanche, si le navigateur rencontrait un <link>pour une feuille de style externe, il continuerait d' analyser le HTML pendant qu'il récupérait le fichier CSS (en parallèle).

Par conséquent, le conseil largement répété de mettre les feuilles de style en premier - elles seraient téléchargées en premier, et le premier script à télécharger pourrait être chargé en parallèle.

Cependant, les navigateurs modernes (y compris tous les navigateurs que j'ai testés ci-dessus) ont implémenté une analyse spéculative , où le navigateur "regarde vers l'avant" dans le HTML et commence à télécharger des ressources avant le téléchargement et l'exécution des scripts.

Dans les anciens navigateurs sans analyse spéculative, placer les scripts en premier affectera les performances car ils ne seront pas téléchargés en parallèle.

Prise en charge du navigateur

L'analyse spéculative a été mise en œuvre pour la première fois en: (ainsi que le pourcentage d'utilisateurs de navigateur de bureau dans le monde utilisant cette version ou une version supérieure en janvier 2012)

  • Chrome 1 (WebKit 525) (100%)
  • IE 8 (75%)
  • Firefox 3.5 (96%)
  • Safari 4 (99%)
  • Opéra 11,60 (85%)

Au total, environ 85% des navigateurs de bureau utilisés aujourd'hui prennent en charge le chargement spéculatif. Mettre les scripts avant CSS aura une pénalité de performance sur 15% des utilisateurs dans le monde ; YMMV en fonction de l'audience spécifique de votre site. (Et rappelez-vous que ce nombre diminue.)

Sur les navigateurs mobiles, il est un peu plus difficile d'obtenir des chiffres définitifs simplement en raison de l'hétérogénéité du paysage du navigateur mobile et du système d'exploitation. Étant donné que le rendu spéculatif a été implémenté dans WebKit 525 (publié en mars 2008) et que presque tous les navigateurs mobiles intéressants sont basés sur WebKit, nous pouvons conclure que "la plupart" des navigateurs mobiles devraient le prendre en charge. Selon quirksmode , iOS 2.2 / Android 1.0 utilise WebKit 525. Je n'ai aucune idée de l'apparence de Windows Phone.

Cependant, j'ai exécuté le test sur mon appareil Android 4, et même si j'ai vu des chiffres similaires aux résultats du bureau, je l'ai connecté au fantastique nouveau débogueur à distance dans Chrome pour Android, et l'onglet Réseau a montré que le navigateur attendait en fait de télécharger le CSS jusqu'à ce que les JavaScripts soient complètement chargés - en d'autres termes, même la dernière version de WebKit pour Android ne semble pas prendre en charge l'analyse spéculative. Je soupçonne qu'il pourrait être désactivé en raison des contraintes de processeur, de mémoire et / ou de réseau inhérentes aux appareils mobiles.

Code

Pardonnez la négligence - c'était 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 était jquery-1.7.1.min.js

josh3736
la source
137
c'est une réponse fantastique, merci d' utiliser la science! D'après votre résultat "dans les navigateurs modernes, il semble que la liaison avec CSS d'abord ne procure jamais un gain de performances" , je pense que la réponse à la question est oui , l'ancien conseil de CSS d'abord est clairement invalide.
Jeff Atwood
Concernant la mise à jour de @ josh3736 sur l'inverse sur mobile ... c'est un exemple à ne pas sauter le pas sur ce changement significatif. Je serais curieux de savoir comment les autres navigateurs mobiles se comportent (webkit, gecko, presto, trident, etc.) car les performances sur mobile sont souvent plus importantes.
scunliffe
1
Vous devriez également essayer d'ajouter une certaine lenteur à l'impression des css / js, pour simuler les vitesses d'un serveur lent.
kirb
1
"Tout d'abord, il est important de noter que je fonctionne en supposant que vous avez des scripts situés dans le <head>de votre document (par opposition à la fin du <body>)." Je soulignerais cela beaucoup plus tôt dans la réponse, comme en haut. Inclure un scriptin headqui fait référence à un fichier externe n'est presque jamais correct, de presque n'importe quel point de vue (certainement pas celui des performances). Je ne me souviens pas avoir dû le faire dans la vraie vie. La ligne impaire ou deux du script en ligne peut-être, mais c'est tout. Le défaut, sans très bonnes raisons contraires, devrait être la fin du corps.
TJ Crowder du
1
Voté, jQuery n'est pas JavaScript et ne fait que gonfler la page, donc les résultats de son utilisation ne sont pas objectifs.
John
303

Il y a deux raisons principales de mettre CSS avant JavaScript.

  1. Les anciens navigateurs (Internet Explorer 6-7, Firefox 2, etc.) bloqueraient tous les téléchargements ultérieurs lorsqu'ils ont commencé à télécharger un script. Donc, si vous les avez a.jssuivis, b.cssils sont téléchargés séquentiellement: d'abord a puis b. Si vous les avez b.csssuivis, a.jsils sont téléchargés en parallèle afin que la page se charge plus rapidement.

  2. Rien n'est rendu tant que toutes les feuilles de style ne sont pas téléchargées - cela est vrai dans tous les navigateurs. Les scripts sont différents - ils bloquent le rendu de tous les éléments DOM qui se trouvent sous la balise de script dans la page. Si vous placez vos scripts dans HEAD, cela signifie que la page entière est bloquée du rendu jusqu'à ce que toutes les feuilles de style et tous les scripts soient téléchargés. Bien qu'il soit logique de bloquer tout le rendu des feuilles de style (vous obtenez donc le style correct la première fois et évitez le flash de contenu non stylisé FOUC), il n'a pas de sens de bloquer le rendu de la page entière pour les scripts. Souvent, les scripts n'affectent aucun élément DOM ou seulement une partie des éléments DOM. Il est préférable de charger les scripts aussi bas que possible dans la page, 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 la TÊTE, de sorte que la page entière est vierge jusqu'à ce qu'elle soit terminée. Cependant, si nous déplaçons le script à la fin du bloc BODY, l'en-tête de page s'affiche car ces éléments DOM se trouvent au-dessus de la balise SCRIPT, comme vous pouvez le voir sur cette page .

Steve Souders
la source
10
Honoré Steve m'a battu à la réponse, mais je vais ajouter un article pertinent à ce qu'il mentionne: stevesouders.com/blog/2009/04/27/…
Juan Pablo Buritica
4
voir quels navigateurs prennent en charge l' asyncattribut, que Steve recommande ici quand il dit "encore mieux de les charger de manière asynchrone" - stackoverflow.com/questions/1834077/…
Jeff Atwood
Hey, pouvez-vous me dire pourquoi quelqu'un lierait des fichiers CSS à des @importdirectives?
Josh Stodola
6
Quelle est la source de 2), et si c'est vrai, pouvez-vous alors expliquer pourquoi une page finit parfois de charger le contenu, puis le CSS est appliqué une seconde ou deux plus tard? (Cela s'est produit, rarement, sur mes propres pages où le CSS était dans les balises <head>)
Izkata
2
Nous devrions donc mettre jQuery+ jQuery UI+ $(document).ready(function () { });à la fin de la page? Est-ce que cela va fonctionnera- toujours comme prévu?
Olivier Pons
42

Je n'insisterais pas trop sur les résultats que vous avez obtenus, je pense que c'est subjectif, mais j'ai une raison de vous expliquer qu'il vaut mieux mettre en CSS avant js.

Lors du chargement de votre site Web, deux scénarios se présentent:

CASE 1: écran blanc> site sans style> site style> interaction> style et site web interactif

CASE 2: écran blanc> site sans style> interaction> site style> site style et interactif


Honnêtement , je ne peux pas imaginer que quelqu'un de choisir le cas 2. Cela signifierait que les visiteurs utilisant des connexions Internet lentes seront confrontés à un site Web dépourvu de style, qui leur permettra d'interagir avec Javascript (car il est déjà chargé). En outre, le temps passé à consulter un site Web dépourvu de style serait ainsi maximisé. Pourquoi quelqu'un voudrait-il cela?

Cela fonctionne également mieux comme le dit jQuery

"Lorsque vous utilisez des scripts qui reposent sur la valeur des propriétés de style CSS, il est important de référencer des feuilles de style externes ou d'incorporer des éléments de style avant de référencer les scripts".

Lorsque les fichiers sont chargés dans le mauvais ordre (d'abord JS, puis CSS), tout code Javascript reposant 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 soient «parfois» connues de Javascript (peut-être est-ce dû à une condition de concurrence?). Cet effet semble plus ou moins important selon le navigateur utilisé.

defau1t
la source
2
Comment feriez-vous pour garantir que tous les css ont été chargés avant l'exécution du javascript? Peut tu? ou si votre javascript est suffisamment robuste pour faire face à la situation où les styles ne sont pas nécessairement chargés.
Jonnio
@Jonnio Si votre JS a une dépendance, vous devez rendre cette dépendance explicite. Sinon, vous aurez toujours de rares problèmes de synchronisation. Les modules ES6 sont un bon moyen d'y parvenir, mais il existe de nombreuses bibliothèques qui pourraient également être utilisées.
kmkemp
26

Vos tests ont-ils été effectués sur votre ordinateur personnel ou sur un serveur Web? Est-ce une page blanche, ou est-ce un système en ligne complexe avec des images, des bases de données, etc.? Vos scripts effectuent-ils une simple action d'événement de survol, ou constituent-ils un composant essentiel de la façon dont votre site Web affiche et interagit avec l'utilisateur? Il y a plusieurs choses à considérer ici, et la pertinence de ces recommandations devient presque toujours des règles lorsque vous vous aventurez dans un développement Web de haut calibre.

Le but de la règle "mettre les feuilles de style en haut et les scripts en bas" est qu'en général, c'est le meilleur moyen d'obtenir un rendu progressif optimal , ce qui est essentiel pour l'expérience utilisateur.

Tout le reste à part: en supposant que votre test est valide et que vous produisez vraiment des résultats contraires aux règles populaires, cela ne serait vraiment pas surprenant. Chaque site Web (et tout ce qu'il faut pour que tout apparaisse sur l'écran d'un utilisateur) est différent et Internet évolue constamment.

dimanche
la source
1
J'apprécie le point que vous soulevez en gras, mais l'OP parle de ce qui se passe lorsque vous modifiez l'ordre avec les deux en haut, ni en bas.
nnnnnn
1
Ainsi, "en supposant que [son] test est valide".
skippr
21

J'inclus des fichiers CSS avant Javascript pour une raison différente.

Si mon Javascript doit effectuer un dimensionnement dynamique d'un élément de page (pour les cas d'angle où CSS est vraiment un élément principal à l'arrière), le chargement du CSS après que le JS est en panne peut entraîner des conditions de concurrence, où l'élément est redimensionné avant les styles CSS sont appliqués et semblent donc bizarres lorsque les styles entrent enfin en jeu. Si je charge le CSS au préalable, je peux garantir que les choses fonctionnent dans l'ordre prévu et que la mise en page finale est ce que je veux qu'elle soit.

hugomg
la source
2
cela cassera un jour sur un navigateur. Je ne devine pas.
jcolebrand
1
jcolebrand: Oui, je pense que je n'avais pas bu assez de café quand j'ai écrit ça. (Rétrospectivement, je suppose que les choses importantes sont juste d'éviter le chargement dynamique de CSS et de placer le JS dans un événement domReady si vous avez besoin de faire un dimensionnement dynamique)
hugomg
Les scripts ne doivent modifier aucun affichage. C'est le travail CSS. HTML = contenu, CSS = Comment afficher le contenu, javascript change le contenu dynamiquement. De plus, js ne doit agir qu'après (ou pendant) que DOMContentLoaded est déclenché avec des situations petites mais très spécifiques.
brunoais
@brunoais: Cependant, certaines dispositions ne peuvent être créées qu'avec Javascript. Par exemple, tout ce qui doit être redimensionné dynamiquement doit être créé via Javascript et certaines choses (comme avoir une taille de 100% à 20 pixels) nécessitent que Javascript soit effectué de manière portative dans les anciens navigateurs.
hugomg
@missingno Dans ces cas, utilisez simplement l'événement DOMContentLoaded. Mais je comprends ce que tu veux dire. (Stupide IE!)
brunoais
10

La recommandation d'inclure CSS avant JavaScript n'est-elle pas valide?

Pas si vous la traitez simplement comme une recommandation. Mais si vous la traitez comme une règle dure et rapide?, Oui, elle n'est pas valide.

Depuis https://developer.mozilla.org/en-US/docs/Web/Reference/Events/DOMContentLoaded

La feuille de style charge l' exécution du script de bloc, donc si vous avez un <script> après <link rel="stylesheet" ...>la page ne terminera pas l'analyse - et DOMContentLoaded ne se déclenchera pas - jusqu'à ce que la feuille de style soit chargée.

Il semble que vous devez savoir sur quoi s'appuie chaque script et vous assurer que l'exécution du script est retardée jusqu'à ce que l'événement de fin soit correct. Si le script ne repose que sur le DOM, il peut reprendre dans ondomready / domcontentloaded, s'il s'appuie sur des images à charger ou des feuilles de style à appliquer, alors si je lis correctement la référence ci-dessus, ce code doit être différé jusqu'à l'événement onload.

Je ne pense pas qu'une seule taille de chaussette convienne à tous, même si c'est la façon dont elles sont vendues et je sais qu'une seule taille de chaussure ne convient pas à tous. Je ne pense pas qu'il y ait une réponse définitive à laquelle charger en premier, les styles ou le script. Il s'agit plutôt d'une décision au cas par cas de ce qui doit être chargé dans quel ordre et de ce qui peut être différé jusqu'à plus tard comme n'étant pas sur le "chemin critique".

Pour parler à l'observateur qui a commenté qu'il vaut mieux retarder la capacité des utilisateurs à interagir jusqu'à ce que la feuille soit jolie. Vous êtes nombreux et vous agacez vos homologues qui ressentent le contraire. Ils sont venus sur un site pour atteindre un objectif et les retards dans leur capacité à interagir avec un site en attendant que des choses qui ne comptent pas terminer le chargement soient très frustrants. Je ne dis pas que vous vous trompez, mais seulement que vous devez savoir qu'il existe une autre faction qui ne partage pas votre priorité.

Cette question s'applique particulièrement à toutes les annonces placées sur des sites Web. Je serais ravi que les auteurs du site rendent juste des divs d'espace réservé pour le contenu de l'annonce et s'assurent que leur site était chargé et interactif avant d'injecter les annonces dans un événement de chargement. Même dans ce cas, j'aimerais voir les annonces chargées en série au lieu de toutes à la fois, car elles ont un impact sur ma capacité à faire défiler le contenu du site même pendant le chargement des annonces gonflées. Mais ce n'est que le point de vue d'une seule personne.

  • Connaissez vos utilisateurs et ce qu'ils apprécient.
  • Connaissez vos utilisateurs et l'environnement de navigation qu'ils utilisent.
  • Sachez ce que fait chaque fichier et quelles sont ses conditions préalables. Tout faire fonctionner aura la priorité sur la vitesse et la beauté.
  • Utilisez des outils qui vous montrent la chronologie du réseau lors du développement.
  • Testez dans chacun des environnements que vos utilisateurs utilisent. Il peut être nécessaire de modifier dynamiquement (côté serveur, lors de la création de la page) l'ordre de chargement en fonction de l'environnement des utilisateurs.
  • En cas de doute, modifiez l'ordre et mesurez à nouveau.
  • Il est possible que le mélange des styles et des scripts dans l'ordre de chargement soit optimal; pas tous l'un puis tous les autres.
  • Expérimentez non seulement dans quel ordre charger les fichiers, mais où. Tête? Dans le corps? Après le corps? DOM prêt / chargé? Chargé?
  • Envisagez les options asynchrones et différées, le cas échéant, pour réduire le délai net que subira l'utilisateur avant de pouvoir interagir avec la page. Testez pour déterminer s'ils aident ou font mal.
  • Il y aura toujours des compromis à considérer lors de l'évaluation de l'ordre de chargement optimal. Pretty vs. Responsive en étant un.
Ted Cohen
la source
1
L'article lié ne prétend plus «La feuille de style charge l'exécution du script de bloc». N'est-ce plus vrai?
Greg
@Greg - C'est toujours vrai. Les scripts doivent pouvoir interroger les attributs DOM .style, afin que les feuilles de style bloquent toujours l'exécution des scripts. Ils peuvent ne pas bloquer le chargement du script , s'ils sont intelligents, mais ils bloqueront les événements script.onLoad.
Jimmy Breck-McKye
10

Mise à jour 2017-12-16

Je n'étais pas sûr des tests en OP. J'ai décidé d'expérimenter un peu et j'ai fini par briser certains des mythes.

Synchronous <script src...>bloquera le téléchargement des ressources en dessous jusqu'à ce qu'il soit téléchargé et exécuté

Ce n'est plus vrai . Jetez un œil à la cascade générée par Chrome 63:

<head>
<script src="//alias-0.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=1"></script>
<script src="//alias-1.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=2"></script>
<script src="//alias-2.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=3"></script>
</head>

Inspecteur de filet chromé -> cascade

<link rel=stylesheet> ne bloquera pas le téléchargement et l'exécution des scripts en dessous

C'est incorrect . La feuille de style ne bloque pas le téléchargement , mais il va bloquer l' exécution du script ( peu d' explications ici ). Jetez un œil au tableau des performances généré par Chrome 63:

<link href="//alias-0.redacted.com/payload.php?type=css&amp;delay=666" rel="stylesheet">
<script src="//alias-1.redacted.com/payload.php?type=js&amp;delay=333&amp;block=1000"></script>

Outils de développement Chrome -> performances


Compte tenu de ce qui précède, les résultats de l'OP peuvent être expliqués comme suit:

CSS First:

CSS Download  500ms:<------------------------------------------------>
JS Download   400ms:<-------------------------------------->
JS Execution 1000ms:                                                  <-------------------------------------------------------------------------------------------------->
DOM Ready   @1500ms:                                                                                                                                                      

JS First:

JS Download   400ms:<-------------------------------------->
CSS Download  500ms:<------------------------------------------------>
JS Execution 1000ms:                                        <-------------------------------------------------------------------------------------------------->
DOM Ready   @1400ms:                                                                                                                                            
Salman A
la source
C'est aussi pourquoi document.write () est l'une des pires idées jamais faites pour HTMLDOM.
brunoais
1
The reason is that the script may want to get coordinates and other style-dependent properties of elements, like in the example above. Naturally, it has to wait for styles to load. javascript.info/… Pourquoi la même hypothèse ne s'applique-t-elle pas en cas de JS d'abord? Cela n'a pas beaucoup de sens pour moi, l'ordre de JS exécuté ne dit rien de son objectif.
Thorsten Schöning
4

Je ne sais pas exactement comment le temps de rendu de vos tests est identique à celui de votre script Java. Considérez cependant ceci

Une page de votre site fait 50k, ce qui n'est pas déraisonnable. L'utilisateur est sur la côte est tandis que votre serveur est à l'ouest. MTU n'est certainement pas à 10 km, il y aura donc quelques allers-retours. Cela peut prendre une demi-seconde pour recevoir votre page et vos feuilles de style. Typiquement (pour moi) javascript (via le plugin jquery et autres) est bien plus que CSS. Il y a aussi ce qui se passe lorsque votre connexion Internet s'étouffe à mi-chemin sur la page mais laisse ignorer cela (cela m'arrive de temps en temps et je crois que le CSS s'affiche mais je ne suis pas sûr à 100%).

Puisque css est en tête, il peut y avoir des connexions supplémentaires pour l'obtenir, ce qui signifie qu'il peut potentiellement se terminer avant la page. Quoi qu'il en soit pendant le type, le reste de la page prend et les fichiers javascript (qui sont beaucoup plus d'octets) la page n'est pas stylée, ce qui rend le site / connexion lent.

MÊME SI l'interpréteur JS refuse de démarrer jusqu'à ce que le CSS soit terminé, le temps nécessaire pour télécharger le code javascript, surtout lorsque le serveur est loin du temps CSS, ce qui rendra le site pas joli.

C'est une petite optimisation mais c'est la raison.


la source
1
le serveur est sur la côte est, fwiw. Vous ignorez également apparemment qu’ils utilisent désormais un CDN.
jcolebrand
3

Voici un RÉSUMÉ de toutes les principales réponses ci-dessus (ou peut-être ci-dessous plus tard :)

Pour les navigateurs modernes, placez css où vous le souhaitez. Ils analyseraient votre fichier html (qu'ils appellent l' analyse spéculative ) et commenceraient à télécharger css en parallèle avec l'analyse html.

Pour les anciens navigateurs, continuez à mettre css en haut (si vous ne voulez pas afficher d'abord une page nue mais interactive).

Pour tous les navigateurs, placez javascript le plus bas possible sur la page, car cela arrêtera l'analyse de votre html. De préférence, téléchargez-le de manière asynchrone (par exemple, appel ajax)

Il existe également des résultats expérimentaux pour un cas particulier qui prétend mettre le javascript en premier (par opposition à la sagesse traditionnelle de mettre le CSS en premier) donne de meilleures performances mais aucun raisonnement logique n'est donné pour cela, et manque de validation concernant l'applicabilité généralisée, vous pouvez donc ignorez-le pour l'instant.

Donc, pour répondre à la question: oui. La recommandation d'inclure le CSS avant JS n'est pas valide pour les navigateurs modernes. Mettez CSS où vous voulez et mettez JS vers la fin, autant que possible.

mehmet
la source
1

Steve Souders a déjà donné une réponse définitive mais ...

Je me demande s'il y a un problème avec le test original de Sam et la répétition de Josh.

Les deux tests semblent avoir été effectués sur des connexions à faible latence où la configuration de la connexion TCP aura un coût trivial.

Comment cela affecte le résultat du test, je ne suis pas sûr et je voudrais regarder les cascades pour les tests sur une connexion à latence `` normale '' mais ...

Le premier fichier téléchargé devrait obtenir la connexion utilisée pour la page html, et le deuxième fichier téléchargé obtiendra la nouvelle connexion. (Le rinçage des premiers modifie cette dynamique, mais cela ne se fait pas ici)

Dans les navigateurs plus récents, la deuxième connexion TCP est ouverte de manière spéculative, de sorte que la surcharge de connexion est réduite / disparaît, dans les navigateurs plus anciens, cela n'est pas vrai et la deuxième connexion aura la surcharge d'être ouverte.

Comment / si cela affecte le résultat des tests, je ne suis pas sûr.

Andy Davies
la source
ne suit pas, sauf si vous avez un pipeline qui est incroyablement rare, il est très peu probable que la configuration de la connexion soit réduite ... d'accord, le test doit être répété sur une faible latence
Sam Saffron
Si vous regardez cette cascade, vous pouvez voir où Chrome ouvre spéculativement une deuxième connexion avant qu'elle ne soit nécessaire webpagetest.org/result/… (IE9 fait de même) ... Je pensais à une latence normale à des fins TCP plutôt qu'à faible - quel genre de l'environnement le test a-t-il été effectué?
Andy Davies
2
Re: "Steve Souders a déjà donné une réponse définitive mais ..." Le truc avec l'évolution du web c'est qu'il n'y a pas de réponse définitive. :) Il y a 3-4 façons de charger des scripts et les choses changent. La vraie sémantique correcte aurait dû être pour Steve de dire "Mettez CSS avant JavaScript synchrone" Sinon, les gens se trompent en généralisant comme étant une règle pour tous les scripts ...
hexalys
Oui, mais la plupart des gens incluent simplement des scripts de manière synchrone, donc les conseils de Steve sont bons pour les non-initiés.
Andy Davies
1

Je pense que ce ne sera pas vrai pour tous les cas. Parce que css téléchargera parallèlement mais js ne peux pas. Considérez pour le même cas,

Au lieu d'avoir un seul CSS, prenez 2 ou 3 fichiers CSS et essayez-les de cette façon,

1) css..css..js 2) css..js..css 3) js..css..css

Je suis sûr que css..css..js donnera un meilleur résultat que tous les autres.

harishkumar329
la source
0

Nous devons garder à l'esprit que les nouveaux navigateurs ont travaillé sur leurs moteurs Javascript, leurs analyseurs, etc., en optimisant les problèmes de code et de balisage courants de manière à ce que les problèmes rencontrés dans les anciens navigateurs tels que <= IE8 ne soient plus pertinents, pas seulement avec en ce qui concerne le balisage mais aussi l'utilisation de variables JavaScript, de sélecteurs d'éléments, etc. Je peux voir dans un avenir pas si lointain une situation où la technologie a atteint un point où les performances ne sont plus vraiment un problème.

George Katsanos
la source
La performance est toujours un problème. J'ignore presque que les navigateurs qui ne suivent pas les spécifications existent. Je prépare simplement mon code de telle sorte que ceux qui suivent les spécifications fonctionnent à pleine vitesse et les autres que je fais juste pour que cela fonctionne. Ainsi, par exemple, si cela fonctionne dans IE8, tout va bien.
brunoais
-5

Personnellement, je ne mettrais pas trop l'accent sur une telle «sagesse populaire». Ce qui a pu être vrai dans le passé pourrait bien ne pas être vrai maintenant. Je suppose que toutes les opérations relatives à l'interprétation et au rendu d'une page Web sont entièrement asynchrones ("récupérer" quelque chose et "agir dessus" sont deux choses entièrement différentes qui pourraient être gérées par différents threads, etc. ), et en tout cas, entièrement hors de votre contrôle ou de votre préoccupation.

Je mettrais des références CSS dans la partie "tête" du document, ainsi que toute référence à des scripts externes. (Certains scripts peuvent exiger d'être placés dans le corps, et si c'est le cas, les obliger.)

Au-delà de cela ... si vous observez que "cela semble être plus rapide / plus lent que cela, sur ce / ce navigateur", traitez cette observation comme une curiosité intéressante mais non pertinente et ne la laissez pas influencer vos décisions de conception. Trop de choses changent trop vite. (Quelqu'un veut-il parier sur combien de minutes il faudra avant que l'équipe Firefox ne présente une autre version intermédiaire de son produit? Ouais, moi non plus.)

user106701
la source