Astro Fonts: จัดการ Web Fonts อย่างมีประสิทธิภาพ
Astro Fonts: จัดการ Web Fonts อย่างมีประสิทธิภาพ
การจัดการ Web Fonts เป็นหนึ่งในปัจจัยสำคัญที่ส่งผลต่อ performance และ user experience ของเว็บไซต์ Astro มี built-in font optimization และรองรับการใช้งาน fonts จากหลายแหล่ง บทความนี้จะแนะนำวิธีการจัดการ fonts ใน Astro อย่างมีประสิทธิภาพ
ปัญหาของ Web Fonts
ก่อนจะเริ่ม ทำความเข้าใจปัญหาที่พบบ่อยกับ Web Fonts:
- FOUT (Flash of Unstyled Text): ข้อความแสดงด้วย fallback font ก่อน custom font โหลด
- FOIT (Flash of Invisible Text): ข้อความหายไปชั่วคราวระหว่างโหลด font
- Layout Shift: font ที่โหลดมาทีหลังทำให้ layout เลื่อน
- Performance: font files ขนาดใหญ่ทำให้ page โหลดช้า
Astro Font Optimization (v4+)
Astro 4.x มี experimental font optimization ในตัว:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
fonts: [
{
provider: 'google',
name: 'Sarabun',
cssVariable: '--font-sarabun',
},
{
provider: 'google',
name: 'Noto Sans Thai',
cssVariable: '--font-noto-thai',
},
],
},
});
ใช้งานใน layout:
---
import { fontFace } from 'astro:fonts';
---
<html>
<head>
<style is:global>
:root {
--font-sarabun: 'Sarabun', sans-serif;
}
body {
font-family: var(--font-sarabun);
}
</style>
</head>
</html>
ใช้ Google Fonts แบบ Manual
วิธีที่ง่ายที่สุดคือใช้ผ่าน <link> tag:
---
// src/layouts/BaseLayout.astro
---
<html lang="th">
<head>
<meta charset="UTF-8" />
<!-- Preconnect เพื่อเพิ่มความเร็ว -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<!-- โหลด font -->
<link
href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600;700&family=Noto+Sans+Thai:wght@300;400;500;700&display=swap"
rel="stylesheet"
/>
<style>
:root {
--font-body: 'Sarabun', 'Noto Sans Thai', sans-serif;
--font-heading: 'Sarabun', sans-serif;
}
body {
font-family: var(--font-body);
}
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-heading);
}
</style>
</head>
<body>
<slot />
</body>
</html>
Self-hosted Fonts
การ host fonts เองให้ performance ดีกว่าและไม่ต้องพึ่ง third-party:
# ดาวน์โหลด font files
mkdir -p public/fonts
# วาง .woff2 files ใน public/fonts/
สร้าง CSS สำหรับ font:
/* src/styles/fonts.css */
@font-face {
font-family: 'Sarabun';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/sarabun-regular.woff2') format('woff2');
unicode-range: U+0E00-U+0E7F; /* Thai characters */
}
@font-face {
font-family: 'Sarabun';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/sarabun-bold.woff2') format('woff2');
unicode-range: U+0E00-U+0E7F;
}
@font-face {
font-family: 'Sarabun';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/sarabun-latin-regular.woff2') format('woff2');
unicode-range: U+0000-U+00FF; /* Latin characters */
}
Import ใน layout:
---
import '../styles/fonts.css';
---
ใช้ fontsource Package
fontsource เป็น npm package ที่รวม fonts ไว้ให้ใช้งานได้ง่าย:
npm install @fontsource/sarabun
npm install @fontsource-variable/noto-sans-thai
Import ใน layout:
---
// Import เฉพาะ weights ที่ต้องการ
import '@fontsource/sarabun/300.css';
import '@fontsource/sarabun/400.css';
import '@fontsource/sarabun/500.css';
import '@fontsource/sarabun/700.css';
---
<style is:global>
body {
font-family: 'Sarabun', sans-serif;
}
</style>
Font Preloading
การ preload fonts ช่วยลด FOUT:
<head>
<!-- Preload critical fonts -->
<link
rel="preload"
href="/fonts/sarabun-regular.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link
rel="preload"
href="/fonts/sarabun-bold.woff2"
as="font"
type="font/woff2"
crossorigin
/>
</head>
Variable Fonts
Variable fonts ช่วยลดจำนวน font files:
@font-face {
font-family: 'Sarabun Variable';
font-style: normal;
font-weight: 100 900; /* รองรับทุก weight */
font-display: swap;
src: url('/fonts/sarabun-variable.woff2') format('woff2-variations');
}
:root {
--font-body: 'Sarabun Variable', sans-serif;
}
.light { font-weight: 300; }
.regular { font-weight: 400; }
.medium { font-weight: 500; }
.bold { font-weight: 700; }
.black { font-weight: 900; }
Font Loading Strategy
สร้าง utility สำหรับจัดการ font loading:
// src/utils/fontLoader.ts
export function createFontLoadObserver(fontFamily: string): Promise<void> {
return new Promise((resolve, reject) => {
if ('fonts' in document) {
document.fonts.load(`1em ${fontFamily}`).then(() => {
resolve();
}).catch(reject);
} else {
// Fallback for older browsers
setTimeout(resolve, 3000);
}
});
}
export async function waitForFonts(fonts: string[]): Promise<void> {
await Promise.all(fonts.map(createFontLoadObserver));
document.documentElement.classList.add('fonts-loaded');
}
ใช้งานใน script:
<script>
import { waitForFonts } from '../utils/fontLoader';
waitForFonts(['Sarabun', 'Noto Sans Thai']).then(() => {
console.log('Fonts loaded!');
});
</script>
Tailwind CSS กับ Custom Fonts
ถ้าใช้ Tailwind CSS:
// tailwind.config.mjs
export default {
theme: {
extend: {
fontFamily: {
sans: ['Sarabun', 'Noto Sans Thai', 'sans-serif'],
heading: ['Sarabun', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
},
},
};
สรุป
การจัดการ fonts ใน Astro มีหลายวิธีตั้งแต่ Google Fonts, self-hosted, ไปจนถึง fontsource packages การเลือกวิธีที่เหมาะสมขึ้นอยู่กับความต้องการด้าน performance, privacy, และความสะดวกในการ maintain สิ่งสำคัญคือใช้ font-display: swap และ preload critical fonts เพื่อให้ user experience ดีที่สุด