
结论先给
把列表卡片图的地址后面追加一个 x-oss-process 参数,交给 OSS 实时裁切并转 WebP:
?x-oss-process=image/auto-orient,1/resize,w_450,h_300,m_fill/sharpen,100/format,webp/quality,q_85
本站实测(首页 13 张卡片图,源图多为 PNG 截图):
| 体积 | |
|---|---|
| 原图 | 约 2.27 MB |
| 处理后 | 约 0.20 MB |
| 降幅 | 约 90% |
单张对比更直观:一张 265 KB 的 PNG 截图,只裁切是 240 KB(几乎白做),裁切 + 转 WebP 后是 13.8 KB。这个幅度和源图格式有关:PNG 截图能省 95% 以上;如果源图本身已经是 JPEG,压缩空间小得多,实测同一张 JPEG 约省 85%。
真正的收益在 WebP,只裁不转基本等于没优化。
一、为什么要单独做缩略图
很多站的做法是:上传一张图,正文用原图,列表卡片也用原图——只是用 CSS 把它缩小显示。浏览器该下载的字节一个没少。
一张 1200×800 的 PNG 截图动辄 200 KB 以上,首页 13 张就是 2 MB 起步。移动端用户在这些图上花的流量和时间,比 HTML/CSS/JS 加起来还多。
正确做法是:列表用小图,正文用大图,各取所需。
二、x-oss-process 是什么
它是阿里云 OSS 的图片处理服务,在 URL 后追加参数,OSS 就会在读取时实时处理并返回结果:
- 不需要预先在控制台「数据处理 > 图片处理」里新建样式;
- 不涉及样式分隔符(
!)的那些麻烦; - 处理结果 OSS 会自动缓存,同一张图第二次访问不再重复计算。
参数逐段解释:
| 参数 | 作用 |
|---|---|
image/auto-orient,1 | 按 EXIF 自动旋转(手机竖拍照片必备) |
resize,w_450,h_300,m_fill | 裁成 450×300。m_fill = 先等比缩放再居中裁切,不变形,和列表卡片的 3:2 比例一致 |
sharpen,100 | 缩放后轻度锐化,避免糊 |
format,webp | 输出 WebP |
quality,q_85 | 质量 85,肉眼与原始基本无差 |
为什么是 450×300:卡片显示宽度约 450px(2 倍屏下 225 CSS px),3:2 比例。尺寸要贴着实际显示尺寸取,取大了等于白省。
三、在哪一层做?三个方案对比
| 方案 | 说明 | 问题 |
|---|---|---|
| 上传时用 WordPress 生成缩略图 | 用 add_image_size() | 图存在 OSS、本地不留文件时,缩略图也要占 OSS 空间和费用;尺寸改了要重新生成历史图 |
| 用 OSS 控制台建图片样式 | 预先定义样式,?x-oss-process=style/xxx | 多一点控制台配置;样式与应用代码耦合,迁移时要重建 |
| 渲染层追加参数(推荐) | 输出 HTML 时给 URL 补参数 | 需要一处代码;但零存储成本、改参数即时生效、回滚只删文件 |
我用第三种:不改数据库、不改主题文件,只在输出层动手。
四、代码:一个 mu-plugin
放到 wp-content/mu-plugins/ 下即可,不需要激活:
<?php
/**
* Plugin Name: 列表缩略图走 OSS 处理(3:2 裁切 + WebP)
*/
defined( 'ABSPATH' ) || exit;
function my_oss_thumb_process() {
return 'image/auto-orient,1/resize,w_450,h_300,m_fill/sharpen,100/format,webp/quality,q_85';
}
function my_oss_thumb_hosts() {
return array( 'img.mokiii.com' ); // 你的图床域名
}
function my_oss_thumb_url( $url ) {
$url = trim( (string) $url );
if ( '' === $url ) {
return $url;
}
// 已经带查询串就原样返回,避免 ? 与 & 拼接歧义
if ( false !== strpos( $url, '?' ) ) {
return $url;
}
$host = strtolower( (string) wp_parse_url( $url, PHP_URL_HOST ) );
if ( '' === $host || ! in_array( $host, my_oss_thumb_hosts(), true ) ) {
return $url;
}
// gif 转 WebP 会丢动画;svg 是矢量不需要处理
$ext = strtolower( pathinfo( (string) wp_parse_url( $url, PHP_URL_PATH ), PATHINFO_EXTENSION ) );
if ( in_array( $ext, array( 'gif', 'svg' ), true ) ) {
return $url;
}
return $url . '?x-oss-process=' . my_oss_thumb_process();
}
/**
* 只重写 media-3x2 容器内那一个 data-src。
* 中间的 (?:(?!</div>).)*? 保证不越过容器边界匹配到相邻卡片。
*/
function my_oss_thumb_rewrite( $html ) {
if ( ! is_string( $html ) || '' === $html || false === strpos( $html, 'media-3x2' ) ) {
return $html;
}
return preg_replace_callback(
'#(<div\s+class="media\s+media-3x2[^"]*"[^>]*>(?:(?!</div>).)*?data-src=")([^"]+)(")#is',
function ( $m ) {
return $m[1] . my_oss_thumb_url( $m[2] ) . $m[3];
},
$html
);
}
function my_oss_thumb_start_buffer() {
if ( is_admin() && ! wp_doing_ajax() ) {
return;
}
if ( is_feed() || is_robots() ) {
return;
}
ob_start( 'my_oss_thumb_rewrite' );
}
add_action( 'template_redirect', 'my_oss_thumb_start_buffer', 1 );
add_action( 'wp_ajax_nopriv_ajax_load_posts', 'my_oss_thumb_start_buffer', 1 );
add_action( 'wp_ajax_ajax_load_posts', 'my_oss_thumb_start_buffer', 1 );
几个设计要点:
- 作用范围刻意收窄——只改列表卡片容器的图片。banner、分类封面、正文头图用的是别的比例(
media-3x1、media-21x9),一律按 3:2 裁会严重变形。 - 跳过 gif / svg,跳过已带查询串的 URL。
- 同时挂整页和"加载更多"的 ajax——后者是分页加载列表的,漏了的话第二页之后的图没处理。
- 输出缓冲用
ob_start( 回调 ),不是把整页读进内存再替换。
五、验证
# 看 HTML 里列表图的地址是否带上了参数
curl -sk https://www.mokiii.com/ | grep -o 'x-oss-process=[^"]*' | head -3
# 对比体积(同一张图)
curl -s -o /dev/null -w '原图 %{size_download} B\n' 'https://img.mokiii.com/2026/01/shot.png'
curl -s -o /dev/null -w '处理图 %{size_download} B\n' 'https://img.mokiii.com/2026/01/shot.png?x-oss-process=image/resize,w_450,h_300,m_fill/format,webp/quality,q_85'
第二行应明显小于第一行。也别忘了点一下「加载更多」,确认 ajax 返回的片段里地址同样带参数。
六、要注意的地方
- 浏览器支持:输出的是 WebP。2020 年后的浏览器都支持(Safari 14+)。若你的访客里有大量老设备,把
format,webp去掉、只保留裁切。 - 图床域名白名单:改成你自己的图床域名,不要用通配,避免误伤外链图。
- 首次访问有处理耗时:OSS 第一次请求会实时计算(通常几十毫秒),之后走 OSS 自身缓存。若你的图会被大量首次访问,可以在上传后就预热一遍。
- 回滚:删掉这个 mu-plugin 文件即可,前台立刻恢复原图。
一句话总结:列表页用原图是流量黑洞。加一个 x-oss-process 参数,让 OSS 实时裁切 + 转 WebP,零存储成本、改参数即时生效——关键是一定要转 WebP,只裁不转没有意义。

评论 (0)