慣性聚合 高效追蹤和閱讀你感興趣的部落格、新聞、科技資訊
閱讀原文 在慣性聚合中打開

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

阮一峰的网络日志

科技爱好者周刊(第 396 期):互联网通信的替代方案 科技爱好者周刊(第 396 期):互联网通信的替代方案 - 阮一峰的网络日志 科技爱好者周刊(第 395 期):软件开发的第三种方式 科技爱好者周刊(第 395 期):软件开发的第三种方式 - 阮一峰的网络日志 科技爱好者周刊(第 393 期):脑腐状态 科技爱好者周刊(第 392 期):axios 投毒与好莱坞式骗术 科技爱好者周刊(第 391 期):AI 的贫富分化 科技爱好者周刊(第 390 期):没有语料,大模型就是智障 套壳中国大模型撑起500亿美元估值?扒一扒 Cursor 的"套壳"疑云 科技爱好者周刊(第 389 期):未来如何招聘程序员 科技爱好者周刊(第 388 期):测试是新的护城河 零安装的"云养虾":ArkClaw 使用指南 科技爱好者周刊(第 387 期):你是领先的 科技爱好者周刊(第 386 期):当外卖员接入 AI 字节全家桶 Seed 2.0 + TRAE 玩转 Skill 科技爱好者周刊(第 385 期):马斯克害怕中国车企吗? 智谱旗舰 GLM-5 实测:对比 Opus 4.6 和 GPT-5.3-Codex 科技爱好者周刊(第 384 期):为什么软件股下跌 科技爱好者周刊(第 383 期):你是第几级 AI 编程 Kimi 的一体化,Manus 的分层 科技爱好者周刊(第 382 期):独立软件的黄昏 AI native Workspace 也许是智能体的下一阶段 科技爱好者周刊(第 381 期):中国 AI 大模型领导者在想什么 科技爱好者周刊(第 380 期):为什么人们拥抱"不对称收益" 科技爱好者周刊(第 379 期):《硅谷钢铁侠》摘录 我如何用 AI 处理历史遗留代码:MiniMax M2.1 升级体验 科技爱好者周刊(第 378 期):预测是新的互联网热点 科技爱好者周刊(第 377 期):14万美元的贫困线 科技爱好者周刊(第 376 期):太空数据中心的争议 科技爱好者周刊(第 375 期):一扇门的 Bug 终于有人做了 Subagent,TRAE 国内版 SOLO 模式来了 科技爱好者周刊(第 374 期):6GHz 的问题 VS Code 使用国产大模型 MiniMax M2 教程 科技爱好者周刊(第 373 期):数据模型是新产品的核心 国产大模型接入 Claude Code 教程:以 Doubao-Seed-Code 为例 科技爱好者周刊(第 372 期):软件界面如何设计 大模型比拼:MiniMax M2 vs GLM 4.6 vs Claude Sonnet 4.5 科技爱好者周刊(第 371 期):一个乐观主义者的专访 科技爱好者周刊(第 370 期):正确的代码高亮 错误处理:异常好于状态码 科技爱好者周刊(第 369 期):Tim 与罗永浩的对谈 科技爱好者周刊(第 368 期):不要这样管理软件团队 一天之内,智谱和 Anthropic 都发了最强编程模型 科技爱好者周刊(第 367 期):Nano Banana 的几个妙用 科技爱好者周刊(第 366 期):旧金山疯狂的 AI 广告 科技爱好者周刊(第 365 期):流量变现正在崩塌 科技爱好者周刊(第 364 期):最难还原的魔方 科技爱好者周刊(第 363 期):最好懂的神经网络解释 科技爱好者周刊(第 362 期):GitHub 工程师谈系统设计 科技爱好者周刊(第 361 期):暗网 Tor 安全吗?
響應式圖像教程
阮一峰 · 2019-06-10 · via 阮一峰的网络日志

網頁在不同尺寸的設備上,都有良好的顯示效果,叫做"響應式設計"(responsive web design)。

響應式設計的網頁圖像,就是"響應式圖像"(responsive image)。

響應式圖像的解決方案有很多,JavaScript 和 CSS 都可以實現。本文介紹最簡單的、語義性最好的 HTML 方法,瀏覽器原生支持。

一、問題的由來

我們知道,<img>標籤用於插入網頁圖像,所有情況默認插入的都是同一張圖像。


<img src="foo.jpg">

上面代碼在桌面端和手機上,插入的都是圖像文件foo.jpg

這種處理方法固然簡單,但是有三大弊端。

(1)體積

一般來說,桌面端顯示的是大尺寸的圖像,文件體積較大。手機的屏幕較小,只需要小尺寸的圖像,可以節省帶寬,加速網頁渲染。

(2)像素密度

桌面顯示器一般是單倍像素密度,而手機的顯示屏往往是多倍像素密度,即多個像素合成為一個像素,稱為 Retina 屏幕。圖像文件很可能在桌面端很清晰,放到手機上會有點模糊,因為像素擴充了。

(3)視覺風格

桌面顯示器的面積較大,圖像可以容納更多細節。手機的屏幕較小,許多細節是看不清的,需要突出重點。

上面兩張圖片,下方的手機圖片經過裁剪以後,更突出圖像重點,明顯效果更好。

二、像素密度的選擇:srcset屬性

為了解決上一節的這些問題,HTML 語言提供了一套完整的解決方案。首先,<img>標籤引入了srcset屬性。

srcset屬性用來指定多張圖像,適應不同像素密度的屏幕。它的值是一個逗號分隔的字符串,每個部分都是一張圖像的 URL,後面接一個空格,然後是像素密度的描述符。請看下面的例子。


<img srcset="foo-320w.jpg,
             foo-480w.jpg 1.5x,
             foo-640w.jpg 2x"
     src="foo-640w.jpg">
 

上面代碼中,srcset屬性給出了三個圖像 URL,適應三種不同的像素密度。

圖像 URL 後面的像素密度描述符,格式是像素密度倍數 + 字母x1x表示單倍像素密度,可以省略。瀏覽器根據當前設備的像素密度,選擇需要加載的圖像。

如果srcset屬性都不滿足條件,那麼就加載src屬性指定的默認圖像。

三、圖像大小的選擇:srcset屬性 + sizes屬性

像素密度的適配,只適合顯示區域一樣大小的圖像。如果希望不同尺寸的屏幕,顯示不同大小的圖像,srcset屬性就不夠用了,必須搭配sizes屬性。

第一步,srcset屬性列出所有可用的圖像。


<img srcset="foo-160.jpg 160w,
             foo-320.jpg 320w,
             foo-640.jpg 640w,
             foo-1280.jpg 1280w"
     src="foo-1280.jpg">

上面代碼中,srcset屬性列出四張可用的圖像,每張圖像的 URL 後面是一個空格,再加上寬度描述符。

寬度描述符就是圖像原始的寬度,加上字符w。上例的四種圖片的原始寬度分別為160像素、320像素、640像素和1280像素。

第二步,sizes屬性列出不同設備的圖像顯示寬度。

sizes屬性的值是一個逗號分隔的字符串,除了最後一部分,前面每個部分都是一個放在括號裡面的媒體查詢表達式,後面是一個空格,再加上圖像的顯示寬度。


<img srcset="foo-160.jpg 160w,
             foo-320.jpg 320w,
             foo-640.jpg 640w,
             foo-1280.jpg 1280w"
     sizes="(max-width: 440px) 100vw,
            (max-width: 900px) 33vw,
            254px"
     src="foo-1280.jpg">

上面代碼中,sizes屬性給出了三種屏幕條件,以及對應的圖像顯示寬度。寬度不超過440像素的設備,圖像顯示寬度為100%;寬度441像素到900像素的設備,圖像顯示寬度為33%;寬度900像素以上的設備,圖像顯示寬度為254px

第三步,瀏覽器根據當前設備的寬度,從sizes屬性獲得圖像的顯示寬度,然後從srcset屬性找出最接近該寬度的圖像,進行加載。

假定當前設備的屏幕寬度是480px,瀏覽器從sizes屬性查詢得到,圖片的顯示寬度是33vw(即33%),等於160pxsrcset屬性裡面,正好有寬度等於160px的圖片,於是加載foo-160.jpg

注意,sizes屬性必須與srcset屬性搭配使用。單獨使用sizes屬性是無效的。

四、<picture>標籤,<source>標籤

上面兩節分別解決了像素密度和屏幕大小的適配,但是如果要同時適配不同像素密度、不同大小的屏幕,應該怎麼辦呢?

這時,就要用到<picture>標籤。它是一個容器標籤,內部使用<source><img>,指定不同情況下加載的圖像。


<picture>
  <source media="(max-width: 500px)" srcset="cat-vertical.jpg">
  <source media="(min-width: 501px)" srcset="cat-horizontal.jpg">
  <img src="cat.jpg" alt="cat">
</picture>

上面代碼中,<picture>標籤內部有兩個<source>標籤和一個<img>標籤。

<source>標籤的media屬性給出媒體查詢表達式,srcset屬性就是<img>標籤的srcset屬性,給出加載的圖像文件。sizes屬性其實這裡也可以用,但由於有了media屬性,就沒有必要了。

瀏覽器按照<source>標籤出現的順序,依次判斷當前設備是否滿足media屬性的媒體查詢表達式,如果滿足就加載srcset屬性指定的圖片文件,並且不再執行後面的<source>標籤和<img>標籤。

<img>標籤是默認情況下加載的圖像,用來滿足上面所有<source>都不匹配的情況。

上面例子中,設備寬度如果不超過500px,就加載豎屏的圖像,否則加載橫屏的圖像。

下面給出一個例子,同時考慮屏幕尺寸和像素密度的適配。


<picture>
  <source srcset="[email protected],
                  [email protected] 2x"       
          media="(min-width: 990px)">
  <source srcset="[email protected],
                  [email protected] 2x" 
          media="(min-width: 750px)">
  <img srcset="[email protected],
               [email protected] 2x" 
       alt="Shopify Merchant, Corrine Anestopoulos">
</picture>

上面代碼中,<source>標籤的media屬性給出屏幕尺寸的適配條件,每個條件都用srcset屬性,再給出兩種像素密度的圖像 URL。

五、<source>標籤的type屬性

除了響應式圖像,<picture>標籤還可以用來選擇不同格式的圖像。比如,如果當前瀏覽器支持 Webp 格式,就加載這種格式的圖像,否則加載 PNG 圖像。


<picture>
  <source type="image/svg+xml" srcset="logo.xml">
  <source type="image/webp" srcset="logo.webp"> 
  <img src="logo.png" alt="ACME Corp">
</picture>

上面代碼中,<source>標籤的type屬性給出圖像的 MIME 類型,srcset是對應的圖像 URL。

瀏覽器按照<source>標籤出現的順序,依次檢查是否支持type屬性指定的圖像格式,如果支持就加載圖像,並且不再檢查後面的<source>標籤了。上面例子中,圖像加載優先順序依次為 svg 格式、webp 格式和 png 格式。

六、參考鏈接

(完)