- Critical CSS คือการดึงเฉพาะ CSS ขั้นต่ำที่จำเป็นต่อการเรนเดอร์ “ส่วนที่มองเห็นได้ทันทีเมื่อเปิดหน้าเว็บ (above the fold)” เท่านั้น และเมื่อนำไปใส่แบบ inline ใน HTML จะช่วยปรับปรุง Core Web Vitals เช่น FCP (First Contentful Paint) ได้
- ใส่แบบ inline ใน
<head> ของ HTML เพื่อให้เบราว์เซอร์เรนเดอร์คอนเทนต์ได้เร็วโดยไม่ต้องรอ stylesheet ทั้งหมด
- มีข้อดี เช่น ความเร็วในการโหลดที่ผู้ใช้รับรู้ได้ดีขึ้น, คะแนน Lighthouse สูงขึ้น, และ SEO กับ UX ดีขึ้น
- CSS ที่ไม่จำเป็นต่อการแสดงผลแรกสามารถโหลดด้วย
<link> ที่ท้าย <body> หรือ โหลดแบบหน่วงเวลาด้วย JavaScript เพื่อเพิ่มประสิทธิภาพได้อีก
- ควรทราบว่าผู้ใช้ต้องปรับพาธของลิงก์ CSS และการอ้างอิง asset ด้วยตนเอง
Critical CSS Generator
- Critical CSS Generator เป็นเครื่องมือที่ช่วยดึงเฉพาะโค้ด CSS ขั้นต่ำที่จำเป็นจริง ๆ จากหน้าเว็บ ทำให้สามารถแยก CSS ได้อย่างเหมาะกับวัตถุประสงค์การใช้งาน
- Critical CSS คือ กฎ CSS ขั้นต่ำที่จำเป็นสำหรับจัดสไตล์ส่วนที่มองเห็นได้ก่อนในหน้าเว็บ
- วิธีนี้ช่วยให้เบราว์เซอร์แสดงคอนเทนต์หลักได้ทันทีโดยไม่ต้องรอโหลด stylesheet ทั้งหมด จึงช่วยด้านประสิทธิภาพและปรับปรุง Core Web Vitals (เช่น FCP)
ทำไมจึงควรใช้?
- ความเร็วการโหลดเริ่มต้นที่รู้สึกได้ว่าเร็วขึ้น
- คะแนน Lighthouse ดีขึ้น
- ปรับปรุง SEO และประสบการณ์ผู้ใช้
🔧 วิธีนำไปใช้
Step 1: ทำ Critical CSS เป็น inline
Step 2: โหลด CSS ที่ไม่จำเป็นแบบหน่วงเวลา (วิธีพื้นฐาน)
Step 3 (ตัวเลือก): โหลดสไตล์แบบอะซิงโครนัสด้วย JavaScript
- หลังหน้าเว็บโหลดเสร็จ ให้ใช้ JavaScript เพื่อ โหลด CSS ที่ไม่จำเป็นแบบไดนามิก
- อาจช่วยเพิ่มประสิทธิภาพได้เมื่อความเร็วเครือข่ายต่ำ
- ต้องลบ
<link> ของ CSS ที่ไม่จำเป็นทั้งหมดออกจาก <head> เดิม
window.addEventListener("DOMContentLoaded", function () {
console.log("✅ Page loaded, now loading non-critical stylesheets...");
let stylesheets = [
// "/css/vendors.min.css",
// "/css/style.min.css",
];
let loadedCount = 0;
function checkAllStylesLoaded() {
loadedCount++;
if (loadedCount === stylesheets.length) {
console.log("✅ All non-critical stylesheets loaded...");
}
}
stylesheets.forEach(function (href) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = href;
link.onload = checkAllStylesLoaded;
link.onerror = () => console.warn(`Failed to load stylesheet: ${href}`);
document.head.appendChild(link);
});
});
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ถ้ารองรับ responsive ได้ด้วยก็น่าจะยอดเยี่ยม เพราะที่ผ่านมา dedupe สไตล์แบบ critical สำหรับ responsive ทำได้ยาก เลยสุดท้ายต้องมานั่งแก้ stylesheet เองอยู่เรื่อย ๆ และในเมื่อขนาดของ critical CSS สำคัญ ก็น่าจะดีถ้ามีตัวเลือก down-compile ของอย่าง CSS variables ด้วย อีกอย่างไม่แนะนำคำแนะนำที่ให้วางแท็ก
<link>ของ non-critical CSS ไว้ก่อน</body>เพราะ CSS ควรถูกดึงมาให้เร็ว การทำแบบนี้จะทำให้การค้นพบ CSS ช้าลงและดาวน์โหลดช้าตามไปด้วย แนะนำให้ใช้วิธีผสมระหว่าง preload กับ noscript แทน<link rel="preload" href="styles.css" as="style" onload="this.rel='stylesheet'"><noscript><link rel="stylesheet" href="styles.css"></noscript>สงสัยว่าวิธีใช้โค้ด JS ใน preload แบบนี้จะโดนบล็อกไหม ถ้า CSP ไม่อนุญาต unsafe-inline
ไม่อยากใช้วิธีโหลด CSS ด้วย JS hack เพราะตอนนำ stylesheet ไปใช้ อาจเกิดการคำนวณ layout/style ใหม่ทั้งหน้าได้ เบราว์เซอร์เองก็ดึง stylesheet ได้เร็วอยู่แล้วแม้อยู่ล่างหน้า
ใช้แค่ prefetch attribute, HTTP header hints และ CDN ก็ได้ผลใกล้เคียงกันแล้ว ไม่จำเป็นต้อง rebuild critical CSS อยู่ตลอด ถ้าใช้ CDN อย่าง CF ให้ถูกต้องก็เร็วมาก
น่าจะพูดถูก มีแผนจะใส่ตัวเลือกนี้เหมือนกัน แทนที่จะใช้แบบ 'before body' เคยลองตัวเลือก 'DOMCONTENTLOADED' แล้ว พบว่าแม้บนมือถือเก่า ๆ หรือเครือข่ายช้า ก็ยังทำงานได้ดีพอทั้งต่อ UX และ Lighthouse
เห็นด้วยอย่างมากเรื่องรองรับ responsive
สำหรับผม นี่ดูเป็นการ optimize เร็วเกินไปหน่อย น่าจะมีคุณค่าก็ต่อเมื่อ CSS ซับซ้อนมากหรือมี resource ที่ต้องโหลดเยอะ แต่ในสถานการณ์ส่วนใหญ่ การเขียน CSS, HTML, JS ให้สะอาดน่าจะมีประสิทธิภาพกว่า และวิธีนี้อาจไม่จำเป็นหรืออาจให้ผลเสียด้วยซ้ำ
มีประโยชน์มาก ผมทำเว็บ WordPress แบบฟรีแลนซ์บ่อย และมักเจอเคสที่ CSS/JS เละเทะมากเพราะผ่านมือนักพัฒนาหรือเอเจนซีหลายเจ้า อยากลองใช้เครื่องมือแบบนี้จริง ๆ
ยิ่ง CSS ซับซ้อนหรือมี resource เยอะ ผลบวกสุทธิของ optimization แบบนี้กลับยิ่งน้อยลง เพราะสิ่งที่เล็งแก้คือ RTT latency แต่ยิ่ง critical CSS ใหญ่ ต้นทุนของ optimization ก็ยิ่งสูง ทำให้ประโยชน์สุทธิลดลง
ถ้าเป็นเมื่อ 12 ปีก่อน ผมน่าจะยอมจ่ายเงินให้เครื่องมือแบบนี้ เพราะตอนนั้นมี CSS ปริมาณมหาศาลที่สะสมมาหลายปี และยากมากที่จะรู้ว่ากฎไหนเป็น critical
หลายเว็บไซต์อาจถือว่าเป็นการ optimize เร็วเกินไปจริง แต่สำหรับเว็บประเภทข่าว/สื่อที่ไวต่อจำนวนคลิก การโหลดหน้าแบบ “ทันที” สำคัญมาก แค่เกิน 1 วินาที อัตราการหลุดออกและรายได้โฆษณาก็ลดลงแล้ว HuffPost เองก็เคยลอง optimization แบบนี้ตั้งแต่ 10 ปีก่อน
พอมองสภาพปัจจุบันของการพัฒนา frontend แล้วรู้สึกว่ามันเกินไปจริง ๆ เครื่องมืออย่าง Lighthouse ทำให้คนหมกมุ่นกับการ optimize เพื่อคะแนนที่ไม่มีความหมาย ผลคือความซับซ้อนของ build เพิ่มขึ้น แต่ผู้ใช้จริงแทบไม่รู้สึกอะไร แถมพัฒนายากขึ้นอีก ทั้งที่ระหว่างนั้นก็ยังเห็นเว็บที่พลาดเรื่องพื้นฐานอย่าง UI/การจัดการ state อยู่เต็มไปหมด น่าอึดอัดมาก
CSS, HTML, JS ที่สะอาดคือคำตอบจริง แต่บางทีก็ต้องรับช่วงโปรเจกต์ที่เละหรือใช้เทมเพลต และต่อให้พัฒนาเอง บางครั้งสถาปัตยกรรมก็อาจพันกันได้
สำหรับผม วิธีโหลด CSS เป็นสิ่งที่ต้องคิดตั้งแต่ขั้นแรกของการพัฒนา เราเคยเสียลูกค้าไปเยอะเพราะเว็บมี page speed test score ต่ำ ประสิทธิภาพมีผลกับ SEO เลยสำคัญมาก ผมถึงกับออกแบบ optimization ของหน้าใหม่ทั้งหมดเพื่อให้ Google Lighthouse ได้ 100 คะแนน ต้องวางแผนตั้งแต่ต้นทั้งลำดับและวิธีโหลด CSS/JS เพื่อจะได้ไม่ต้องมานั่งแก้ทีหลัง เราแยก CSS ส่วนเหนือ/ใต้ fold แล้ว inline ให้ตรงจุด และ JS ใต้ fold จะไม่ถูก evaluate เลยจนกว่าจะมีการ scroll เราทำตามทุกอย่างที่ Lighthouse แนะนำ ระบบก่อนหน้านี้ใส่ CSS ทั้งเว็บทุกหน้า (3~4MB) ส่วน JS หนักกว่านั้นอีก เพราะไม่ได้วางแผน optimization ตั้งแต่แรก ตอนนี้ยังใช้ระบบนั้นอยู่เลยบอกชื่อไม่ได้ แต่ภายในก็ยังเป็นปัญหาอยู่เรื่อย ๆ ถ้าเป้าหมายคือ performance ผมไม่คิดว่ามีคำว่า optimize เร็วเกินไป ต้องคิดทุกอย่างตั้งแต่แรก ผลลัพธ์คือได้ performance 100 คะแนนกับทุก client รวมถึงมือถือ และยังเหนือกว่าคู่แข่ง พอลองใช้เครื่องมือนี้กับเว็บตัวเองก็แทบไม่มีอะไรให้ optimize เพิ่มแล้ว เลยไม่เห็นผล
สำหรับหน้าเว็บที่ผมทำด้วย Astro, HTML มี 27.52KB (บีบอัดแล้ว 6.1KB), JS ต่ำกว่า 10KB, critical CSS 57KB (บีบอัดแล้ว 7KB) ส่วนเว็บคล้ายกันบางแห่งอยู่ที่ 100KB~1MB ถ้าทำให้สะอาด resource hints อย่างเดียวก็เร็วพอโดยไม่ต้อง inline css/js ถ้าใช้ nginx+HTTP/2+edge cache ก็ทำ performance 100/100 ได้โดยไม่ต้องมี critical CSS/inline js ผมสงสัยว่าการเพิ่ม 7KB ทุกหน้ามันไม่ค่อยคุ้ม ในเชิง implementation แล้ว SPA/edge caching เป็นมิตรต่อสิ่งแวดล้อมกว่าและเร็วกว่า ไม่จำเป็นต้องส่ง HTML ที่หนักมากแบบ Elementor โดยเฉพาะเมื่อแบตมือถือมีจำกัด ก็ไม่มีเหตุผลจะต้องส่งข้อมูลที่ไม่จำเป็นด้วย
เป็นทริกที่ดี แต่ในสถานการณ์ที่ CDN และ HTTP/2 แพร่หลายอยู่แล้ว optimization แบบนี้สุดท้ายก็เปลืองแค่ bandwidth ปรับตัวเลข benchmark ได้นิดหน่อย และในโลกจริงก็เร็วขึ้นแค่ราว 10~20ms เท่านั้น
การใส่ critical CSS ในทุกหน้าไม่ใช่คำตอบเสมอไป วิธีเลี่ยง data bloat ที่ไม่จำเป็นคือใช้แบบ selective เฉพาะ first visit (ตอนยังไม่มี cache) หรือหน้าเริ่มต้นของ session เท่านั้น
เพราะลูกค้าร้องขอเลยไปหาเครื่องมือสำหรับ extract critical CSS แต่ไม่เจอฟังก์ชันที่ต้องการ สุดท้ายเลยมาแชร์โซลูชันที่ทำเองด้วย Puppeteer และเครื่องมือของตัวเอง สามารถกำหนดได้ว่าจะรอหลังโหลดหน้าเท่าไร เคยใช้บริการเสียเงินด้วยแต่ไม่ถูกใจเลยขอคืนเงิน ตอนนี้เปิดให้ใช้ฟรีและยินดีรับ feedback
สงสัยว่ามีปัญหากับเครื่องมือเดิมอย่างแพ็กเกจ penthouse หรือเปล่า
ถ้าใส่เว็บไซต์ที่ไม่มี CSS จะเกิด error
โค้ดเปิดให้ดูหรือเปล่า อยากใช้เป็นปลั๊กอิน Vite/Astro ด้วย
อยากถามว่านี่คือเวอร์ชัน UI ของ penthouse หรือเปล่า เพราะค่าตั้งหลายอย่างคล้ายกันมาก
วิธีนี้กลับให้ผลตรงข้ามมากกว่า เพราะทำให้เกิด FOUC (หน้าแวบแบบยังไม่ลงสไตล์) อย่างสม่ำเสมอ ถ้า layout เปลี่ยนกลางคัน ผู้ใช้ที่กำลังกดอะไรอยู่แล้วอาจเจอปัญหาใหญ่ นี่ไม่ใช่แค่เรื่องความสวยงาม แต่เป็นปัญหาด้าน usability จริง ๆ
ผมเองก็ปรับสไตล์บางส่วนหลังใช้วิธีนี้ แต่สุดท้ายก็ optimize ให้ CLS (cumulative layout shift) เป็น 0 ได้อยู่ดี ถ้างบน้อยและใช้เทมเพลตที่มีไลบรารีเยอะ มันมีประโยชน์มาก
เป้าหมายตั้งแต่แรกไม่ใช่การหลีกเลี่ยง FOUC โดยไม่ block CSS network request หรอกหรือ
วิธีนี้มีความหมายมากขึ้นเมื่อสมมติว่าการเปิดดูหน้าครั้งแรกไม่มี CSS cache เลย แต่ในความเป็นจริงก็มี trade-off จากหลายปัจจัย เช่น สัดส่วนผู้ใช้ใหม่/ผู้ใช้กลับมา, การตั้งค่า CSS cache, CDN, 103 early hints, critical css/initial congestion window เป็นต้น
ตอนวัด performance บน localhost แทบไม่เห็นผลของ CSS เลย ต่อให้เอา CSS ออกทั้งหมดก็เร็วขึ้นไม่ถึง 7ms และยังอยู่ในช่วงความคลาดเคลื่อนของการวัดด้วย
พอใช้เครื่องมือนี้กับเว็บผม ก็พบว่ามัน extract แม้กระทั่งองค์ประกอบสำหรับ debugging ที่ไม่จำเป็นจริง ๆ ลงไปใน CSS ด้วย เช่น
body::afterสำหรับ grid overlay ของเว็บก็ถูกใส่มาด้วยเฉย ๆ (ลืมไปแล้วด้วยซ้ำว่าเคยมี เลยมาพบเพราะอันนี้)ผมชอบแนวทางเขียน HTML ที่สื่อความหมายได้ดีแม้ไม่มี CSS เพราะแบบนี้จะช่วยป้องกันไม่ให้โครงสร้างเอกสารซับซ้อนเกินไปตั้งแต่ต้น
ไอเดียสดใหม่ดี เลยลองใช้กับเว็บไซต์ส่วนตัว แต่เจอ error ว่า CSS ตกหล่นจากไลบรารี penthouse
{"error":true,"name":"Error","message":"css should not be empty" ...}