The ADDs
เทคโนโลยี9 นาที·

ทำเว็บให้เร็วจริง: Core Web Vitals อธิบายง่ายๆ และแนวปฏิบัติสำหรับ Next.js

เว็บที่ช้าทำให้คนปิดหน้าไปก่อนจะเห็นสินค้า และ Google เองก็นำประสบการณ์การใช้งานมาเป็นสัญญาณหนึ่งในการจัดอันดับ บทความนี้อธิบายตัวชี้วัด Core Web Vitals ทั้งสามตัวด้วยภาษาที่ไม่ต้องเป็นสายเทคนิคก็เข้าใจ แล้วไล่ดูว่าอะไรทำให้เว็บหนัก และแก้ได้อย่างไรโดยเฉพาะบน Next.js

H

ทีม Haliviq

สตูดิโอผลิตภัณฑ์ดิจิทัล กรุงเทพฯ

ทำเว็บให้เร็วจริง: Core Web Vitals อธิบายง่ายๆ และแนวปฏิบัติสำหรับ Next.js

Core Web Vitals วัดอะไรบ้าง

Core Web Vitals คือชุดตัวชี้วัดที่ Google กำหนดเพื่อวัดประสบการณ์ของคนที่เปิดเว็บจริงๆ ปัจจุบันมีสามตัว ตัวแรกคือ LCP (Largest Contentful Paint) วัดว่ากว่าองค์ประกอบใหญ่ที่สุดในหน้าจอแรก เช่น ภาพหลักหรือหัวข้อ จะขึ้นครบใช้เวลานานแค่ไหน เกณฑ์ที่ถือว่าดีคือไม่เกิน 2.5 วินาที

ตัวที่สองคือ CLS (Cumulative Layout Shift) วัดว่าเนื้อหาในหน้าขยับเลื่อนไปมาโดยผู้ใช้ไม่ได้ตั้งใจแค่ไหน ลองนึกถึงตอนกำลังจะกดปุ่ม แล้วโฆษณาหรือภาพโหลดเสร็จดันปุ่มหนีไป เกณฑ์ที่ดีคือไม่เกิน 0.1 ตัวที่สามคือ INP (Interaction to Next Paint) วัดว่าหลังผู้ใช้กด แตะ หรือพิมพ์ หน้าเว็บตอบสนองให้เห็นผลช้าแค่ไหน เกณฑ์ที่ดีคือไม่เกิน 200 มิลลิวินาที

INP เข้ามาแทน FID (First Input Delay) อย่างเป็นทางการในปี 2024 ความต่างสำคัญคือ FID วัดแค่ความหน่วงของการโต้ตอบครั้งแรก ส่วน INP ดูการโต้ตอบตลอดการใช้งานหน้านั้น จึงจับปัญหาอย่างเมนูที่กดแล้วค้าง หรือฟอร์มที่พิมพ์แล้วกระตุกได้ดีกว่ามาก

ภาพ ฟอนต์ และ JavaScript: ตัวการน้ำหนักเกิน

ในเว็บส่วนใหญ่ ภาพคือไฟล์ที่ใหญ่ที่สุด และมักเป็นองค์ประกอบ LCP ด้วย ปัญหาที่พบบ่อยคืออัปโหลดภาพจากกล้องหรือดีไซน์ขนาดเต็มมาใช้ตรงๆ แล้วให้เบราว์เซอร์ย่อเอง ควรส่งขนาดที่พอดีกับหน้าจอแต่ละเครื่อง ใช้รูปแบบสมัยใหม่อย่าง WebP หรือ AVIF และกำหนดความกว้างความสูงไว้ล่วงหน้าเพื่อกัน CLS

ฟอนต์ก็มีผล โดยเฉพาะเว็บภาษาไทยที่ไฟล์ฟอนต์มักใหญ่กว่าฟอนต์ละติน ให้เลือกน้ำหนักตัวอักษรเท่าที่ใช้จริง โหลดจากโดเมนเดียวกับเว็บ และตั้ง font-display ให้ข้อความขึ้นก่อนแล้วค่อยสลับฟอนต์ เพื่อไม่ให้หน้าว่างระหว่างรอ ส่วน JavaScript เป็นต้นเหตุหลักของ INP เพราะเบราว์เซอร์ต้องดาวน์โหลด แปลง และรันก่อนหน้าจึงตอบสนองได้

สคริปต์ของบุคคลที่สาม เช่น แชตวิดเจ็ต แท็กโฆษณา และเครื่องมือวิเคราะห์ มักถูกลืมนับ ทั้งที่รวมกันแล้วหนักไม่แพ้โค้ดของเราเอง ลองตรวจเป็นระยะว่าตัวไหนยังจำเป็นอยู่

  • ภาพ: ขนาดพอดี รูปแบบ WebP หรือ AVIF กำหนด width และ height เสมอ
  • ฟอนต์: ใช้เท่าที่จำเป็น โหลดจากโดเมนตัวเอง ตั้ง font-display
  • JavaScript: ส่งเฉพาะโค้ดที่หน้านั้นใช้ และแยกส่วนที่ไม่จำเป็นออกไปโหลดทีหลัง
  • สคริปต์ภายนอก: โหลดแบบ async หรือหลังผู้ใช้โต้ตอบ และลบตัวที่เลิกใช้
แผนภาพตัวชี้วัด LCP, CLS และ INP ตามช่วงเวลาที่ผู้ใช้เปิดหน้าเว็บและโต้ตอบ
แผนภาพตัวชี้วัด LCP, CLS และ INP ตามช่วงเวลาที่ผู้ใช้เปิดหน้าเว็บและโต้ตอบ

แคช: ทำให้งานเดิมไม่ต้องทำซ้ำ

วิธีที่เร็วที่สุดในการตอบหน้าเว็บคือไม่ต้องสร้างใหม่ ไฟล์ static อย่างภาพ CSS และ JavaScript ควรตั้ง Cache-Control ให้เบราว์เซอร์เก็บไว้นาน โดยใช้ชื่อไฟล์ที่มี hash ต่อท้าย เมื่อไฟล์เปลี่ยนชื่อก็เปลี่ยนตาม ผู้ใช้จึงได้ของใหม่ทันทีโดยไม่ต้องรอแคชหมดอายุ

สำหรับหน้าที่เนื้อหาไม่เปลี่ยนทุกวินาที เช่น บทความ หน้าบริการ หรือหน้าสินค้า การสร้างหน้าล่วงหน้าแล้วเสิร์ฟผ่าน CDN ทำให้ผู้ใช้ในกรุงเทพฯ ได้ไฟล์จากเซิร์ฟเวอร์ใกล้ตัว ไม่ต้องวิ่งไปไกลถึงต้นทาง และลดภาระฐานข้อมูลไปด้วย ส่วนข้อมูลที่เปลี่ยนบ่อยค่อยกำหนดอายุแคชสั้นๆ หรือสั่งล้างแคชเมื่อมีการแก้ไข

แนวปฏิบัติบน Next.js

Next.js มีเครื่องมือที่ช่วยเรื่องข้างต้นอยู่แล้ว คอมโพเนนต์ next/image ปรับขนาดและรูปแบบภาพตามอุปกรณ์ โหลดแบบ lazy และจองพื้นที่กัน CLS ส่วน next/font ฝังฟอนต์ไว้กับเว็บและลดการกระพริบตอนสลับฟอนต์ ภาพที่เป็น LCP ควรตั้ง priority เพื่อให้โหลดก่อน และอย่าใส่ lazy กับภาพบนสุดของหน้า

เรื่อง JavaScript แนวคิดของ Server Components ใน App Router คือให้คอมโพเนนต์ที่ไม่ต้องโต้ตอบรันบนเซิร์ฟเวอร์ ไม่ถูกส่งไปที่เบราว์เซอร์ ให้ใส่ 'use client' เฉพาะส่วนที่ต้องมีสถานะหรือ event จริงๆ ส่วนที่หนักและไม่ต้องเห็นทันที เช่น แผนที่ หรือกราฟ ใช้ dynamic import แยกออกไป และใช้ Suspense เพื่อให้ส่วนที่พร้อมแล้วแสดงก่อน

สุดท้ายอย่าลืมดูผลของ library ที่ติดตั้ง บางตัวเพิ่มขนาด bundle มากกว่าที่คิด การดู bundle analyzer สักครั้งก่อนปล่อยงานมักพบของที่ตัดทิ้งได้ง่ายๆ

ความเร็วไม่ใช่งานที่ทำครั้งเดียวตอนปิดโปรเจกต์ แต่เป็นนิสัยที่ต้องเช็กทุกครั้งที่เพิ่มของใหม่เข้าหน้า

ข้อมูลจากสนามจริง กับข้อมูลจากห้องแล็บ

Lighthouse และเครื่องมืออย่าง PageSpeed Insights ส่วนที่รันทดสอบเอง เป็น lab data คือจำลองอุปกรณ์และเครือข่ายหนึ่งแบบ รันซ้ำได้ เหมาะกับการหาสาเหตุและเทียบก่อนหลังแก้โค้ด แต่ไม่ได้บอกว่าผู้ใช้จริงพบอะไร เพราะคนเปิดเว็บด้วยมือถือรุ่นต่างๆ ผ่าน 4G ที่แรงไม่เท่ากัน

field data คือข้อมูลที่เก็บจากผู้เข้าชมจริง เช่น รายงาน Core Web Vitals ใน Search Console หรือ Chrome UX Report ซึ่ง Google ใช้ค่าที่เปอร์เซ็นไทล์ 75 ของผู้เข้าชม และเป็นข้อมูลที่ใกล้เคียงกับสิ่งที่นำไปประเมินจริง INP โดยเฉพาะต้องมีการโต้ตอบจริงจึงวัดได้ ถ้าอยากเห็นข้อมูลละเอียดกว่านั้น ติดตั้งไลบรารี web-vitals ส่งค่ากลับมาที่ระบบวิเคราะห์ของเราเองได้

วิธีทำงานที่ได้ผลคือใช้ field data หาว่าหน้าไหนมีปัญหา ใช้ lab data หาสาเหตุและลองแก้ แล้วกลับไปดู field data อีกรอบหลังปล่อย ซึ่งอาจต้องรอข้อมูลสะสมสักระยะ

สรุปสั้น ๆ

  • Core Web Vitals มีสามตัว: LCP วัดความเร็วการแสดงผล CLS วัดความนิ่ง และ INP วัดการตอบสนอง โดย INP แทน FID ตั้งแต่ปี 2024
  • ภาพ ฟอนต์ไทย JavaScript และสคริปต์ภายนอก คือสี่จุดที่ควรตรวจก่อน
  • ตั้งแคชให้ไฟล์ static และเสิร์ฟหน้าที่ไม่เปลี่ยนบ่อยผ่าน CDN
  • บน Next.js ใช้ next/image, next/font, Server Components และ dynamic import ให้เป็นนิสัย
  • ใช้ field data หาปัญหา ใช้ lab data หาสาเหตุ แล้วกลับมาเช็ก field data หลังแก้

คำถามที่พบบ่อย

ไม่เสมอไป Lighthouse จำลองเครื่องและเครือข่ายแบบเดียว ผู้ใช้จริงอาจใช้มือถือรุ่นเก่าและสัญญาณไม่ดี จึงควรดู field data ใน Search Console ประกอบกันเสมอ

Next.js ให้เครื่องมือที่ดีมาให้ แต่ไม่ได้ทำแทนทั้งหมด ภาพขนาดใหญ่เกินจำเป็น สคริปต์ภายนอกหนักๆ หรือคอมโพเนนต์ฝั่ง client ที่มากเกินไปยังทำให้ช้าได้เหมือนเดิม

ดูรายงานใน Search Console ว่าตัวไหนไม่ผ่านในหน้าที่มีคนเข้ามากที่สุด แล้วเริ่มจากตรงนั้น ในหลายทีม LCP แก้ได้เร็วที่สุดเพราะมักเกี่ยวกับภาพหลักของหน้า

บริการที่เกี่ยวข้อง

Core Web VitalsNext.jsWeb PerformanceLCPINP

มีโปรเจกต์แบบนี้อยู่ในใจไหม

เล่าให้เราฟังว่าตอนนี้อยู่ตรงไหน เดี๋ยวเราแนะนำก้าวแรกที่เหมาะให้ โดยไม่มีข้อผูกมัด

คุยกับเรา