首页背景图渐进式加载,解决卡顿难题

该方法通过外部引入,无需修改主题源文件

最近把首页的顶图配置启用了,为了加一张背景图整个博客的加载速度都受到了影响,不仅访问体验不流畅,甚至一点都不美观(特别是图片资源卡住的时候)。尝试找了一圈,最终找到了一个调整图片加载的方案比较贴近我的需求。按照原文章提供的部分代码做出调整,适配了pjax以及增加了手机端的设备判断,最终得出了本博客使用的效果。

  • 样式预览:

原理是先加载小图文件并进行高斯模糊处理,在大图加载完成后再对大图进行加载。

操作步骤
以本站使用的主题anzhiyu为例(butterfly通用),为首页顶部图配置渐进式加载。这个方法应该也同样适用于一图流的博客背景,有需要的朋友可以自己研究一下~

新建文件

  • 新建文件source/js/imgloaded.js新增以下内容,并按照注释调整图片路径

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    // 首页头图加载优化
    /**
    * @description 实现medium的渐进加载背景的效果
    */
    class ProgressiveLoad {
    constructor(smallSrc, largeSrc) {
    this.smallSrc = smallSrc;
    this.largeSrc = largeSrc;
    this.initTpl();
    }

    /**
    * @description 生成ui模板
    */
    initTpl() {
    this.container = document.createElement('div');
    this.smallStage = document.createElement('div');
    this.largeStage = document.createElement('div');
    this.smallImg = new Image();
    this.largeImg = new Image();
    this.container.className = 'pl-container';
    this.smallStage.className = 'pl-img pl-blur';
    this.largeStage.className = 'pl-img';
    this.container.appendChild(this.smallStage);
    this.container.appendChild(this.largeStage);
    this.smallImg.onload = this._onSmallLoaded.bind(this);
    this.largeImg.onload = this._onLargeLoaded.bind(this);
    }

    /**
    * @description 加载背景
    */
    progressiveLoad() {
    this.smallImg.src = this.smallSrc;
    this.largeImg.src = this.largeSrc;
    }

    /**
    * @description 大图加载完成
    */
    _onLargeLoaded() {
    this.largeStage.classList.add('pl-visible');
    this.largeStage.style.backgroundImage = `url('${this.largeSrc}')`;
    }

    /**
    * @description 小图加载完成
    */
    _onSmallLoaded() {
    this.smallStage.classList.add('pl-visible');
    this.smallStage.style.backgroundImage = `url('${this.smallSrc}')`;
    }
    }

    const executeLoad = (config, target) => {
    console.log('执行渐进背景替换');
    const isMobile = window.matchMedia('(max-width: 767px)').matches;
    const loader = new ProgressiveLoad(
    isMobile ? config.mobileSmallSrc : config.smallSrc,
    isMobile ? config.mobileLargeSrc : config.largeSrc
    );
    // 和背景图颜色保持一致,防止高斯模糊后差异较大
    if (target.children[0]) {
    target.insertBefore(loader.container, target.children[0]);
    }
    loader.progressiveLoad();
    };

    const config = {
    smallSrc: '/img/xiaotu.jpg', // 小图链接 尽可能配置小于100k的图片
    largeSrc: '/img/tu.jpg', // 大图链接 最终显示的图片
    mobileSmallSrc: '/img/sjxt.jpg', // 手机端小图链接 尽可能配置小于100k的图片
    mobileLargeSrc: '/img/sjdt.jpg', // 手机端大图链接 最终显示的图片
    enableRoutes: ['/'],
    };

    function initProgressiveLoad(config) {
    const target = document.getElementById('page-header');
    if (target && target.classList.contains('full_page')) {
    executeLoad(config, target);
    }
    }

    function onPJAXComplete(config) {
    const target = document.getElementById('page-header');
    if (target && target.classList.contains('full_page')) {
    initProgressiveLoad(config);
    }
    }

    document.addEventListener("DOMContentLoaded", function() {
    initProgressiveLoad(config);
    });

    document.addEventListener("pjax:complete", function() {
    onPJAXComplete(config);
    });
  • 新建文件source/css/imgloaded.css新增以下内容,并按照注释自行决定调整内容

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    /* 首页头图加载 */
    .pl-container {
    width: 100%;
    height: 100%;
    position: relative;
    overflow: hidden;
    will-change: transform; /* 添加性能优化 */
    animation: blur-to-clear 2s cubic-bezier(.62,.21,.25,1) 0s 1 normal backwards running, scale 1.5s cubic-bezier(.62,.21,.25,1) 0s 1 both;
    }
    .pl-img {
    width: 100%;
    height: 100%;
    position: absolute;
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    opacity: 0;
    transition: opacity 1s;
    }

    @keyframes blur-to-clear {
    0% {
    filter: blur(50px);
    opacity: 1;
    }
    100% {
    filter: blur(0);
    opacity: 1;
    }
    }

    @keyframes scale {
    0% {
    transform: scale(1.5) translateZ(0);
    opacity: 0;
    }
    to {
    transform: scale(1) translateZ(0);
    opacity: 1;
    }
    }

    .pl-visible {
    opacity: 1;
    }

    .pl-blur {
    /* 小图锯齿多,增加高斯模糊 */
    filter: blur(50px);
    }

引入文件

  • 在_config.anzhiyu.yml主题配置文件下inject配置项中head和bottom处分别引入imgloaded.css和imgloaded.js文件
    1
    2
    3
    4
    5
    6
    inject:
    head:
    - <link rel="stylesheet" href="/css/imgloaded.css?1">

    bottom:
    - <script async data-pjax src="/js/imgloaded.js?1"></script> # 首页图片渐进式加载

配置图片

  • 务必记得在主题配置文件中开启顶部图的功能,也可以像我这样配置空链接。因为js文件已经接替了图片加载功能,此处不需要配置图片(当然你也可以配置上)
    1
    2
    # The banner image of home page 这个就是首页顶部图开关
    index_img: "background: url() top / cover no-repeat" # 就这么写就行
  • 在imgloaded.js中第70行至73行处,也就是以下示例的部分配置自己的图片(推荐用Imagine压缩),可以是图片直链也可以是本地路径
    1
    2
    3
    4
    5
    6
    7
    const config = {
    smallSrc: '/img/xiaotu.jpg', // 小图链接 尽可能配置小于100k的图片
    largeSrc: '/img/tu.jpg', // 大图链接 最终显示的图片
    mobileSmallSrc: '/img/sjxt.jpg', // 手机端小图链接 尽可能配置小于100k的图片
    mobileLargeSrc: '/img/sjdt.jpg', // 手机端大图链接 最终显示的图片
    enableRoutes: ['/'],
    };

大功告成

到这一步若你配置的图片文件没有问题,可以执行hexo三连查看效果啦!

思考

该方案是否还有可优化的点,或者是否有其他用途呢🤔

灵感来源:Butterfly主题优化首页大图加载效果 - 假想国