ปรับแต่งฟอนต์เว็บไซต์แบรนด์: ฟอนต์ระบบ, font-display, preload และ FOIT
1. ทำไมฟอนต์ถึงบล็อกการแสดงข้อความ
เบราว์เซอร์ไม่รู้ว่าข้อความควรมีหน้าตาอย่างไรจนกว่าจะได้ไฟล์ฟอนต์ พฤติกรรมเริ่มต้นคือซ่อนข้อความไว้ (FOIT, Flash of Invisible Text) ช่วงที่ซ่อนนี้ในเบราว์เซอร์เก่าคือ 3 วินาที เบราว์เซอร์ใหม่เปลี่ยนเป็น 1 วินาทีแล้วบังคับแสดงด้วยฟอนต์ fallback ปัญหาคือ: เนื้อหาหน้าจอแรกคือองค์ประกอบ LCP ถ้ามันรอฟอนต์อยู่ LCP ก็จะถูกเวลาดาวน์โหลดฟอนต์ฉุดไว้
ข้อผิดพลาดที่พบบ่อยในเว็บไซต์แบรนด์: เจ้าของธีมติด Google Fonts อย่าง Inter หรือ Roboto ทุกน้ำหนัก (100 ถึง 900 รวม 9 น้ำหนัก) เพื่อความ “ดีไซน์” แต่ละน้ำหนัก 100KB โหลดครั้งเดียว 900KB บนเครือข่าย 3G แค่ฟอนต์ก็ใช้เวลาโหลด 3 ถึง 5 วินาที ผู้ใช้เห็นเพียงหน้าจอว่างเปล่า ตัวชี้วัดที่เกี่ยวกับฟอนต์ใน Core Web Vitals ดูที่การปรับแต่ง Core Web Vitals การตั้งค่า CDN ดูที่CDN เร่งความเร็วทั่วโลก。
| คำถาม | ผลต่อประสิทธิภาพ | ขนาดทั่วไป |
|---|---|---|
| โหลดทุกน้ำหนัก (9 ระดับ) | หน้าจอแรกดาวน์โหลดเพิ่ม 800KB | น้ำหนักละ 80 ถึง 120KB |
| ฟอนต์จีนที่ไม่ได้ตัด subset | ไฟล์เดียว 2 ถึง 8MB | เกินงบหน้าจอแรกไปไกล |
| font-display ค่าเริ่มต้น block | FOIT ซ่อน 1 ถึง 3 วินาที | ข้อความไม่ปรากฏ |
| ไม่ preload ฟอนต์สำคัญ | เบราว์เซอร์พบฟอนต์ช้า ล่าช้า 200ms | LCP ถูกฉุดให้ช้าลง |
| ใช้หลายตระกูล (>3) | ทุกตระกูลต้องดาวน์โหลด | รวม 300 ถึง 500KB |
2. ฟอนต์ระบบ: คำตอบเริ่มต้นสำหรับเว็บ B2B
ฟอนต์ระบบ (system font stack) ใช้ฟอนต์ที่ติดตั้งอยู่ในอุปกรณ์ของผู้ใช้แล้ว ไม่ต้องส่งคำขอเครือข่าย แสดงผลทันที เนื้อหาของเว็บไซต์แบรนด์ B2B เน้นตารางสเปก คำอธิบายเคส และบทความเทคนิค การจัดวางไม่จำเป็นต้องใช้ฟอนต์ตกแต่งหรือฟอนต์เฉพาะแบรนด์ ฟอนต์ระบบเพียงพอด้านภาพและสม่ำเสมอข้ามแพลตฟอร์ม
ชุด CSS ที่ใช้ได้เลย: font-family: -apple-system, BlinkMacSystemFont, “Segoe UI”, Roboto, “Helvetica Neue”, Arial, “PingFang SC”, “Microsoft YaHei”, sans-serif ชุดนี้ครอบคลุม macOS, Windows, Android และ iOS ทั้งภาษาไทยและอังกฤษมีฟอนต์ระบบรองรับ ข้อสรุปที่ขัดกับความรู้สึกทั่วไป:การใช้ฟอนต์ระบบไม่ได้ทำให้เว็บไซต์ดู “ไม่มืออาชีพ” ตรงกันข้าม GitHub, Stripe, Linear ซึ่งเป็นเว็บไซต์ต้นแบบด้านดีไซน์กลับใช้ชุดฟอนต์ระบบทั้งหมด วิธีเลือกธีม WP ดูได้ที่สแต็กเทคโนโลยี WordPress。
| 方案 | ข้อความบนหน้าจอแรก | ดาวน์โหลดเพิ่ม | เหมาะกับเว็บแบบไหน |
|---|---|---|---|
| ใช้ฟอนต์ระบบล้วน | แสดงทันที | 0KB | เว็บ B2B ส่วนใหญ่ |
| หัวข้อเว็บฟอนต์ 1 ตัว | แสดง fallback ก่อนแล้วค่อยเปลี่ยน | 30 ถึง 80KB | เว็บที่เน้นภาพลักษณ์แบรนด์ |
| ตระกูลเว็บฟอนต์ 2 ตระกูล | แสดง fallback ก่อนแล้วค่อยเปลี่ยน | 80 ถึง 150KB | เว็บแบรนด์ที่ขับเคลื่อนด้วยดีไซน์ |
| เว็บฟอนต์ 3 ตัวขึ้นไป | เห็น FOUT/FOIT ชัดเจน | >200KB | ไม่แนะนำ |
| เว็บฟอนต์ไทยแบบเต็มชุด | FOIT หลายวินาที | 2 ถึง 8MB | แทบเป็นไปไม่ได้ |
สาม font-display:swap กับ FOIT: อย่าให้ข้อความซ่อนหาย
font-display เป็นพร็อพเพอร์ตี้ใน @font-face ควบคุมว่าข้อความจะแสดงอย่างไรระหว่างที่ฟอนต์กำลังโหลด มีสี่ค่า: auto (ค่าเริ่มต้นของเบราว์เซอร์ แต่เดิมคือ block), block (ซ่อนชั่วครู่ 3 วินาทีแล้วใช้ fallback), swap (ใช้ fallback แสดงทันที พอฟอนต์โหลดเสร็จค่อยเปลี่ยน), optional (เบราว์เซอร์ตัดสินใจเอง เอนไปทางไม่ดาวน์โหลด)
เว็บ B2B ควรใช้ swap ทั้งหมด block บนเครือข่าย 3G เท่ากับหน้าจอแรกว่างเปล่า 3 วินาที ผู้เข้าชมไปนานแล้ว ส่วน optional เหมาะกับฟอนต์ที่ไม่ใช่หัวใจของแบรนด์ แต่ควบคุมไม่ได้ ความเข้าใจผิดที่พบบ่อยคือ “swap ทำให้ฟอนต์กระพริบ (FOUT)” แต่สำหรับเว็บ B2B การให้ผู้ใช้ได้อ่านสเปกและช่องทางติดต่อก่อนสำคัญกว่าการรอหัวข้อแบบตัวเขียนประณีตมาก ฟอนต์กระพริบแป๊บเดียวยอมรับได้ entirely แต่การที่อ่านข้อความไม่เห็นต่างหากคือความเสียหายจริง ดูกลยุทธ์การโหลด CSS/JS ได้ที่การปรับแต่ง CSS/JS。
| font-display | ช่วงบล็อก | หลังฟอนต์โหลดเสร็จ | เหมาะกับ |
|---|---|---|---|
| auto/block | ข้อความมองไม่เห็นภายใน 3 วินาที | เปลี่ยนเป็นเว็บฟอนต์ | ไม่แนะนำ |
| swap | ใช้ fallback แสดงทันที | พอฟอนต์เสร็จก็เปลี่ยน | ค่าเริ่มต้นของเว็บ B2B |
| fallback | ซ่อน 100ms แล้วใช้ fallback | เปลี่ยนก็ต่อเมื่อโหลดเสร็จภายใน 3 วินาที | ฟอนต์กึ่งสำคัญ |
| optional | ซ่อน 100ms แล้วใช้ fallback | การเข้าชมครั้งนี้ไม่เปลี่ยน | ฟอนต์ตกแต่งล้วน |
สี่ preload กับ subset: ทำให้ฟอนต์ที่ควรเร็วได้เร็ว
ถ้าหัวข้อบนหน้าจอแรกจำเป็นต้องใช้เว็บฟอนต์ ให้ใช้ preload บอกเบราว์เซอร์ให้ดาวน์โหลดล่วงหน้าด้วยความสำคัญสูง: เพิ่ม <link rel=”preload” href=”font.woff2″ as=”font” type=”font/woff2″ crossorigin> ใน head วิธีนี้ฟอนต์จะเริ่มดาวน์โหลดก่อนที่ CSS จะถูกประมวลผล ทำให้ LCP เร็วขึ้น 200 ถึง 400 มิลลิวินาที ระวังอย่าละ crossorigin ไม่งั้น preload จะไม่ทำงาน
การทำ subset เป็นอีกหนึ่งการปรับแต่งที่ต้องทำ ฟอนต์ภาษาอังกฤษเก็บแค่ตัวอักษรอังกฤษ ตัวเลข และสัญลักษณ์ที่ใช้บ่อย ขนาดลดจาก 100KB เหลือ 30KB ส่วนฟอนต์ภาษาจีนเพราะชุดตัวอักษรใหญ่เกินไป ต่อให้ทำ subset ก็ยังมีขนาด 200KB ถึง 1MB ดังนั้นเว็บภาษาจีนจึงแนะนำให้ใช้ฟอนต์ของระบบไปเลย ใช้ glyphhanger หรือพารามิเตอร์ text ของ Google Fonts เพื่อโหลดเฉพาะตัวอักษรที่ใช้จริง ตัวอย่างสถานการณ์จริง หัวข้อแรกหน้าจอใช้แค่ 20 ตัวอักษรจีน ก็ทำ subset แค่ 20 ตัวนี้ ไฟล์ลดจาก 4MB เหลือ 5KB ส่วนแคช CDN ดูที่เปรียบเทียบการเลือก CDN。
| การปรับแต่งฟอนต์ | ขนาด/เวลาโหลดที่ลดลง | ความยากในการทำ | คำแนะนำ |
|---|---|---|---|
| ใช้เฉพาะรูปแบบ woff2 | เล็กกว่า ttf 30% | ต่ำ | ต้องทำ |
| โหลดเฉพาะน้ำหนัก 400 และ 700 | ลดการดาวน์โหลด 60% | ต่ำ | ต้องทำ |
| ทำ subset ชุดตัวอักษรอังกฤษ | ลดอีก 50% | ปานกลาง | แนะนำ |
| preload ฟอนต์หน้าจอแรก | LCP เร็วขึ้น 200 ถึง 400ms | ต่ำ | หัวข้อหน้าจอแรกใช้ |
| เว็บฟอนต์จีนแบบเต็มชุด | ข้อเสีย | สูง | ห้ามทำ |
ห้า การตรวจรับ ดู waterfall การโหลดฟอนต์ด้วย DevTools
ทำการปรับแต่งฟอนต์เสร็จแล้วจะตรวจรับอย่างไร เปิดแผง Network ใน Chrome DevTools กรอง Font ดูสามอย่าง จำนวนไฟล์ฟอนต์ ควรไม่เกิน 2 ตระกูล ตระกูลละไม่เกิน 2 น้ำหนัก ขนาดไฟล์ฟอนต์ ไฟล์เดียวไม่เกิน 50KB ถือว่าดี จุดเวลาที่ฟอนต์เริ่มดาวน์โหลด หลัง preload ควรอยู่ในคำขอแรกสุด ไม่ใช่รอ CSS ประมวลผลเสร็จแล้วจึงเจอ ถ้าไฟล์ฟอนต์ใดเกิน 100KB ควรกลับไปตรวจว่าตั้งน้ำหนักหรือ subset ไม่ดีหรือเปล่า
จากนั้นใช้ Lighthouse ดู audit สองรายการ คือ “หลีกเลี่ยงการเลื่อนตำแหน่งเลย์เอาต์จากเว็บฟอนต์” และ “preload คำขอสำคัญ” เช็กลิสต์ที่ทำได้จริง font-display เป็น swap ทั้งหมด preload ฟอนต์หน้าจอแรก รูปแบบ woff2 ไม่มีรูปแบบเก่าอย่าง ttf/eot ใช้พารามิเตอร์ display=swap กับ Google Fonts เว็บหลายภาษาจัดการฟอนต์อย่างไร ดูที่การจัดการแผนภูมิของเว็บหลายภาษา ส่วนการมอนิเตอร์เว็บไซต์ดูที่การแจ้งเตือนมอนิเตอร์เว็บไซต์。
| รายการตรวจรับ | เกณฑ์ผ่าน | เครื่องมือวัด |
|---|---|---|
| font-display | swap หรือ fallback ทั้งหมด | ตรวจสอบ CSS |
| preload ฟอนต์หน้าจอแรก | ฟอนต์หัวข้อหน้าจอแรก preload แล้ว | DevTools Network |
| รูปแบบไฟล์ฟอนต์ | มีแค่ woff2 | กรอง Font ใน Network |
| ขนาดฟอนต์เดี่ยว | ≤50KB | คอลัมน์ Network Size |
| จำนวนตระกูลฟอนต์ | ≤2 ตระกูล | ตรวจสอบ CSS |
| LCP เปอร์เซ็นไทล์ที่ 75 | ≤2.5 วินาที | CrUX/RUM |
FAQ คำถามที่พบบ่อย
เว็บ B2B จำเป็นต้องใช้เว็บฟอนต์ไหม
font-display:swap กับ block ต่างกันตรงไหน
ฟอนต์จีนใช้เว็บฟอนต์ได้ไหม
ทำไม preload ฟอนต์ต้องใส่ crossorigin ด้วย?
โหลด Google Fonts ยังไงให้เร็วที่สุด?
ปรับแต่งฟอนต์เสร็จแล้วตรวจรับยังไง?
หก、FOUT กับการเลื่อนตำแหน่งเลย์เอาต์: เปลี่ยนฟอนต์แล้วทำยังไงไม่ให้กระตุก
หลังใช้กลยุทธ์ swap พอฟอนต์ fallback ถูกแทนที่ด้วย Web font เพราะความกว้างและความสูงของตัวอักษรต่างกัน หน้าจึงอาจกระตุก นี่คือที่มาของ CLS (cumulative layout shift) Stripe เคยวัดไว้: การแทนที่ฟอนต์หนึ่งครั้งทำให้เกิด CLS เฉลี่ย 0.05-0.1 ซึ่งพอดีเกาะเส้นผ่านที่ 0.1 พอดี เว็บ B2B เพราะเนื้อหายาวและมีหลายย่อหน้า ความต่างของการตัดบรรทัดจากการแทนที่ทำให้ตำแหน่งรูปภาพกระโดดขึ้นลง
วิธีจัดการคือ descriptor สองตัว: font-size-adjust กับ size-adjust ใน @font-face ใช้ size-adjust: 105% และ ascent-override ปรับเมตริกของ Web font ให้ใกล้เคียงกับ fallback พอแทนที่ก็แทบไม่กระตุก อีกวิธีที่สบายกว่าคือเลือกคู่ที่ fallback กับ Web font มีเมตริกใกล้กัน เช่น fallback ของ Inter เลือก Arial หรือใช้ system font stack ไปเลยไม่ต้องเปลี่ยน เกณฑ์ตรวจรับที่ชัดเจน: ดู audit “หลีกเลี่ยงการเลื่อนตำแหน่งเลย์เอาต์บน Web font” ใน Lighthouse ถ้าคะแนนต่ำ ให้ดูก่อนว่าเกิดจาก swap ไหม แล้วค่อยตัดสินใจว่าจะใส่ size-adjust หรือเปล่า
| วิธีจัดการ FOUT | ปรับปรุง CLS | ความยากในการทำ |
|---|---|---|
| ไม่แก้ไข ยอมรับการกระพริบ | 0.05 ถึง 0.1 | ไม่มี |
| ปรับละเอียดด้วย size-adjust | ลดให้ต่ำกว่า 0.02 | ปานกลาง ต้องทดสอบ |
| เลือก fallback ที่ค่าตัววัดใกล้เคียง | ลดให้ต่ำกว่า 0.03 | ต่ำ |
| ไม่ใช้ Web font ไปเลย | 0 | ไม่มีค่าใช้จ่าย |
ทิ้งท้าย
หลักตัดสินใจเรื่องฟอนต์ง่ายมาก ผู้ใช้เว็บ B2B เข้ามาอ่านสเปก ดูเคส แล้วหาช่องทางติดต่อ ไม่ได้มาเสพศิลปะการจัดตัวอักษร ระบบฟอนต์ของเครื่องตอบโจทย์ได้ใน 95% ของกรณี ประหยัดไปได้หลายร้อย KB กับหลายร้อยมิลลิวินาที ซึ่งสำคัญกว่าความต่างทางสายตามาก ถ้าจะเก็บ Web font ไว้ก็ให้คุมแค่ 2 ตระกูล 2 น้ำหนัก ฟอร์แมต woff2 และโหลดแบบ swap เท่านั้น
ลงมือ 3 ขั้น ขั้นแรก สัปดาห์นี้เปลี่ยนฟอนต์ของธีมเป็นระบบฟอนต์ของเครื่อง แล้วลบ Google Fonts ที่ไม่จำเป็นออกให้หมด ขั้นที่สอง Web font ที่เก็บไว้ให้ใส่ font-display:swap ทุกตัว เหลือแค่น้ำหนัก 400 กับ 700 และโฮสต์ไฟล์ woff2 เอง ขั้นที่สาม ใส่ preload ให้ฟอนต์หัวข้อที่อยู่เหนือ fold พร้อมเติม crossorigin อีกสองสัปดาห์กลับมาดูว่า LCP กับ audit ที่เกี่ยวกับฟอนต์ดีขึ้นไหม
ประโยคเดียวที่จำได้ติดหัว ผู้ใช้ไม่ได้อยู่ต่ออีกหนึ่งวินาทีเพราะเว็บคุณใช้ Inter แต่จะปิดหนีทันทีเพราะรอฟอนต์โหลด 3 วินาที ฟอนต์เป็นรายละเอียด แต่รายละเอียดคือสิ่งที่ตัดสินว่า 2.5 วินาทีแรกจะดึงคนไว้ได้หรือไม่
