Category: guide
SVG Sprites & Icon System — icon ที่ maintain ง่ายและ accessible
วิธีสร้าง icon system ด้วย SVG sprite (symbol + use) และแนวทางทำ accessible icons ที่ถูกต้อง
สารบัญ
ปัญหาของ inline SVG ทุก icon
การ copy SVG ทุก icon เข้า HTML ตรงๆ ทำให้:
- HTML ยาวมาก อ่านยาก
- แก้ icon ต้องหาหลายที่
- browser โหลด SVG ซ้ำทุก instance (ถ้า embed ตรงๆ)
SVG Sprite Pattern (ใช้งานได้กับ Astro)
<!-- sprite.svg — โหลดครั้งเดียว ซ่อนไว้ -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none">
<symbol id="icon-arrow" viewBox="0 0 24 24">
<path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</symbol>
<symbol id="icon-check" viewBox="0 0 24 24">
<path d="M20 6L9 17l-5-5" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</symbol>
</svg>
<!-- ใช้ซ้ำได้ทุกที่ -->
<svg width="20" height="20" aria-hidden="true" focusable="false">
<use href="#icon-arrow" />
</svg>
Astro Component สำหรับ Icon
---
// src/components/Icon.astro
interface Props {
name: string;
size?: number;
label?: string; // ถ้ามี label = accessible icon; ถ้าไม่มี = decorative
}
const { name, size = 20, label } = Astro.props;
---
<svg
width={size}
height={size}
aria-label={label}
aria-hidden={label ? undefined : 'true'}
focusable="false"
role={label ? 'img' : undefined}
>
<use href={`/icons/sprite.svg#icon-${name}`} />
</svg>
<!-- Decorative icon (ข้างข้อความ) -->
<Icon name="arrow" size={16} />
<!-- Standalone icon (ปุ่มที่มีแค่ icon) -->
<button aria-label="ดูเพิ่มเติม">
<Icon name="arrow" label="ดูเพิ่มเติม" />
</button>
Accessibility Rules
| กรณี | วิธี |
|---|---|
| Icon ข้างข้อความ | aria-hidden="true" — text อธิบายอยู่แล้ว |
| Icon คนเดียวใน button | aria-label บน button หรือ <title> ใน SVG |
| Icon เป็นส่วนหนึ่งของ heading | aria-hidden="true" — heading text อธิบายอยู่แล้ว |
currentColor — ให้ icon ตาม text color
/* SVG ที่ใช้ currentColor จะเปลี่ยนสีตาม CSS color อัตโนมัติ */
.icon-btn { color: #2563eb; }
.icon-btn:hover { color: #1d4ed8; }
/* svg ใน .icon-btn จะเปลี่ยนสีตามโดยไม่ต้อง override */
สำคัญ: ใน SVG source ใช้ stroke="currentColor" และ fill="currentColor" ไม่ใช่ hardcode สี