ข้ามไปเนื้อหาหลัก

Category: guide

Core Web Vitals — ทำ Static Site ให้ได้คะแนนสูง

แนวทางปรับ LCP, CLS, INP สำหรับ static site บน Astro ที่ทำได้จริงโดยไม่ต้องจ้างผู้เชี่ยวชาญ

· อ่านประมาณ 2 นาที

สารบัญ

ทำไม Core Web Vitals ถึงสำคัญ

Google ใช้ Core Web Vitals เป็น ranking signal ตั้งแต่ปี 2021 ยิ่งไปกว่านั้น ตัวเลขพวกนี้สะท้อนประสบการณ์ผู้ใช้ตรงๆ ถ้า LCP ช้า คนจะออกก่อนที่หน้าจะโหลดเสร็จ

3 Metrics หลัก

Metricย่อมาจากวัดอะไรเป้าหมาย
LCPLargest Contentful Paintความเร็วของ element ที่ใหญ่สุด≤ 2.5s
CLSCumulative Layout Shiftการขยับ layout โดยไม่ตั้งใจ≤ 0.1
INPInteraction to Next Paintความเร็วตอบสนองต่อ interaction≤ 200ms

LCP — ทำให้ไวขึ้น

1. Preload รูปภาพ Hero

<link rel="preload" as="image" href="/hero.jpg" fetchpriority="high" />

ใน Astro:

<Fragment slot="head">
  <link rel="preload" as="image" href="/og-image.svg" fetchpriority="high" />
</Fragment>

2. ใช้ font-display: swap

@font-face {
  font-family: 'Inter';
  font-display: swap; /* แสดง fallback font ก่อน แล้วสลับเมื่อโหลดเสร็จ */
  src: url('/fonts/inter.woff2') format('woff2');
}

3. Self-host ฟอนต์แทน Google Fonts

Google Fonts เพิ่ม round-trip HTTP เสมอ ดาวน์โหลดและ host เองจะเร็วกว่า:

# ใช้ fontsource ใน npm ecosystem
npm install @fontsource/inter
---
import '@fontsource/inter/400.css';
import '@fontsource/inter/700.css';
---

4. ปรับขนาด image ให้พอดี

<img
  src="/hero.jpg"
  width="1200"
  height="630"
  loading="eager"
  decoding="async"
  alt="..."
/>

ระบุ width และ height เสมอเพื่อกัน CLS ด้วย

CLS — ป้องกัน Layout Shift

สาเหตุหลัก

  1. รูปไม่มี dimension — เบราว์เซอร์ไม่รู้จะจองพื้นที่เท่าไหร่ก่อนโหลด
  2. ฟอนต์ swap ทำให้ขนาดข้อความเปลี่ยน — ใช้ size-adjust CSS descriptor แก้ได้
  3. Ads/embeds ที่ไม่มี placeholder

แก้ด้วย aspect-ratio

/* แทน width/height บน img โดยตรง */
.hero-image {
  aspect-ratio: 16 / 9;
  width: 100%;
  object-fit: cover;
}

ระวัง Custom Font FOUT

@font-face {
  font-family: 'Inter';
  font-display: optional; /* ถ้าโหลดไม่ทันใน 100ms ใช้ fallback ไปเลย — CLS = 0 */
}

INP — ปรับ Interaction

INP แทน FID ตั้งแต่ March 2024 วัดทุก interaction ไม่ใช่แค่ first click

หลักการ

  • Event handler ควรเสร็จภายใน 50ms
  • งานหนักให้ยก offload ไปใน setTimeout หรือ Web Worker
  • ใช้ content-visibility: auto กับ sections ที่อยู่ล่าง fold
/* Browser จะ skip rendering ของ section ที่ไม่ได้อยู่ในหน้าจอ */
.long-section {
  content-visibility: auto;
  contain-intrinsic-size: 0 500px; /* estimate size เพื่อกัน scrollbar กระโดด */
}

วัดผลด้วย Tools

# ใช้ Lighthouse CLI
npm install -g lighthouse
lighthouse https://panupongws.com --view

# หรือใช้ PageSpeed Insights
# https://pagespeed.web.dev/

Astro-specific Tips

Astro ทำหลายอย่างให้อัตโนมัติแล้ว:

  • Zero JS by default — ไม่มี hydration overhead เหมือน React/Vue
  • Built-in CSS bundling — CSS ถูก inline ใน <head> อัตโนมัติ
  • Static HTML — ไม่ต้องรอ JS parse ก่อน render
  • <Image /> component — auto-resize, WebP conversion, lazy loading

เพิ่มเติมที่ต้องทำเอง: self-host fonts, preload hero image, ระบุ width/height บนทุก <img>