您的位置:新葡亰496net > 新葡亰官网 > 什么是关键,的自动化解决方案

什么是关键,的自动化解决方案

发布时间:2019-10-13 08:29编辑:新葡亰官网浏览(191)

    什么是关键 CSS

    2017/10/05 · CSS · CSS

    原文出处: Dean Hume   译文出处:众成翻译   

    网络速度很慢,但是有一些简单的策略可以使网站变快。其中之一就是将关键的css内联插入到网页的``标签, 但是,如果您的网站包含数百页,甚至更糟糕的是包含数百种不同的模板,那么你该怎么做呢? 你不能手动做这件事。 Dean Hume解释了一个简单的方法来完成它。如果您是经验丰富的网页开发人员,您可能会发现这篇文章显而易见,并且不言而喻,但对于您的客户和初级开发人员来说,这是一个很好的选择。— Ed.

    提供快速,流畅的网络体验是如今构建网站的重要部分。 大多数情况下,我们开发网站,而不去理解浏览器实际在做什么。 浏览器是如何从我们创建的HTML,CSS和JavaScript渲染我们的网页? 我们如何使用这些知识来加速我们网页的渲染

    关键 CSS 和 Webpack : 减少阻塞渲染的 CSS 的自动化解决方案

    2017/10/12 · CSS · webpack

    原文出处: Anthony Gore   译文出处:iKcamp   

    新葡亰496net 1“消除阻塞渲染的CSS和JavaScript”。 这一条Google Page Speed Insights的建议总让我困惑。当一个网页被访问时,Google希望它仅加载对初始视图有用的内容,并使用空闲时间来加载其他内容。这种方式可以使用户尽可能早地看到页面。

    新葡亰496net 2

    我们可以做很多事情来减少阻塞渲染的JavaScript,例如code splitting、tree shaking,缓存等。

    但是如何减少阻塞渲染的CSS?为此,可以拆分并优先加载首次渲染所需要的CSS(关键CSS),然后再加载其它CSS。

    可以通过编程的方式筛选出关键CSS,在本文中,我将向你展示如何通过Webpack的自动化流程来实现该方案。

    npm install -g grunt-cli

    新葡亰496net 3

    在 SmashingMag阅读更多:

    • 改善粉碎杂志的表现:案例研究
    • PostCSS介绍
    • 预加载,有什么好处?
    • 前端性能检查表

    如果我想快速提高网站的性能, Google的 PageSpeed Insights 工具是我的首选。 当尝试检测网页并找到需要改进的区域时,这非常有用。 您只需输入要测试的页面的URL,该工具就会提供一系列性能建议。

    如果您曾经通过PageSpeed Insights工具运行自己的网站,您可能会遇到以下建议。

    新葡亰496net 4

    CSS and JavaScript 会阻塞页面的渲染。 (查看大图)

    我必须承认,我第一次看到这个时有点困惑。 该建议的内容如下:

    “如果以下资源未下载完成,您的页面上的任何内容都不会被渲染。 尝试延迟或异步加载阻塞资源,或直接在HTML中内联嵌入这些资源的关键部分。“

    幸运的是,解决这个问题比看起来更简单! 答案在于CSS和JavaScript在您的网页中的加载方式。

    什么是阻塞渲染

    如果资源是“阻塞渲染”的,则表示浏览器在资源下载或处理完成之前不会显示该页面。

    通常,我们在html的head标签中添加CSS样式表,这种方式会阻塞渲染,如下所示:

    JavaScript

    <head> <link rel="stylesheet" href="/style.css"> ...</head><body> <p>在style.css下载完之前,你看不到我!!!</p></body>

    1
    2
    3
    4
    <head>
      <link rel="stylesheet" href="/style.css">
      ...</head><body>
      <p>在style.css下载完之前,你看不到我!!!</p></body>

    当这个html页面被网络浏览器加载时,它将从上到下被逐行解析。当浏览器解析到link标签时,它将立即开始下载CSS样式表,在完成之前不会渲染页面。

    对于一个大型网站,尤其是像使用了Bootstrap这种庞大框架的网站,样式表有几百KB,用户必须耐心等待其完全下载完才能看到页面。

    那么,我们是否应该把link标签放到body中,以防止阻塞渲染?你可以这么做,但是阻塞渲染也不是全无优点,我们实际上可以利用它。如果页面渲染时没有加载任何CSS,我们会遇到丑陋的”内容闪现”。

    新葡亰496net 5

    我们想要的完美解决方案就应该是:首屏相关的关键CSS使用阻塞渲染的方式加载,所有的非关键CSS在首屏渲染完成后加载。

    npm init -y

    • 原文地址: Critical CSS and Webpack: Automatically Minimize Render-Blocking CSS
    • 原文作者: Anthony Gore
    • 译者: 蜗牛(GivenCui)
    • 校对者: veizz

    什么是关键CSS?

    对CSS文件的请求可以显著增加网页呈现所需的时间。 原因是默认情况下,浏览器将延迟页面呈现,直到它完成加载、解析和执行所有在“页面”中引用的CSS文件。 这样做是因为它需要计算页面的布局。

    不幸的是,这意味着如果我们有一个非常大的CSS文件,并且需要一段时间才能完成下载,我们的用户将在浏览器开始呈现页面之前等待整个文件被下载下来。 幸运的是,有一个巧妙的技术,使我们能够优化我们的CSS的传输并减轻阻塞。这种技术被称为优化关键渲染路径。 关键渲染路径表示浏览器呈现页面的所有必须步骤。 我们想要找到最小的阻塞CSS集合 ,或者关键 CSS,以使页面显示给用户。 关键资源是可能阻塞页面首屏呈现的所有资源。 这背后的想法是,网站应该在前几个TCP数据包响应中为用户获取第一个屏幕的内容(或“首屏”内容)。 想要简要了解如何在网页上工作,请查看下面的图片。

    新葡亰496net 6

    关键 CSS是向用户呈现第一屏的内容所需CSS的最少集合。 (查看大图)

    在上面的示例中,网页的关键部分只是用户在首次加载页面时可以看到的内容。 这意味着我们只需要加载最小量的CSS来渲染页面顶部的内容。 对于CSS的其余部分,我们不需要担心,因为我们可以异步加载它。

    我们如何确定关键CSS? 确定页面的关键CSS是相当复杂的,需要您浏览网页的DOM。 接下来,我们需要确定当前应用于视图中每个元素的样式列表。 手动执行此操作将是一个繁琐的过程,但是一些很棒的工具可以自动执行这个过程。

    在本文中,我将向您展示如何使用关键的CSS提高您的网页呈现速度,并介绍一个可以帮助您自动执行此过程的工具。

    关键CSS

    这里是我用Webpack和Bootstrap编写的一个简单的网页, 下面的截图是首次渲染后的样式。

    新葡亰496net 7

    点击Sign Up today按钮会弹出一个模态框, 模态框弹出时的样式如下:

    新葡亰496net 8

    首次渲染需要的样式包括导航条的样式、超大屏幕样式、按钮样式、其它布局和字体的公用样式。但是我们并不需要模态框的样式,因为它不会立即在页面中显示。考虑到这些,下面是我们拆分关键CSS和非关键CSS的可能的方式:

    critical.css

    .nav { ... } .jumbtron { ... } .btn { ... }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .nav {
      ...
    }
     
    .jumbtron {
      ...
    }
     
    .btn {
      ...
    }

    non_critical.css

    .modal { ... }

    1
    2
    3
    .modal {
      ...
    }

    如果你已经有这个概念,那么你可能会提出两个疑问:

    1. 我们如何用程序区分关键CSS和非关键CSS?
    2. 如何让页面在首次渲染之前加载关键CSS,之后加载非关键CSS?

    npm install grunt --save-dev


    关键CSS实践

    使用关键CSS,我们需要改变我们处理CSS的方式 – 这意味着将其分成两个文件。 对于第一个文件,我们仅提取渲染上述内容所需的最小CSS集,然后将其内联在网页中。 对于第二个文件或非关键的CSS,我们异步加载它,以免阻塞网页。

    一开始似乎有点奇怪,但是通过将关键的CSS集成到HTML中,我们可以消除关键路径中的额外的请求。 这使我们能够在一次请求中提供关键的CSS,以尽快向用户展示页面。

    下面的代码给出了一个基本的例子。

    JavaScript

    <!doctype html> <head> <style> /* 内联CSS */ </style> ``<script> loadCSS('non-critical.css'); </script>`` </head> <body> ...body goes here </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    &lt;!doctype html&gt;
    &lt;head&gt;
      &lt;style&gt; /* 内联CSS */ &lt;/style&gt;
      ``&lt;script&gt; loadCSS('non-critical.css'); &lt;/script&gt;``
    &lt;/head&gt;
    &lt;body&gt;
      ...body goes here
    &lt;/body&gt;
    &lt;/html&gt;

    如上,我们将关键CSS内联在style 标签中。然后,使用 loadCSS(); 异步加载非关键的CSS。 这很重要,因为我们在展示首屏后加载繁重的(非关键) CSS。

    起初,这似乎是一场噩梦。 为什么要手动在每个页面内嵌CSS片段? 但是有一个好消息,这个过程可以自动化,在这个例子中,我将运行一个名为Critical 的工具。 Addy Osmani 创造,它是一个允许您自动提取和内联关键路径CSS到HTML中的的Node.js包。 我将把这个工具和 Grunt 一起介绍, Grunt是一个JavaScript 任务执行器, 自动处理CSS。 如果你之前没听过Grunt, 这个网站有一些非常 详细文档, 以及配置项目的各种解释。我之前博客介绍过这个工具.

    示例项目

    我将简要介绍一下这个项目的基本配置,这样我们在遇到解决方案时,方便快速消化。
    首先, 在入口文件中引入Bootsrap SASS。

    main.js

    require("bootstrap-sass/assets/stylesheets/_bootstrap.scss");

    1
    require("bootstrap-sass/assets/stylesheets/_bootstrap.scss");

    我使用sass-loader来处理sass,与Extract Text Plugin一起使用,将编译出来的css放到单独的文件中。

    使用HTML Webpack Plugin来创建一个HTML文件,它引入编译后的CSS。这在我们的解决方案中是必需的,你马上就会看到。

    webpack.config.js

    module.exports = { module: { rules: [ { test: /.scss$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, ... ] }, ... plugins: [ new ExtractTextPlugin({ filename: 'style.css' }), new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.html', inject: true }) ] };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    module.exports = {
      module: {
        rules: [
          {
            test: /.scss$/,
            use: ExtractTextPlugin.extract({
              fallback: 'style-loader',
              use: ['css-loader', 'sass-loader']
            })
          },
          ...
        ]
      },
      ...
      plugins: [
        new ExtractTextPlugin({ filename: 'style.css' }),
        new HtmlWebpackPlugin({
          filename: 'index.html',
          template: 'index.html',
          inject: true
        })
      ]
    };

    运行构建之后,这里是HTML文件的样子。请注意,CSS文件在head标签里引入,因此将会阻塞渲染。

    index.html

    JavaScript

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>vuestrap-code-split</title> <link href="/style.css" rel="stylesheet"> </head> <body> <!--App content goes here, omitted for brevity.--> <script type="text/javascript" src="/build_main.js"></script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>vuestrap-code-split</title>
        <link href="/style.css" rel="stylesheet">
    </head>
    <body>
      <!--App content goes here, omitted for brevity.-->
      <script type="text/javascript" src="/build_main.js"></script>
    </body>
    </html>

    grunt 安装完毕

    "消除阻塞渲染的CSS和JavaScript"。 这一条Google Page Speed Insights的建议总让我困惑。

    开始

    我们先从Node.js控制台开始,并导航到您的网站的路径。 通过在您的控制台中输入以下命令来安装Grunt命令行界面:

    npm install -g grunt-cli 

    1
    2
    npm install -g grunt-cli
    

    这将把grunt命令放在你的系统路径中,允许从任何目录运行它。 接下来,使用以下命令安装Grunt任务运行程序:

    npm install grunt --save-dev 

    1
    2
    npm install grunt --save-dev
    

    然后安装 grunt-critical 插件.

    npm install grunt-critical --save-dev 

    1
    2
    npm install grunt-critical --save-dev
    

    接下来,您需要创建项目任务配置的Gruntfile。 看起来有点像下面的代码。

    module.exports = function (grunt) { grunt.initConfig({ critical: { dist: { options: { base: './' }, // The source file src: 'page.html', // The destination file dest: 'result.html' } } }); // Load the plugins grunt.loadNpmTasks('grunt-critical'); // Default tasks. grunt.registerTask('default', ['critical']); }; 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    module.exports = function (grunt) {
    grunt.initConfig({
      critical: {
        dist: {
          options: {
            base: './'
          },
          // The source file
          src: 'page.html',
          // The destination file
          dest: 'result.html'
          }
        }
      });
      // Load the plugins
      grunt.loadNpmTasks('grunt-critical');
      // Default tasks.
      grunt.registerTask('default', ['critical']);
    };
    

    在上面的代码中,我配置了 Critical 插件来查看我的page.html文件。 然后它会根据给定的页面处理CSS来计算关键的CSS。 接下来,它将内联关键的CSS并相应地更新HTML页面。

    通过在控制台中输入grunt来运行插件。

    新葡亰496net 9

    使用Grunt自动检测网络性能。(查看大图)

    如果您导航到该文件夹,则应该会注意到一个名为result.html的文件,其中包含内联的关键CSS,而剩余的CSS异步加载。 您的网页现在就可以使用了!

    在幕后, 插件自动使用 PhantomJS, 一个无头WebKit浏览器,捕获所需的关键CSS。 这意味着它能够静默地加载您的网页并测试最佳关键CSS。 这个功能还保证了插件在不同屏幕尺寸上的灵活性。 例如,您可以提供不同的屏幕尺寸,插件将相应地捕获并内联您的关键CSS

    critical: { dist: { options: { base: './', dimensions: [{ width: 1300, height: 900 }, { width: 500, height: 900 }] }, files: [ {src: ['index.html'], dest: 'dist/index.html'} ] } } 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    critical: {
      dist: {
        options: {
          base: './',
          dimensions: [{
            width: 1300,
            height: 900
          },
          {
            width: 500,
            height: 900
          }]
        },
        files: [
          {src: ['index.html'], dest: 'dist/index.html'}
        ]
      }
    }
    

    上面的代码将从多个维度处理给定的文件,并内联相应的关键CSS。 这意味着您可以根据多个屏幕宽度运行您的网站,并确保您的用户仍然拥有相同的体验。 我们知道,使用3G和4G的移动连接可能是不稳定的 – 这就是为什么这种技术对于移动用户来说如此重要。

    编程识别关键CSS

    手动区分关键CSS维护起来会非常痛苦。以编程方式来实现的话,我们可以使用Addy Osmani的Critical。这是一个Node.js模块,它将读入HTML文档,并识别关键CSS。Critical能做的还不止这些,你很快就能体会到。

    Critical识别关键CSS的方式如下:指定屏幕尺寸并使用PhantomJS加载页面,提取在渲染页面中用到的所有CSS规则。

    以下为对项目的设置:

    const critical = require("critical"); critical.generate({ /* Webpack打包输出的路径 */ base: path.join(path.resolve(__dirname), 'dist/'), src: 'index.html', dest: 'index.html', inline: true, extract: true, /* iPhone6的尺寸,你可以按需要修改 */ width: 375, height: 565, /* 确保调用打包后的JS文件 */ penthouse: { blockJSRequests: false, } });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    const critical = require("critical");
     
    critical.generate({
      
      /* Webpack打包输出的路径 */
      base: path.join(path.resolve(__dirname), 'dist/'),
      src: 'index.html',
      dest: 'index.html',
      inline: true,
      extract: true,
     
      /* iPhone6的尺寸,你可以按需要修改 */
      width: 375,
      height: 565,
      
      /* 确保调用打包后的JS文件 */
      penthouse: {
        blockJSRequests: false,
      }
    });

    执行时,会将Webpack打包输出文件中HTML更新为:

    JavaScript

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Bootstrap Critical</title> <style type="text/css"> /* 关键CSS通过内部样式表方式引入 */ body { font-family: Helvetica Neue,Helvetica,Arial,sans-serif; font-size: 14px; line-height: 1.42857; color: #333; background-color: #fff; } ... </style> <link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'"> <noscript> <link href="/style.96106fab.css" rel="stylesheet"> </noscript> <script> /*用来加载非关键CSS的脚本*/ </script> </head> <body> <!-- 这里是App的内容 --> <script type="text/javascript" src="/build_main.js"></script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      <title>Bootstrap Critical</title>
      <style type="text/css">
        /* 关键CSS通过内部样式表方式引入 */
        body {
          font-family: Helvetica Neue,Helvetica,Arial,sans-serif;
          font-size: 14px;
          line-height: 1.42857;
          color: #333;
          background-color: #fff;
        }
        ...
      </style>
      <link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'">
      <noscript>
          <link href="/style.96106fab.css" rel="stylesheet">
      </noscript>
      <script>
        /*用来加载非关键CSS的脚本*/
      </script>
    </head>
    <body>
      <!-- 这里是App的内容 -->
      <script type="text/javascript" src="/build_main.js"></script>
    </body>
    </html>

    它还将输出一个新的CSS文件,例如style.96106fab.css(文件自动Hash命名)。这个CSS文件与原始样式表相同,只是不包含关键CSS。

    Gruntfile干这几件事情

    当一个网页被访问时,Google希望它仅加载对初始视图有用的内容,并使用空闲时间来加载其他内容。这种方式可以使用户尽可能早地看到页面。

    在生产环境中使用Critical

    使用Critical这样的工具是自动提取和内联关键CSS的好方法,而无需改变开发网站的方式,但是如何适应真实场景? 要将新更新的文件置于目标文件,您只需按照通常的方式进行部署 – 无需在生产环境中更改。 您只需记住,每次构建或更改CSS文件时,都需要运行Grunt。

    我们在本文中运行的代码示例涵盖了单个文件的使用,但是当您需要处理多个文件关键CSS甚至整个文件夹时会发生什么? 您的Gruntfile可以更新以处理多个文件,类似于下面的示例。

    critical: { dist: { options: { base: './', dimensions: [{ width: 1300, height: 900 }, { width: 500, height: 900 }] }, files: [ {src: ['index.html'], dest: 'dist/index.html'}, {src: ['blog.html'], dest: 'dist/blog.html'} {src: ['about.html'], dest: 'dist/about.html'} {src: ['contact.html'], dest: 'dist/contact.html'} ] } } 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    critical: {
      dist: {
        options: {
          base: './',
          dimensions: [{
            width: 1300,
            height: 900
           },
           {
            width: 500,
            height: 900
          }]
        },
        files: [
          {src: ['index.html'], dest: 'dist/index.html'},
          {src: ['blog.html'], dest: 'dist/blog.html'}
          {src: ['about.html'], dest: 'dist/about.html'}
          {src: ['contact.html'], dest: 'dist/contact.html'}
        ]
      }
    }
    

    您还可以使用以下代码对给定文件夹中的每个HTML文件执行任务:

    critical: { dist: { options: { base: './', dimensions: [{ width: 1300, height: 900 }, { width: 500, height: 900 }], src: '*.html', dest: 'dist/' } } } 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    critical: {
      dist: {
        options: {
          base: './',
          dimensions: [{
            width: 1300,
            height: 900
          },
          {
            width: 500,
            height: 900
          }],
          src: '*.html',
          dest:  'dist/'
        }
      }
    }
    

    上面的代码示例可以让您深入了解如何在您的网站上实现。

    内联嵌入关键CSS样式

    你会注意到,关键CSS已经嵌入到文档的头部。这是最佳的,因为页面不必从服务器加载它。

    1、包装函数 module.exports = function(grunt) {}

    新葡亰496net 10

    测试

    一如以往,测试任何新的变化是非常重要的。 如果您想要测试更改,有一些很棒的工具可以在线免费使用。进到 Google’s PageSpeed Insights 并通过该工具运行您的URL。 您应该注意到,您的网页现在不再具有任何阻塞资源,并且您的性能改进建议已经变绿 。而你可能也熟悉了另一个伟大的工具。新葡亰496net,WebPagetest

    新葡亰496net 11

    使用WebPagetest是测试您的网页及时呈现的好方法。 (查看大图)

    它是一个免费的工具,可以让您从全球各个地点进行网站速度测试。 除了对您的网页的内容进行丰富的分析性审查,如果您选择“Visual Comparison”, 该工具将比较两个网页。 这是比较更新您的关键CSS之前和之后的结果并回放差异的好方法。

    使用关键CSS的想法是,我们的网页会尽快呈现,从而尽快向用户展示内容。 测量这个的最好方法是使用 speed index. WebPagetest采用的测量方法是衡量页面内容的视觉填充速度。SpeedIndex测量可视页面加载的视觉进度,并计算内容绘制速度的总体得分。 比较 SpeedIndex测量通过内联关键CSS之前和之后的改变。 您将对您的渲染时间的改变大吃一惊。

    预加载非关键CSS

    你还会注意到,非关键CSS使用了一个看起来更复杂的link标签来加载。rel="preload"通知浏览器开始获取非关键CSS以供之后用。其关键在于,preload不阻塞渲染,无论资源是否加载完成,浏览器都会接着绘制页面。

    link标签中的onload属性允许我们在非关键CSS加载完成时运行脚本。Critical模块可以自动将此脚本嵌入到文档中,这种方式提供了将非关键CSS加载到页面中的跨浏览器兼容方法。

    <link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'"/>

    1
      <link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'"/>

    2、项目/任务配置 initConfig()

    我们可以做很多事情来减少阻塞渲染的JavaScript,例如code splitting、tree shaking,缓存等。

    深入了解

    正如大多数优化工具,对你的网站总有利弊。弊端之一是 丢失浏览器中的CSS缓存 。 如果动态网页更改频繁,我们不希望缓存HTML页面 这意味着内联CSS 每次重新下载。 需要说明的是只列出关键的CSS,异步加载剩下的非关键的CSS。 我们可以缓存非关键的CSS。有很多争论和反对关于在``中内联CSS, 了解更多我推荐 Hans Christian Reinl的博客 “A counter statement: Putting the CSS in the head”。

    如果您使用(CDN),也值得一提的是,您还应该 从CDN中提供非关键的CSS。 这样做允许您直接从边缘提供缓存的资源,提供更快的响应时间,而不是一路路由到源服务器来获取它们。

    对于传统的网页,内联CSS的技术运作良好,但根据您的情况,可能并不总是适用。 如果您有客户端JavaScript生成HTML怎么办? 如果您在单页面应用程序上怎么办? 如果您尽可能多地输出关键的CSS,它将提升页面渲染效果。 了解关键CSS的工作原理及是否适用于您的网页,这一点很重要。 我喜欢Guy Podjarny对此的立场:

    “尽管有这些限制,Inline在前端优化领域仍然是一个很重要的工具。 因此,你应该使用它,但要小心,不要滥用它。“

    —Guy Podjarny

    在 “为什么内联一切不是答案”,他提供了关于什么时候应该_什么时候不应该嵌入CSS的好建议。

    把Critical组件添加到webpack打包流程中

    我创建了一个名为HTML Critical Webpack Plugin的插件,该插件仅仅是Critical模块的封装。它将在HTML Webpack Plugin输出文件后运行。

    你可以在Webpack的项目中这样引入:

    const HtmlCriticalPlugin = require("html-critical-webpack-plugin"); module.export = { ... plugins: [ new HtmlWebpackPlugin({ ... }), new ExtractTextPlugin({ ... }), new HtmlCriticalPlugin({ base: path.join(path.resolve(__dirname), 'dist/'), src: 'index.html', dest: 'index.html', inline: true, minify: true, extract: true, width: 375, height: 565, penthouse: { blockJSRequests: false, } }) ] };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    const HtmlCriticalPlugin = require("html-critical-webpack-plugin");
     
    module.export = {
      ...
      plugins: [
        new HtmlWebpackPlugin({ ... }),
        new ExtractTextPlugin({ ... }),
        new HtmlCriticalPlugin({
          base: path.join(path.resolve(__dirname), 'dist/'),
          src: 'index.html',
          dest: 'index.html',
          inline: true,
          minify: true,
          extract: true,
          width: 375,
          height: 565,
          penthouse: {
            blockJSRequests: false,
          }
        })
      ]
    };

    注意:你应该只在生产版本中使用,因为它将使你的开发环境的构建很慢

    3、加载插件 loadNpmTasks()

    但是如何减少阻塞渲染的CSS?为此,可以拆分并优先加载首次渲染所需要的CSS(关键CSS),然后再加载其它CSS。

    这不完美

    虽然生成和内联关键CSS所需的许多工具都在不断改进,但可能还有一些需要改进的领域。 如果您发现任何错误,您的项目,open up an issue 或提出请求,并在GitHub贡献项目。

    为您的网站优化关键渲染路径可以大大改善页面加载时间。 使用这种技术使我们能够使用响应式布局,而不会影响其众所周知的优点。 这也是确保您的页面加载快速而不妨碍您的设计的好方法。

    表现结果

    现在已经抽离了关键CSS,并且把非关键CSS的加载放到空闲时间,这在性能方面会有怎样的提升呢?

    我使用Chrome的Lighthouse扩展插件进行测试。请记住,我们尝试优化的指标是“首次有效绘制”,也就是用户需要多久才能看到真正可浏览的页面。

    不使用区分关键CSS技术的表现

    新葡亰496net 12

    使用区分关键CSS技术的表现

    新葡亰496net 13

    正如你所看到的,我的应用程序First Meaningful paint时间缩短了将近1秒,到达可交互状态的时间节省了0.5秒。实际中,你的应用程序可能无法获得如此惊人的改善,因为我的CSS很笨重(我包含了整个Bootstrap库),而且在这样一个简单的应用程序中,我没有很多关键CSS规则。

    1 赞 1 收藏 评论

    新葡亰496net 14

    4、注册任务 registerTask()

    可以通过编程的方式筛选出关键CSS,在本文中,我将向你展示如何通过Webpack的自动化流程来实现该方案。

    更多资源

    如果您喜欢使用其他构建系统(如Gulp),则可以直接使用插件,而无需下载Grunt。 还有一个有用的教程,如何使用Gulp优化基本页面.

    还有其他插件可以提取你的关键CSS,比如 Penthouse,和来自Filament 公司的criticalCSS。我强烈推荐 “我们如何使RWD网站快速加载” 了解如何使用这个技术来确保他们的网页尽可能快地加载。

    Smashing Magazine的总编辑Vitaly Friedman写了一篇关于Smashing Magazine如何改进表现的文章 improved the performance 。如果您想了解关于渲染路径的更多信息,那么在Udacity网站上可以免费使用 一个有用的课程。 Google Developers website 也有关于 优化CSS传输的内容。 Patrick Hamman 写了一篇博客关于 如何识别关键的CSS创建更快的网页。

    默认情况下,您是否在您的项目中嵌入关键CSS? 你使用什么工具? 你遇到什么问题? 欢迎在文章下方分享你的经验!

    (il, rb, ml, og)

    1 赞 2 收藏 评论

    新葡亰496net 15

    项目/任务配置中干这几件事情

    什么是阻塞渲染

    如果资源是“阻塞渲染”的,则表示浏览器在资源下载或处理完成之前不会显示该页面。

    通常,我们在html的head标签中添加CSS样式表,这种方式会阻塞渲染,如下所示:

    <head>
      <link rel="stylesheet" href="/style.css">
      ...
    </head>
    <body>
      <p>在style.css下载完之前,你看不到我!!!</p>
    </body>
    

    当这个html页面被网络浏览器加载时,它将从上到下被逐行解析。当浏览器解析到link标签时,它将立即开始下载CSS样式表,在完成之前不会渲染页面。

    对于一个大型网站,尤其是像使用了Bootstrap这种庞大框架的网站,样式表有几百KB,用户必须耐心等待其完全下载完才能看到页面。

    那么,我们是否应该把link标签放到body中,以防止阻塞渲染?你可以这么做,但是阻塞渲染也不是全无优点,我们实际上可以利用它。如果页面渲染时没有加载任何CSS,我们会遇到丑陋的"内容闪现"。

    新葡亰496net 16

    我们想要的完美解决方案就应该是:首屏相关的关键CSS使用阻塞渲染的方式加载,所有的非关键CSS在首屏渲染完成后加载。

    1、将配置文件读出,并且转换为json对象 pkg: grunt.file.readJSON('package.json')

    关键CSS

    这里是我用Webpack和Bootstrap编写的一个简单的网页, 下面的截图是首次渲染后的样式。

    新葡亰496net 17

    点击Sign Up today按钮会弹出一个模态框, 模态框弹出时的样式如下:

    新葡亰496net 18

    首次渲染需要的样式包括导航条的样式、超大屏幕样式、按钮样式、其它布局和字体的公用样式。但是我们并不需要模态框的样式,因为它不会立即在页面中显示。考虑到这些,下面是我们拆分关键CSS和非关键CSS的可能的方式:

    critical.css

    .nav {
      ...
    }
    
    .jumbtron {
      ...
    }
    
    .btn {
      ...
    }
    

    non_critical.css

    .modal {
      ...
    }
    

    如果你已经有这个概念,那么你可能会提出两个疑问:

    1. 我们如何用程序区分关键CSS和非关键CSS?
    2. 如何让页面在首次渲染之前加载关键CSS,之后加载非关键CSS?

    2、配置一些命名性属性比如:uglify

    示例项目

    我将简要介绍一下这个项目的基本配置,这样我们在遇到解决方案时,方便快速消化。
    首先, 在入口文件中引入Bootsrap SASS。

    main.js

    require("bootstrap-sass/assets/stylesheets/_bootstrap.scss");
    

    我使用sass-loader来处理sass,与Extract Text Plugin一起使用,将编译出来的css放到单独的文件中。

    使用HTML Webpack Plugin来创建一个HTML文件,它引入编译后的CSS。这在我们的解决方案中是必需的,你马上就会看到。

    webpack.config.js

    module.exports = {
      module: {
        rules: [
          {
            test: /.scss$/,
            use: ExtractTextPlugin.extract({
              fallback: 'style-loader',
              use: ['css-loader', 'sass-loader']
            })
          },
          ...
        ]
      },
      ...
      plugins: [
        new ExtractTextPlugin({ filename: 'style.css' }),
        new HtmlWebpackPlugin({
          filename: 'index.html',
          template: 'index.html',
          inject: true
        })
      ] 
    };
    

    运行构建之后,这里是HTML文件的样子。请注意,CSS文件在head标签里引入,因此将会阻塞渲染。

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>vuestrap-code-split</title>
        <link href="/style.css" rel="stylesheet">
    </head>
    <body>
      <!--App content goes here, omitted for brevity.-->
      <script type="text/javascript" src="/build_main.js"></script>
    </body>
    </html>
    

    1、在src中找到目标文件进行压缩

    编程识别关键CSS

    手动区分关键CSS维护起来会非常痛苦。以编程方式来实现的话,我们可以使用Addy Osmani的Critical。这是一个Node.js模块,它将读入HTML文档,并识别关键CSS。Critical能做的还不止这些,你很快就能体会到。

    Critical识别关键CSS的方式如下:指定屏幕尺寸并使用PhantomJS加载页面,提取在渲染页面中用到的所有CSS规则。

    以下为对项目的设置:

    const critical = require("critical");
    
    critical.generate({
    
      /* Webpack打包输出的路径 */
      base: path.join(path.resolve(__dirname), 'dist/'),
      src: 'index.html',
      dest: 'index.html',
      inline: true,
      extract: true,
    
      /* iPhone6的尺寸,你可以按需要修改 */
      width: 375,
      height: 565,
    
      /* 确保调用打包后的JS文件 */
      penthouse: {
        blockJSRequests: false,
      }
    });
    

    执行时,会将Webpack打包输出文件中HTML更新为:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      <title>Bootstrap Critical</title>
      <style type="text/css">
        /* 关键CSS通过内部样式表方式引入 */
        body {
          font-family: Helvetica Neue,Helvetica,Arial,sans-serif;
          font-size: 14px;
          line-height: 1.42857;
          color: #333;
          background-color: #fff;
        }
        ...
      </style>
      <link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'">
      <noscript>
          <link href="/style.96106fab.css" rel="stylesheet">
      </noscript>
      <script>
        /*用来加载非关键CSS的脚本*/
      </script>
    </head>
    <body>
      <!-- 这里是App的内容 -->
      <script type="text/javascript" src="/build_main.js"></script>
    </body>
    </html>
    

    它还将输出一个新的CSS文件,例如style.96106fab.css(文件自动Hash命名)。这个CSS文件与原始样式表相同,只是不包含关键CSS。

    2、找到要导出的目录,没有就新建,将压缩文件放进去

    内联嵌入关键CSS样式

    你会注意到,关键CSS已经嵌入到文档的头部。这是最佳的,因为页面不必从服务器加载它。

    3、在上面加几个描述语言

    预加载非关键CSS

    你还会注意到,非关键CSS使用了一个看起来更复杂的link标签来加载。rel="preload"通知浏览器开始获取非关键CSS以供之后用。其关键在于,preload不阻塞渲染,无论资源是否加载完成,浏览器都会接着绘制页面。

    link什么是关键,的自动化解决方案。标签中的onload属性允许我们在非关键CSS加载完成时运行脚本。Critical模块可以自动将此脚本嵌入到文档中,这种方式提供了将非关键CSS加载到页面中的跨浏览器兼容方法。

    <link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'">
    

    综上:我们使用grunt时,主要工作就是配置或者注册任务,实际上就是在做一个事件注册,由我们来触发

    把Critical组件添加到webpack打包流程中

    我创建了一个名为HTML Critical Webpack Plugin的插件,该插件仅仅是Critical模块的封装。它将在HTML Webpack Plugin输出文件后运行。

    你可以在Webpack的项目中这样引入:

    const HtmlCriticalPlugin = require("html-critical-webpack-plugin");
    
    module.export = {
      ...
      plugins: [
        new HtmlWebpackPlugin({ ... }),
        new ExtractTextPlugin({ ... }),
        new HtmlCriticalPlugin({
          base: path.join(path.resolve(__dirname), 'dist/'),
          src: 'index.html',
          dest: 'index.html',
          inline: true,
          minify: true,
          extract: true,
          width: 375,
          height: 565,
          penthouse: {
            blockJSRequests: false,
          }
        })
      ] 
    };
    

    注意:你应该只在生产版本中使用,因为它将使你的开发环境的构建很慢

    文件头部加一段注释性语言配置banner信息options: {banner:'/*! 注释信息 */'}

    表现结果

    现在已经抽离了关键CSS,并且把非关键CSS的加载放到空闲时间,这在性能方面会有怎样的提升呢?

    我使用Chrome的Lighthouse扩展插件进行测试。请记住,我们尝试优化的指标是“首次有效绘制”,也就是用户需要多久才能看到真正可浏览的页面。

    不使用区分关键CSS技术的表现

    新葡亰496net 19

    使用区分关键CSS技术的表现

    新葡亰496net 20

    正如你所看到的,我的应用程序First Meaningful paint时间缩短了将近1秒,到达可交互状态的时间节省了0.5秒。实际中,你的应用程序可能无法获得如此惊人的改善,因为我的CSS很笨重(我包含了整个Bootstrap库),而且在这样一个简单的应用程序中,我没有很多关键CSS规则。

    新葡亰496net 21

    新葡亰496net 22

    iKcamp原创新书《移动Web前端高效开发实战》已在亚马逊、京东、当当开售。

    iKcamp官网:http://www.ikcamp.com

    npminstallgrunt-contrib-uglify--save-dev//安装压缩插件grunt.loadNpmTasks('grunt-contrib-uglify');//引入压缩插件

    npm install grunt-contrib-concat--save-dev//安装合并插件grunt.loadNpmTasks('grunt-contrib-concat');//引入压缩插件

    npm install grunt-contrib-cssmin --save-devnpm install grunt-contrib-htmlmin --save-dev

    npminstallgrunt-contrib-watch--save-dev//监听grunt.loadNpmTasks('grunt-contrib-watch');

    module.exports =function(grunt){    grunt.initConfig({pkg: grunt.file.readJSON('package.json'),uglify:{options: {banner:'/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */n'},bar:{//files:[//    {//        src:'js/js1.js',//        dest:'dist/js1.min.js'//    },//    {//        src:'js/js2.js',//        dest:'dist/js2.min.js'//    }//]files:[{expand:true,cwd:'js/',src: ['*.js'],dest:'dist/js'}]            }        },concat:{css:{src:'css/*.css',dest:'dist/css/all.css'},js:{src:'js/*.js',dest:'dist/jsmin/all.js'}        },htmlmin:{bar:{options: {removeComments:true,removeCommentsFromCDATA:true,collapseWhitespace:true,collapseBooleanAttributes:true,removeAttributeQuotes:true,removeRedundantAttributes:true,useShortDoctype:true,removeEmptyAttributes:true,removeOptionalTags:true},files:[{expand:true,src: ['*.html'],dest:'dist/html'}]            }        },watch:{files:['js/*.js'],tasks:['uglify','concat']        }    });    grunt.loadNpmTasks('grunt-contrib-uglify');    grunt.loadNpmTasks('grunt-contrib-concat');    grunt.loadNpmTasks('grunt-contrib-htmlmin');    grunt.loadNpmTasks('grunt-contrib-watch');    grunt.registerTask('default', ['uglify','concat','htmlmin','watch']);};

    本文由新葡亰496net发布于新葡亰官网,转载请注明出处:什么是关键,的自动化解决方案

    关键词: