根据Google的建议优化CSS加载速度

8

我在使用谷歌的PageSpeed Insights测试我的网站时发现,它告诉我可以通过延迟加载非关键资源来提高CSS传递速度。具体地说,它提到了Font Awesome的引入:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">

我想将它的加载延迟,只需将其放在闭合body标签之前的脚本之前,如下所示:

  ...
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
  <script src="js/min/scripts.min.js"></script>
</body>
</html>

然而!当查看谷歌有关交付速度的文档时,我发现了两种不同的解决方案。

在我的母语荷兰语中(您可以在右下角更改文档的语言),文档指出我应该将非必要的CSS放置在HTML结束标签之后。这对我来说似乎非常奇怪。这样做是否会在尝试通过JS访问文件时使事情变得复杂?为什么不将其放在结束body标签之前?

  ...
  </body>
</html>
<link rel="stylesheet" href="small.css">

然而,在英文文档中,情况变得更加复杂,需要使用JavaScript:

    ...
    <script>
      var cb = function() {
        var l = document.createElement('link'); l.rel = 'stylesheet';
        l.href = 'small.css';
        var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h);
      };
      var raf = requestAnimationFrame || mozRequestAnimationFrame ||
          webkitRequestAnimationFrame || msRequestAnimationFrame;
      if (raf) raf(cb);
      else window.addEventListener('load', cb);
    </script>
  </body>
</html>

为什么需要JS?这有点过分了吗?

我的做法有什么问题? 为什么不能在关闭的body标签之前加载非关键CSS?


肯定存在翻译问题,因为在闭合的HTML标签后面放置任何内容都是无效的。我在该链接的英文版本中没有看到这样的声明。 - Rob
@Rob 我也是这么想的。我会寻找与 Google 联系的方法。 - Bram Vanroy
1
看起来它曾经也在英文规范中。我猜是缺乏更新,当然也不符合标准。https://dev59.com/QGEi5IYBdhLWcg3wq91D - Shikkediel
5个回答

3
我建议您查看这个代码库:https://github.com/filamentgroup/loadCSS LoadCSS是Filament Group的技术人员非常聪明的脚本,以一种大多数浏览器都能良好运行的方式延迟加载样式表。如果禁用JavaScript或由于其他原因该脚本无法正常工作,则还包括备选方案。

好的工具,但不是我所问的。我问的是我的代码与谷歌的代码相比有什么区别,为什么谷歌使用那种方法。 - Bram Vanroy

3
一个外部样式表会阻塞页面的渲染,直到它完全加载完成。Google建议将文档初始可见(关键,above the fold)部分所需的样式放在标签内的

1
将样式放在<head>标签外面是HTML5的有效写法。请参考此链接。否则,scoped属性就会变得无用。 - Bram Vanroy
好的观点,虽然与问题直接无关,但对HTML5表示赞赏。目前支持看起来相当糟糕,但这并不影响它是标准的一部分这一事实。http://caniuse.com/#feat=style-scoped - Shikkediel

1

回答你的具体问题:

  1. 为了实现你想要的效果,不需要使用Javascript。有几种方法可以以非阻塞方式加载CSS。其中一些依赖于JS,而另一些则不需要。Filamant Group的LoadCSS是一种JS选项。Critical Path的CSS Generator是一种非JS方法。生成关键CSS的过程也可以使用GulpGrunt自动化。

  2. 虽然你的方法可以工作,但这并不推荐。Google建议使用Javascript加载非关键CSS文件,以便在页面完成加载后将CSS加载到中。

替代方案

有两种方法可以改进您当前的实现。

  1. 看起来您目前正在加载2个CSS文件 - 您网站的CSS和font-awesome.min.css。这需要2个HTTP请求,会导致轻微的延迟。将这2个文件中的CSS合并为单个CSS文件。

  2. 正如其他人所指出的,Google建议将关键的CSS内联到页面的head中,并以非阻塞的方式加载其余的CSS。我发现另一种有用的选择是在一个style标签内将CSS的整个内容加载到站点的head中。我仅推荐在CSS文件相对较小且经过最小化处理时使用此选项。

 <head>
   <style>
     // ALL YOUR CSS
   </style>
 </head>

我重新审视了谷歌的JS方法,但这会在您的头部之前加载样式表。为什么?为什么不在头部中呢? - Bram Vanroy

0

我认为你关注了他们(令人困惑的)文档中错误的部分。我认为他们真正想要分享的是,你应该将关键CSS内联到你的HTML中。看看样式标签中的蓝色类

<html>
  <head>
    <style>
       <!-- This is what they are trying to show -->
      .blue{color:blue;}
    </style>
    </head>
  <body>
    <div class="blue">
      Hello, world!
    </div>
    <script>
      var cb = function() {
        var l = document.createElement('link'); l.rel = 'stylesheet';
        l.href = 'small.css';
        var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h);
      };
      var raf = requestAnimationFrame || mozRequestAnimationFrame ||
          webkitRequestAnimationFrame || msRequestAnimationFrame;
      if (raf) raf(cb);
      else window.addEventListener('load', cb);
    </script>
  </body>
</html>

我阅读了同样的法语文档,它似乎和你们的荷兰语版本一样过时,而且他们也将蓝色类放在了内联中。

<html>
  <head>
    <style>
      .blue{color:blue;}
    </style>
    </head>
  <body>
    <div class="blue">
      Hello, world!
    </div>
  </body>
</html>
<link rel="stylesheet" href="small.css">

他们想要表达的是,关键 CSS 可以直接放在 HTML 中,而不必加载整个 CSS 文件。在他们的示例中,蓝色类别是关键的,因为它是唯一使用的。

关于 HTML 标签之外的部分,它确实是无效的 HTML,但浏览器似乎仍然允许它存在。至于 JS 代码部分,我猜他们试图在头部添加样式表,但只有当 JS 执行时才会这样做,也就是在页面加载结束时。此时,您可能需要考虑代码可读性而非性能。


我重新审视了谷歌的JS方法,但这会在head之前加载样式表。为什么?为什么不在head中呢? - Bram Vanroy
很好的发现...我唯一能想到的原因是如果两个类具有相同的特异性,插入到head之前将无法覆盖在head中插入的CSS(因为顺序很重要),并且会防止文件加载时出现CSS闪烁。但是,即使浏览器支持,在head外放置样式表也是无效的。 - Simon ML
那不可能是这样的,因为谷歌的代码会在样式表之前添加,所以你永远无法覆盖任何其他样式表。 - Bram Vanroy
也许我没有表达清楚,它是在前面添加而不是覆盖,因为覆盖会导致屏幕闪烁。假设我们内联了.color { color: red; }并且一个 CSS 文件包含.color { color: blue; }那么当文件被加载时,颜色将保持为红色而不是改变为蓝色。我同意一定有更好的原因,但我不知道是什么。 - Simon ML

-1

好的,有三个主要部分,您可以放置

第一个是body,第二个是head,第三个是html中的任何地方,请尝试使用它


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接