图片尺寸、WebP、懒加载、srcset 按什么顺序配,才不会把页面拖慢

简介: 图片这块最常见的顺序错误是:先装一个自动转 WebP 的东西,再挂一个懒加载,最后发现首屏那张图还是慢。打开 DevTools 的 Network 面板按 Img 过滤,会看到手机实际下载的是两千多像素宽的 jpeg——格式换了,尺寸没换,省下的那点字节还不够抵消多下载的像素。 下面这个顺序是按依赖关系排的:每一步的产出是下一步的输入,倒过来做就要返工。

图片这块最常见的顺序错误是:先装一个自动转 WebP 的东西,再挂一个懒加载,最后发现首屏那张图还是慢。打开 DevTools 的 Network 面板按 Img 过滤,会看到手机实际下载的是两千多像素宽的 jpeg——格式换了,尺寸没换,省下的那点字节还不够抵消多下载的像素。

下面这个顺序是按依赖关系排的:每一步的产出是下一步的输入,倒过来做就要返工。

一、先定尺寸档:页面显示多宽,就准备几档

在压缩之前先回答一个问题:这张图在页面上最宽显示多少像素?

  • 正文内容图:内容列宽度(假设 760px)× 你愿意照顾到的 DPR(2 已经够用,3 的收益很小)
  • 全宽 banner:视口上限(假设 1600px)× 2
  • 列表卡片:按卡片实际宽度算,不要按容器宽度算

WordPress 里用 add_image_size 注册这些档位,只注册真正会用到的:

add_action( 'after_setup_theme', function () {
   
    add_image_size( 'content-1x', 760, 0, false );
    add_image_size( 'content-2x', 1520, 0, false );
    add_image_size( 'hero-1x',    1600, 0, false );
    add_image_size( 'hero-2x',    3200, 0, false );
    add_image_size( 'card',       640, 400, true ); // 固定裁切,列表高度才稳定
} );

add_image_size 只对之后上传的图生效,已经存在的图要跑一次重新生成缩略图。上传前把图裁到目标尺寸更省事:一张 4000px 的原图丢进去生成五档,多出来的文件都是废的。

还要顺手看一下超大图的阈值。默认会把这个尺寸以上的上传等比缩小,如果 2x 档需要 3200px,阈值不够高的话那张 2x 图根本生成不出来:

add_filter( 'big_image_size_threshold', function () {
   
    return 3200;
} );

这一步的验收标准很直白:媒体库里随便点开一张图,能看到你注册的那几档尺寸,并且都不是原图等比缩放出来的意外产物。

二、再做格式:WebP 解决的是“同尺寸下更小”

尺寸档定好之后再转格式,收益才算得清:每个档位一份 WebP,而不是十几个尺寸各自两套。

批量转换用 cwebp 走一遍上传目录,转换后的文件放在原图旁边,同名不同后缀:

#!/usr/bin/env bash
set -euo pipefail

root="${1:?用法: ./to-webp.sh wp-content/uploads}"
find "$root" -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \) -print0 |
while IFS= read -r -d '' src; do
  out="${src%.*}.webp"
  [ -f "$out" ] && continue
  cwebp -quiet -q 82 "$src" -o "$out"
done
  • 带透明通道的 PNG 不用特殊处理,cwebp 会保留 alpha。
  • 依赖 EXIF 方向信息的照片,转完抽几张用看图工具确认方向是对的。
  • 纯色 logo、界面截图这类图,WebP 有损压到 82 反而会出现色块,留在 PNG 里通常更划算。别对上传目录统一处理完就不看了。

接下来让服务端按 Accept 头决定发哪个文件,这比批量改 HTML 里的 <img> 简单得多:

map $http_accept $webp_suffix {
   
    default        "";
    "~*image/webp" ".webp";
}

server {
   
    # 上传目录里的 jpg/png:有同名 .webp 且客户端支持,就发 webp
    location ~* ^/wp-content/uploads/.+\.(?:jpe?g|png)$ {
   
        add_header Vary Accept;
        try_files $uri$webp_suffix $uri =404;
        expires 30d;
        access_log off;
    }
}

两个细节别漏:

  • add_header Vary Accept; 不能省。少了它,中间的缓存层可能把 WebP 存下来再发给不支持 WebP 的客户端。
  • 如果站前面还有一层 CDN,要么在 CDN 侧做同样的规则,要么确认回源请求里 Accept 头是透传的。很多“转换没生效”最后查出来是这一层把请求头吃了。

验证一下返回的类型对不对:

curl -sI -H 'Accept: image/webp' https://example.com/wp-content/uploads/2026/11/card-640.jpg | grep -i content-type
curl -sI https://example.com/wp-content/uploads/2026/11/card-640.jpg | grep -i content-type

两次应该分别返回 image/webp 和 image/jpeg。

三、然后是 srcset 和 sizes:让浏览器自己挑

档位和格式都就位了,才轮到浏览器选哪一个。WordPress 默认会输出 srcset,但 sizes 是按内容宽度推的,主题改过布局就对不上,浏览器于是按错误的宽度挑图——常见结果是手机上下了 2x 那张。

按实际布局改写:

add_filter( 'wp_calculate_image_sizes', function ( $sizes, $size, $url, $meta, $attachment_id ) {
   
    if ( ! empty( $size[0] ) && $size[0] >= 1500 ) {
   
        return '(max-width: 1600px) 100vw, 1600px'; // 全宽图
    }
    return '(max-width: 820px) 100vw, 760px';       // 内容图
}, 10, 5 );

改完在 Console 里跑一段,看浏览器实际挑的是哪一档:

document.querySelectorAll( 'img' ).forEach( ( img ) => {
   
  if ( ! img.currentSrc ) return;
  console.log(
    img.currentSrc.split( '/' ).pop(),
    'naturalWidth', img.naturalWidth,
    'clientWidth', img.clientWidth,
    'DPR', devicePixelRatio
  );
} );

合理的输出是 naturalWidth 接近 clientWidth × DPR,而不是固定等于 2x 档。

手写 <img> 的地方也要把宽高写全,否则图片加载完页面会跳一下:

<img src="/uploads/card-640.jpg"
     srcset="/uploads/card-640.jpg 640w, /uploads/card-1280.jpg 1280w"
     sizes="(max-width: 720px) 100vw, 360px"
     width="640" height="400"
     alt="接线端子正面"
     loading="lazy" decoding="async">

配套一行 CSS:img { max-width: 100%; height: auto; }。写了宽高属性又不给它 height:auto,图会被拉变形。

四、懒加载放最后,并且必须把首屏摘出来

懒加载改变的是“什么时候下载”,不改变“下载多大”。它放在最后做,是因为要依赖前面已经正确的 srcset:浏览器连该下哪张都算错了,懒加载只会把错的那张推迟到用户快滚到时才下。

WordPress 会把懒加载自动加到内容图里,包括首屏那张。用 class 排除是最可控的方式:

add_filter( 'wp_img_tag_add_loading_attr', function ( $value, $image, $context ) {
   
    if ( str_contains( $image, 'skip-lazy' ) ) {
   
        return false; // 这张图不加 loading 属性
    }
    return $value;
}, 10, 3 );

然后在首屏那张图上加 class="skip-lazy",并给它该有的优先级:

<img class="skip-lazy"
     fetchpriority="high"
     decoding="async"
     src="/uploads/hero-1600.jpg"
     srcset="/uploads/hero-1600.jpg 1600w, /uploads/hero-3200.jpg 3200w"
     sizes="100vw"
     width="1600" height="900"
     alt="设备全景">

另一种写法是按渲染顺序数前 N 张,只适合快速验证:

add_filter( 'wp_img_tag_add_loading_attr', function ( $value, $image, $context ) {
   
    static $n = 0;
    $n++;
    return $n <= 2 ? false : $value;
}, 10, 3 );

页面上有轮播、有区块动态插入、有多处 the_content() 调用时,这个计数会飘,别留在正式环境。

还有两个容易忽略的点:

  • 首屏如果有 CSS 背景图,它既不会被懒加载,也不会被 srcset 优化,还会挡住 LCP 的计算优化。想优化就换成 <img> 加 object-fit: cover。
  • 用 JS 库实现懒加载时,禁用 JavaScript 刷新一遍,如果有图不显示,说明它在拿可访问性换体积。优先用浏览器原生的 loading="lazy"。

五、最后才动缓存和 CDN

到这一步文件名和尺寸才固定下来,缓存规则才有意义。两个坑:

  • 图片内容换了但文件名没换,边缘节点按 URL 缓存就会继续发旧图。改图时换文件名,或者在 URL 里带上内容指纹。
  • Vary: Accept 的规则要和 CDN 的缓存键对齐。缓存键里不含 Accept、又开了格式自动转换,就会出现“缓存里存的是 WebP,发给了不支持的客户端”。

验收:用真实宽度走一遍

  1. Network 面板按 Img 过滤,清空缓存后刷新,看格式、实际像素宽度、单页图片总字节三个数。
  2. 跑上面那段 Console 脚本,确认每张图挑的档位合理;把 DPR 手动调成 2 再看一遍,应该换成 2x 文件,而不是靠 CSS 放大。
  3. 首屏那张 LCP 图:没有 loading="lazy",有 fetchpriority="high",尺寸对。
  4. 禁用 JavaScript 刷新:图应该还在。有图不显示,就是某个 JS 懒加载还在管事。

顺序上就这五步:尺寸 → 格式 → srcset/sizes → 懒加载 → 缓存。中间任何一步提前做,后面的验证都会被前面的错误掩盖。

页面本身的图处理完之后,如果还要给搜索引擎和 AI 读的东西(结构化数据、sitemap、llms.txt)还没理,AumViso 是免费的:https://aumcreate.com/plugins/aumviso?utm_source=aliyun&utm_medium=content&utm_campaign=aliyun-image-webp-lazy-load-order

相关文章
|
7天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
3092 28
|
1天前
|
云安全 人工智能 安全
|
6天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
|
7天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
1364 5
|
云安全 安全 网络安全
|
7天前
|
安全 算法 定位技术
《高性价比人生指南》完整原版:普通人用最少的资源,过好这一生的底层逻辑~How To Live Better
📖《高性价比人生指南》是一份基于实证、拒绝焦虑的生存手册,倡导以“人生时薪”为视角,重新计算时间、金钱与精力的成本与收益。它不承诺逆袭,只教人算清账:省下的钱若耗掉时间便亏;买体验比买物品更值;睡眠是最高杠杆的健康投资;关系贵在情绪价值而非表面热络;学习重在改变行为而非自我安慰。核心理念:用低成本、高回报的微小行动,换取长期的选择权——不是成为谁,而是掌控自己人生的主动权。
|
20天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
3483 53
|
12天前
|
人工智能 JSON Linux
【保姆级】ComfyUI部署教程(下载+安装+配置+工作流,2026最新)
ComfyUI 是一款开源节点式AI生成工具,支持图像、视频、音频及3D内容创作。通过拖拽连线组合模型加载、提示词、采样等节点,构建可复用、易修改的工作流,兼容SD1.5、SDXL、Flux、Qwen Image等主流模型。