<img>标签从入门到实战:性能、SEO、可访问性一篇讲透
做前端开发,图片处理是最容易出问题的地方。很多人觉得图片不就是写个src就能显示吗?等上线以后才发现,页面加载慢、搜索抓不到、屏幕阅读器读不出来,甚至页面还会来回跳动。
先看一个最常见的写法:
<img src="/images/product-detail.jpg">这段代码能跑,但问题不少:
没有alt,盲人用户用屏幕阅读器时不知道这张图是什么
没有width和height,图片加载时页面会突然跳动
没有懒加载,列表页所有图片一次性全下载
没有响应式图片,手机上也加载大尺寸原图
图片文件太大,影响LCP(最大内容绘制)指标
开发环境下看不出来,一到弱网、手机端、搜索引擎抓取,这些问题全暴露了。
一、先把性能基础打好
下面是一个比较完善的图片写法:
<img
src="/images/product-800.jpg"
srcset="/images/product-400.jpg 400w,
/images/product-800.jpg 800w,
/images/product-1200.jpg 1200w"
sizes="(max-width: 768px) 50vw, 33vw"
alt="黑色降噪耳机"
width="800"
height="800"
loading="lazy"
decoding="async"
/>每个属性的作用:
width和height:让浏览器提前知道图片占多大地方,避免图片加载后页面跳动
loading="lazy":图片滚动到可视区域才开始加载,节省流量
decoding="async":异步解码图片,不阻塞其他内容渲染
srcset和sizes:根据屏幕宽度加载不同尺寸的图片
注意:首屏的关键图片不要用懒加载。比如首页的大图,应该直接加载,不然LCP反而会更差。首屏图可以这样写:
<img
src="/images/hero-1280.webp"
alt="在线协作平台首页主视觉"
width="1280"
height="720"
fetchpriority="high"
/>fetchpriority="high"告诉浏览器这张图优先级高,要先加载。但不要给页面里十几张图都加这个属性,那就没意义了。
二、响应式图片,不同设备用不同尺寸
手机屏幕只有375像素宽,如果加载一张2000像素的大图,浏览器虽然能缩小显示,但流量浪费了。正确的做法是准备多个尺寸,让浏览器自己选。
<img
src="/images/avatar-160.jpg"
srcset="/images/avatar-80.jpg 80w,
/images/avatar-160.jpg 160w,
/images/avatar-320.jpg 320w"
sizes="80px"
alt="用户头像"
width="80"
height="80"
/>用户的头像、商品缩略图、文章封面图都适合这样处理,图片体积能减少不少。
如果图片在不同屏幕下需要显示不同的裁剪区域,比如手机上看人和手机上方的标题文字,桌面版看完整的风景,这时候用<picture>更合适:
<picture>
<source media="(max-width: 768px)" srcset="/images/banner-mobile.webp">
<source media="(min-width: 769px)" srcset="/images/banner-desktop.webp">
<img
src="/images/banner-desktop.webp"
alt="夏季活动宣传横幅"
width="1200"
height="500"
>
</picture>手机版和桌面版用两张不同的图,各自按合适的比例和构图来设计,比一张图硬缩要好得多。
三、SEO层面,图片不是摆设
很多人优化SEO只盯着标题和关键词,图片这块反而随便写写。实际上搜索引擎读不懂图片内容,全靠你提供的信息。
先说alt属性。别写成这样:
<img src="/images/a1.jpg" alt="图片">这等于没写。alt应该描述这张图承载的信息:
<img src="/images/cover.jpg" alt="Node.js日志清洗流程示意图">如果图片只是装饰性的,比如分割线、背景装饰,alt写空字符串就行:
<img src="/images/divider.svg" alt="">注意:alt=""和直接不写alt不是一回事。不写alt,屏幕阅读器可能会把文件名、路径这些乱七八糟的东西读出来,体验很差。
文件名也有讲究。IMG_9483.JPG和noise-cancelling-headphones-black.jpg,哪个更容易被搜索引擎理解,不用多说。
如果项目里图片很多,建议封装一个统一的渲染函数:
const articles = [
{
title: 'img标签性能优化清单',
cover: {
src: '/images/img-guide-cover-800.webp',
alt: 'img标签性能优化清单文章封面',
width: 800,
height: 450
}
}
];
function renderCover(cover) {
return `
<img
src="${cover.src}"
alt="${cover.alt}"
width="${cover.width}"
height="${cover.height}"
loading="lazy"
decoding="async"
>
`;
}四、可访问性,不能最后才想起来补
alt首先是给人用的。图片加载失败时用户能看到提示,盲人用户靠屏幕阅读器读取。
判断标准很简单:这张图去掉以后,页面会丢失重要信息吗?
会丢失 → 认真写alt
不会丢失,只是装饰 → alt=""
别省略这个属性
另外,按钮里如果只有图标没有文字,别这么写:
<button>
<img src="/icons/search.svg">
</button>屏幕阅读器读这个按钮,可能只读到“按钮”,用户不知道点下去是干什么。应该这样写:
<button aria-label="搜索">
<img src="/icons/search.svg" alt="">
</button>真正该被感知的是按钮的动作(搜索),不是里面那张放大镜图标。
五、项目里怎么统一规范,不靠人工盯
代码评审时一个一个图片去检查,很累而且容易漏。更好的办法是封一个组件:
function SmartImage({
src,
alt,
width,
height,
lazy = true,
priority = false
}) {
const attrs = [
`src="${src}"`,
`alt="${alt ?? ''}"`,
`width="${width}"`,
`height="${height}"`,
lazy && !priority ? 'loading="lazy"' : '',
!priority ? 'decoding="async"' : '',
priority ? 'fetchpriority="high"' : ''
].filter(Boolean).join(' ');
return `<img ${attrs}>`;
}调用的时候,首屏图和普通图分开处理:
// 首屏大图,优先级高
const hero = SmartImage({
src: '/images/hero.webp',
alt: '数据看板首页主视觉',
width: 1280,
height: 720,
priority: true
});
// 普通卡片图,懒加载
const card = SmartImage({
src: '/images/card-cover.webp',
alt: '文章封面图',
width: 320,
height: 180
});六、排查顺序,按这个来
页面图片多了以后,不要上来就怀疑CDN或者框架。按这个顺序检查:
首屏关键图是不是太大了
有没有加上width和height
该懒加载的是否懒了,不该懒的是不是误加了懒加载
srcset有没有按屏幕尺寸下发合适的图片
alt是不是认真写了,还是用“图片”两个字糊弄
装饰图有没有空alt,按钮里的图标有没有语义
<img>标签本身不复杂,复杂的是它同时连着性能、SEO、可访问性三条线。写得太随便,三条线一起扣分。写得仔细点,页面更稳、加载更快、语义也更干净。
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!