AeroCore主题 LCP优化:图片、JS、CSS与Preconnect

我的网站使用了AeroCore主题,发现文章页和列表页有很多图片,都用上了懒加载,包括首屏幕,但首屏幕使用懒加载会影响LCP。

我还用了几个第三方脚本和样式。结果也让首屏加载很慢。LCP 得分也不高。然后我写了一段 PHP 代码。这段代码包含四个部分。

第一部分设置图片的 eager 和 lazy 加载。第二部分给脚本加 defer。第三部分异步加载非关键 CSS。第四部分添加 preconnect。我将代码放到了主题functions.php 文件开头,这个方法提高了首屏加载速度。

PageSpeed Insights的测试效果:

PageSpeed Insights的测试效果-手机

PageSpeed Insights的测试效果-桌面设备

不过这个方案目前不完善,对于部分服务器可能存在性能问题,大家可以酌情参考,我还在研究更高效的方案。

保留functions.php文件中原有代码

<?php
if (!defined('ABSPATH')) exit;

$fun_file = __DIR__ . '/fun.php';
if (is_file($fun_file)) {
    require_once $fun_file;
}

1.图片加载优化:动态设置 Eager 和 Lazy

这段代码识别内容图片。它只处理 /wp-content/uploads/ 下的图片。它排除头像、Logo 和备案图标。然后它根据页面类型决定 eager 图片数量。首页、归档页和搜索页是 5 张。文章页是 2 张。其他页面是 3 张。第一张 eager 图片加 fetchpriority="high"。其余图片加 eager 或 lazy。所有图片都加 decoding="async"。这样首屏图片优先加载,LCP 变快。

// 图片加载优化
add_action('template_redirect', function () {
    if (is_admin() || wp_doing_ajax() || (defined('REST_REQUEST') && REST_REQUEST)) return;
    ob_start('meow_filter_images_by_page');
}, 0);

function meow_filter_images_by_page($html) {
    if (stripos($html, '<img') === false) return $html;
    $eager_count = meow_get_eager_count();

    $is_content_img = function ($tag, &$src_out) {
        $src_out = '';
        if (!preg_match('/src=["\']([^"\']+)["\']/i', $tag, $s)) return false;
        $src = html_entity_decode($s[1], ENT_QUOTES);
        if (strpos($src, '/wp-content/uploads/') === false) return false;
        if (stripos($src, 'weavatar.com') !== false) return false;
        if (stripos($src, 'gravatar.com') !== false) return false;
        if (preg_match('/\/(icp|police)\./i', $src)) return false;
        if (preg_match('/\bclass=["\']([^"\']*)/i', $tag, $c)) {
            $cls = strtolower($c[1]);
            foreach (['site-logo', 'avatar', 'trp-flag', 'logo-', 'gravatar'] as $skip) {
                if (strpos($cls, $skip) !== false) return false;
            }
        }
        $src_out = $src;
        return true;
    };

    $i = 0;
    $html = preg_replace_callback('/<img\b[^>]*>/i', function ($m) use ($is_content_img, $eager_count, &$i) {
        $tag = $m[0];
        $src = '';
        if (!$is_content_img($tag, $src)) return $tag;
        $i++;
        $tag = preg_replace('/\s+(loading|decoding|fetchpriority)=["\'][^"\']*["\']/i', '', $tag);
        if ($i <= $eager_count) {
            if ($i === 1) {
                $tag = preg_replace('/<img\b/i', '<img fetchpriority="high" loading="eager" decoding="async"', $tag, 1);
            } else {
                $tag = preg_replace('/<img\b/i', '<img loading="eager" decoding="async"', $tag, 1);
            }
        } else {
            $tag = preg_replace('/<img\b/i', '<img loading="lazy" decoding="async"', $tag, 1);
        }
        return $tag;
    }, $html);

    return $html;
}

function meow_get_eager_count() {
    if (is_front_page() || is_home() || is_tag() || is_category() || is_author()) {
        return (int) apply_filters('meow_archive_eager_count', 5);
    }
    if (is_search()) {
        return (int) apply_filters('meow_search_eager_count', 5);
    }
    if (is_single()) {
        return 2;
    }
    return (int) apply_filters('meow_default_eager_count', 3);
}

2.JS Defer:让脚本不阻塞渲染

这段代码给前端脚本加 defer 属性。它排除 jQuery 和 jQuery 迁移脚本。因为很多主题用 $() 内联调用。脚本加上 defer 后,浏览器会继续解析 HTML。这样首屏渲染不被 JavaScript 阻塞。LCP 时间会变短。

// JS defer
add_filter('script_loader_tag', function ($tag, $handle, $src) {
    if (is_admin()) return $tag;
    $exclude = ['jquery', 'jquery-core', 'jquery-migrate'];
    if (in_array($handle, $exclude, true)) return $tag;
    if (strpos($tag, ' defer') !== false || strpos($tag, ' async') !== false) return $tag;
    return str_replace(' src=', ' defer src=', $tag);
}, 10, 3);

3.非关键 CSS 异步加载:减少渲染阻塞

这段代码找到三个非关键样式表。它们不是首屏必需的。代码使用 preloadonload 异步加载这些 CSS。不支持 JavaScript 的浏览器使用 noscript 加载。这样浏览器不会等待这些样式表。首屏渲染更快。

// 非关键 CSS 异步
add_filter('style_loader_tag', function ($html, $handle, $href) {
    if (is_admin()) return $html;
    $async = [
        'trp-language-switcher-v2.css',
        'bbhcuschma-style.css',
        'perf_metrics/style.css',
    ];
    foreach ($async as $p) {
        if (strpos($href, $p) !== false) {
            return '<link rel="preload" as="style" href="' . esc_url($href)
                 . '" onload="this.rel=\'stylesheet\'">'
                 . '<noscript><link rel="stylesheet" href="' . esc_url($href) . '"></noscript>';
        }
    }
    return $html;
}, 10, 3);

4.Preconnect:提前连接第三方域名

这段代码添加三个 preconnect 提示。浏览器提前连接统计、标签管理和头像服务。当页面需要请求这些资源时,连接已经建立。这样后续请求的延迟降低。整体页面加载速度提高。

// preconnect
add_action('wp_head', function () {
    echo '<link rel="preconnect" href="https://cloud.umami.is" crossorigin>' . "\n";
    echo '<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin>' . "\n";
    echo '<link rel="preconnect" href="https://weavatar.com" crossorigin>' . "\n";
}, 1);
上一篇 剪映键盘快捷键速查表,Windows与Mac版
下一篇 AeroCore主题SEO优化:禁止日期/搜索页收录,分页标题加页码