跳到主要內容

圖片、背景與 CSS 造型

圖片格式與尺寸怎麼選、背景圖上的文字怎麼保證看得見、不用圖片就能做出來的十種背景,以及紋理與遮罩。

約 7 分鐘 · imagery-and-backgrounds.md

1. 圖片的四件必做

一、一定要有尺寸

<img src="hero.avif" width="1600" height="900" alt="…" />

有了寬高,瀏覽器在圖片載入前就能保留空間。沒有的話,圖片一到位就把下面的內容往下推(CLS)。

不知道原始尺寸時用 aspect-ratio

.thumb { aspect-ratio: 16 / 9; object-fit: cover; }

二、格式順序

<picture>
  <source srcset="hero.avif" type="image/avif" />
  <source srcset="hero.webp" type="image/webp" />
  <img src="hero.jpg" width="1600" height="900" alt="…" />
</picture>

AVIF 通常比 JPEG 小 50%,WebP 小 30%。照片用 AVIF/WebP,圖示與 logo 用 SVG(無限清晰、可以吃 CSS 變數換色)。

三、responsive srcset

<img
  src="hero-800.avif"
  srcset="hero-400.avif 400w, hero-800.avif 800w, hero-1600.avif 1600w"
  sizes="(max-width: 700px) 100vw, 50vw"
  width="1600" height="900" alt="…" />

沒有 sizes 的話瀏覽器會假設圖片滿版,於是手機也下載大圖。

四、載入優先序

  • 首屏主視覺:fetchpriority="high"不要 loading="lazy"
  • 其他全部:loading="lazy" decoding="async"

對首屏圖片加 lazy 是常見的反效果 —— 它會讓 LCP 變慢。

2. alt 怎麼寫

圖片類型 alt
純裝飾 alt=""(空字串,不是省略)
有資訊 描述資訊,不是描述畫面
圖片就是連結 描述連結會去哪裡
圖表 講結論:「營收從 1 月的 120 萬成長到 6 月的 310 萬」

alt="" 和沒有 alt 不一樣:前者是「這張圖可以跳過」,後者會讓螢幕閱讀器唸出檔名。

3. 背景圖上的文字

永遠不要直接把文字放在照片上。 照片的亮度會變,文字一定會在某個裝置上讀不到。

三種處理,依強度排序:

一、漸層 scrim(最常用)

.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    190deg,
    color-mix(in srgb, var(--ds-canvas) 72%, transparent) 0%,
    color-mix(in srgb, var(--ds-canvas) 22%, transparent) 46%,
    transparent 70%
  );
}

color-mix() 讓 scrim 跟著主題色走,換深色主題時不需要另外寫一套。

二、文字自帶底:黑色圓角長條加白字。清楚、可預測,也是 Neon Ink 用的手法。

三、模糊局部backdrop-filter: blur(8px) 加半透明底。漂亮但耗效能,只用在小面積。

不要用 text-shadow 當唯一手段 —— 在複雜背景上仍然讀不清,而且會讓文字看起來髒。

4. 不用圖片的背景

網點(半調)

background-image: radial-gradient(currentColor 1px, transparent 1.2px);
background-size: 14px 14px;
opacity: 0.06;

方格紙

background-image:
  linear-gradient(var(--ds-line) 1px, transparent 1px),
  linear-gradient(90deg, var(--ds-line) 1px, transparent 1px);
background-size: 32px 32px;

斜線

background: repeating-linear-gradient(
  45deg,
  var(--ds-line) 0 1px,
  transparent 1px 10px
);

光暈

background:
  radial-gradient(900px 500px at 12% -8%, rgb(124 92 255 / 0.2), transparent 62%),
  radial-gradient(700px 420px at 92% 8%, rgb(34 211 238 / 0.12), transparent 60%);

一個光源比三個好。 多個光源會讓畫面沒有方向感。

紙紋(SVG 雜訊,零請求)

--ds-texture: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='160' height='160' filter='url(%23n)' opacity='0.05'/></svg>");

注意 #n 在 data URI 裡必須寫成 %23n,否則會被當成 fragment。

漸層邊框

.gradient-border {
  border: 1px solid transparent;
  background:
    linear-gradient(var(--ds-surface), var(--ds-surface)) padding-box,
    linear-gradient(135deg, var(--ds-accent), transparent) border-box;
}

遮罩淡出

.fade-bottom {
  mask-image: linear-gradient(to bottom, #000 60%, transparent);
}

用在插畫出血、長清單的下緣、無限捲動的邊界。

5. SVG 插畫

SVG 的最大優勢是它會跟著主題換色

.art .ink { fill: var(--ds-ink); }
.art .blast { fill: var(--ds-accent); }

一份插畫,六種風格都對,不需要六個匯出檔。

程序生成的圖形要確定性,不要用 Math.random() —— 伺服器和瀏覽器會產生不同結果,hydration 會警告,畫面也會跳。用固定的資料陣列。

6. 效能預算

項目 上限
首屏所有圖片 250KB
單張主視覺 150KB
圖示 一律 SVG inline 或 sprite
字型檔 兩個家族,各 ≤ 2 個字重

檢查方式:DevTools → Network → 篩選 Img → 看 transferred 總量。

7. 檢查清單

  • 每張圖都有 width heightaspect-ratio
  • 有 AVIF / WebP,JPEG 只當 fallback
  • srcsetsizes
  • 首屏圖 fetchpriority="high" 且沒有 lazy
  • 其他圖 loading="lazy" decoding="async"
  • 裝飾圖 alt="",資訊圖有真正的描述
  • 背景上的文字有 scrim 或自帶底
  • 能用 CSS 做的紋理沒有用圖片
  • 程序生成的圖形是確定性的

顯示設定

這裡改的每一項,會即時套用到站上所有預覽。

風格

密度

圓角

動態

系統層級的「減少動態效果」永遠優先於這裡的設定。

語言