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

Responsive Images

รูปภาพคือสาเหตุที่พบบ่อยที่สุดของ Responsive Layout ที่พัง ภาพถ่ายกว้าง 1200 px ที่วางลงในหน้าจอโทรศัพท์ขนาด 375 px จะล้นออกและทำให้เลื่อนหน้าจอซ้าย-ขวา การแก้ไขคือ CSS หนึ่งบรรทัด แต่การเข้าใจว่า ทำไม ถึงได้ผล (และจะไปต่อได้อย่างไร) ทำให้คุณเป็น Designer-Developer ที่ดีขึ้นมาก

img {
max-width: 100%;
height: auto;
}
  • max-width: 100% — รูปภาพจะกว้างกว่า Container ไม่ได้ ถ้า Container ย่อ รูปภาพก็ย่อตาม
  • height: auto — Browser คำนวณความสูงใหม่โดยอัตโนมัติเพื่อรักษา Aspect Ratio ถ้าไม่ใส่ รูปภาพจะยืดในแนวตั้ง

สิ่งนี้สำคัญมากจนส่วนใหญ่ CSS Reset และ Framework (เช่น Tailwind) ใส่ไว้ให้เป็น Default แล้ว

Preview แสดงรูปภาพสองใบ (แทนด้วยกล่องสีเพื่อการสาธิต) ใบแรกไม่มี max-width Constraint ใบที่สองมี max-width: 100% ย่อ Preview Pane เพื่อดูสิ่งที่เกิดขึ้น

เมื่อ Pane แคว กล่องสีแดงล้น Container — นั่นคือสิ่งที่รูปภาพขนาดตายตัวทำบนมือถือ กล่องสีเขียวเคารพขอบ Container และย่อตัวอย่างสวยงาม

max-width: 100% ทำให้รูปภาพ ดูเล็กลง บนหน้าจอเล็ก แต่ไม่ได้ทำให้ไฟล์เล็กลง ภาพถ่ายขนาด 3 MB ยังคงเป็น 3 MB แม้จะแสดงที่ความกว้าง 375 px — เพียงแต่มาช้าๆ ผ่าน Connection มือถือที่ช้า

Attribute srcset ให้คุณระบุหลายเวอร์ชันของรูปภาพ Browser จะเลือกเวอร์ชันที่เหมาะสมกับอุปกรณ์:

<img
src="hero-800.jpg"
srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1600.jpg 1600w"
sizes="(max-width: 480px) 100vw, 800px"
alt="Hero image description"
/>
  • 400w, 800w, 1600w — ความกว้างจริงของแต่ละไฟล์เป็น Pixels
  • sizes — บอก Browser ว่ารูปภาพจะแสดงกว้างแค่ไหนที่ Breakpoint ต่างๆ เพื่อให้เลือก Source ที่เหมาะสมก่อนดาวน์โหลด

คุณไม่ต้องเขียน srcset ด้วยตนเองในโปรเจกต์ส่วนใหญ่ — Tools อย่าง Next.js <Image>, Astro <Image> หรือ Cloudinary จัดการให้อัตโนมัติ สิ่งสำคัญคือเข้าใจแนวคิด: Export รูปภาพหลายขนาด และให้ Browser เลือก

เมื่อต้องการแสดง Crop หรือ Composition ที่ต่างกัน บน Mobile กับ Desktop (ไม่ใช่แค่เวอร์ชันเล็กกว่าของรูปเดิม) ให้ใช้ Element <picture>:

<picture>
<source media="(max-width: 480px)" srcset="hero-portrait.jpg" />
<img src="hero-landscape.jpg" alt="Hero image" />
</picture>

นี่คือ Code Equivalent ของการมี Image Crop ต่างกันใน Mobile และ Desktop Artboard ของ Figma โดยตรง

  • ใช้รูปเดียวกัน (ขนาดใหญ่สุด) กับทุกหน้าจอ ทำให้มือถือโหลดหนักเกินจำเป็น
  • ลืมกำหนด width/height ทำให้เกิด layout shift ตอนรูปกำลังโหลด

Designer ส่งไฟล์รูป 1 ไฟล์ความละเอียดสูงสุด แต่ developer ต้อง generate หลาย size (srcset) ให้ browser เลือกไฟล์ที่เหมาะกับหน้าจอนั้นเอง

💡 ตัวอย่างจากของจริง

Airbnb serve รูปที่ปรับ resolution ตามอุปกรณ์อัตโนมัติผ่าน CDN ทำให้มือถือโหลดไฟล์เล็กกว่า desktop หลายเท่าโดยที่ดูเหมือนกัน

`max-width: 100%` บนรูปภาพทำอะไร?
ทำไมต้องเพิ่ม `height: auto` ร่วมกับ `max-width: 100%`?
ความแตกต่างระหว่าง srcset กับ max-width: 100% คืออะไร?
เมื่อไรถึงจะใช้ Element `<picture>` แทน `srcset`?