ข้ามไปยังเนื้อหา

Images & Assets

ในหน้าเว็บส่วนใหญ่ image คือ bytes ที่ใหญ่ที่สุดบนสาย — hero photo ที่ไม่ optimize อาจหนักกว่า HTML, CSS และ JavaScript รวมกัน Astro มี image pipeline อยู่ในโมดูล astro:assets ที่มีมาให้ในตัว เราจึงได้ format สมัยใหม่, dimension ที่ถูกต้อง และ lazy loading โดยไม่ต้องทำเอง

เมื่อ import local image เข้ามาแล้ว render ด้วย <Image /> Astro จะ process ภาพนั้นตอน build time — แปลงเป็น format ที่มีประสิทธิภาพ (เช่น WebP/AVIF) และบังคับให้ระบุ width/height เพื่อให้ browser จองพื้นที่ไว้ (ไม่มี layout shift):

---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.png'; // a local import
---
<Image src={heroImage} alt="A mountain at sunrise" width={800} height={400} />

สิ่งที่ <Image /> ทำแต่ <img> ธรรมดาไม่ทำ:

  • optimize ไฟล์ — re-encode เป็น format สมัยใหม่ที่เล็กกว่าอัตโนมัติ
  • ป้องกัน layout shift — บังคับ width/height (infer มาจาก local import) พื้นที่จึงถูกจองก่อน image โหลด
  • lazy-load โดย default — ใส่ loading="lazy" และ decoding="async" ให้ image ที่อยู่นอกจอไม่ block การ render แรก

สำหรับ local import Astro รู้ dimension จริงอยู่แล้ว เราจึงละ width/height ได้และจะเติมให้เอง

เมื่ออยากให้ browser เลือก format เอง หรือ serve crop ต่างกันในแต่ละ breakpoint ให้ใช้ <Picture /> ซึ่ง render ออกมาเป็น element <picture> ที่มีหลาย <source>:

---
import { Picture } from 'astro:assets';
import hero from '../assets/hero.png';
---
<Picture src={hero} formats={['avif', 'webp']} alt="Sunrise" width={800} height={400} />

browser เลือก format แรกที่รองรับ (AVIF แล้วค่อย WebP) และ fallback ไปที่ต้นฉบับ — ได้ compression ที่ดีที่สุดเท่าที่ browser ของผู้ชมแต่ละคนรับได้

  • local image (import จาก src/) ถูก optimize เต็มที่และรู้ dimension — ควรใช้แบบนี้เสมอ
  • image ใน public/ ถูก serve ตามเดิม ไม่ optimize (Astro ไม่แตะ public/ เลย) ใช้เฉพาะกับของที่ต้องคง path/ชื่อไว้เป๊ะ ๆ
  • remote image (URL) optimize ได้เหมือนกัน แต่ต้อง list domain เป็น authorized ใน astro.config.mjs (image.domains หรือ image.remotePatterns) — เป็นมาตรการความปลอดภัยไม่ให้เรา proxy host มั่วซั่ว
flowchart TB
  local["Imported from src/"] --> opt["Optimized, dimensions known"]
  remote["Remote URL"] --> auth["Optimized only if domain is authorized"]
  pub["In public/"] --> asis["Served as-is, not optimized"]
Where an image comes from decides how it's handled

font คืออีก asset ใหญ่ที่ render-blocking Fonts API ของ Astro มี component <Font /> (จาก astro:assets) ที่ download, self-host และ optimize web font ตอน build time — สร้าง @font-face rule และ preload ที่ถูกต้อง — เราจึงเลี่ยง request ไป font ของ third-party และ layout shift ที่ตามมา เรา config font family ใน astro.config.mjs แล้ววาง <Font /> ใน head

component `<Image />` ทำอะไรที่ `<img>` ธรรมดาไม่ทำ?
ควรใช้ `<Picture />` แทน `<Image />` เมื่อไร?
image ที่วางในโฟลเดอร์ `public/` ถูกจัดการยังไง?
จะ optimize remote image จาก URL ต้องมีอะไร?