วิธีแก้ไขปัญหาการเปลี่ยนแปลงเค้าโครงสะสม (CLS)

เผยแพร่แล้ว: 2022-03-10
สรุปโดยย่อ ↬ ความคิดริเริ่ม Core Web Vitals ของ Google ทำให้โลก SEO และประสิทธิภาพของเว็บล่มสลาย และเว็บไซต์หลายแห่งกำลังยุ่งอยู่กับการปรับประสบการณ์หน้าเพจให้เหมาะสมเพื่อเพิ่มปัจจัยการจัดอันดับให้ได้มากที่สุด ตัวชี้วัด Cumulative Layout Shift ทำให้เกิดปัญหากับเว็บไซต์จำนวนมาก ดังนั้น เรามาดูวิธีแก้ไขปัญหาสำหรับตัวชี้วัดนั้นกันดีกว่า

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

ในบทความนี้ ผมจะพูดถึง รูปแบบ front-end เพื่อลด CLS ฉันจะไม่พูดมากเกินไปเกี่ยวกับการวัด CLS เนื่องจากฉันได้กล่าวถึงไปแล้วในบทความก่อนหน้านี้ ฉันจะไม่พูดมากเกินไปเกี่ยวกับกลไกของวิธีคำนวณ CLS: Google มีเอกสารที่ดีเกี่ยวกับเรื่องนั้นและ Jess Peck's The Near-Complete Guide to Cumulative Layout Shift เป็นการดำน้ำลึกที่ยอดเยี่ยมเช่นกัน อย่างไรก็ตาม ฉันจะให้พื้นฐานเล็กน้อยที่จำเป็นในการทำความเข้าใจเทคนิคบางอย่าง

ทำไม CLS ถึงแตกต่าง

ในความคิดของฉัน CLS เป็น Core Web Vitals ที่น่าสนใจที่สุด ส่วนหนึ่งเพราะเป็นสิ่งที่เราไม่เคยวัดหรือปรับให้เหมาะสมมาก่อนจริงๆ ดังนั้นจึงมักต้องใช้เทคนิคและวิธีคิดใหม่ๆ เพื่อพยายามเพิ่มประสิทธิภาพ มันเป็นสัตว์เดรัจฉานที่แตกต่างไปจาก Core Web Vitals อีกสองตัว

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

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

เหตุผลหนึ่งที่ทำให้ CLS แตกต่างไปจากนี้ก็คือมีการวัดค่า ตลอดอายุของหน้าเว็บ นั่นคือส่วน "สะสม" ของชื่อ! Core Web Vitals อีกสองตัวหยุดทำงานหลังจากพบองค์ประกอบหลักบนหน้าหลังจากโหลด (สำหรับ LCP) หรือสำหรับการโต้ตอบครั้งแรก (สำหรับ FID) ซึ่งหมายความว่าเครื่องมือในห้องปฏิบัติการแบบดั้งเดิมของเรา เช่น Lighthouse มักจะไม่ได้สะท้อนถึง CLS ทั้งหมด เนื่องจากจะคำนวณเฉพาะ CLS โหลดเริ่มต้นเท่านั้น ในชีวิตจริง ผู้ใช้จะเลื่อนหน้าลงและอาจได้รับเนื้อหาเพิ่มขึ้นซึ่งทำให้มีการเปลี่ยนแปลงมากขึ้น

CLS ยังเป็นตัวเลขปลอมเล็กน้อยที่คำนวณโดยพิจารณาจากจำนวนหน้าที่มีการเคลื่อนไหวและความถี่ แม้ว่า LCP และ FID จะวัดเป็นมิลลิวินาที แต่ CLS จะเป็นเอาต์พุตตัวเลขแบบไม่มีหน่วย โดยการคำนวณที่ซับซ้อน เราต้องการให้หน้าเป็น 0.1 หรือต่ำกว่าเพื่อส่งผ่าน Core Web Vital นี้ สิ่งใดที่สูงกว่า 0.25 จะถูกมองว่า "แย่"

ไม่นับ กะที่เกิดจากการโต้ตอบของผู้ใช้ สิ่งนี้ถูกกำหนดให้อยู่ภายใน 500ms ของชุดการโต้ตอบของผู้ใช้เฉพาะแม้ว่าจะไม่รวมเหตุการณ์ตัวชี้และการเลื่อน สันนิษฐานว่าผู้ใช้ที่คลิกปุ่มอาจคาดหวังให้เนื้อหาปรากฏขึ้น ตัวอย่างเช่น โดยการขยายส่วนที่ยุบ

CLS เป็นเรื่องเกี่ยวกับ การวัดการเปลี่ยนแปลงที่ไม่คาดคิด การเลื่อนไม่ควรทำให้เนื้อหาเคลื่อนที่ไปมาหากมีการสร้างหน้าเว็บอย่างเหมาะสม และในทำนองเดียวกัน การเลื่อนเมาส์ไปเหนือรูปภาพผลิตภัณฑ์เพื่อให้ได้เวอร์ชันซูมเข้าก็ไม่ควรทำให้เนื้อหาอื่นกระโดดไปมา แต่แน่นอนว่ามีข้อยกเว้นและเว็บไซต์เหล่านั้นจำเป็นต้องพิจารณาว่าจะตอบสนองต่อสิ่งนี้อย่างไร

CLS ยังพัฒนาอย่างต่อเนื่องด้วยการปรับแต่งและแก้ไขข้อผิดพลาด เพิ่งมีการเปลี่ยนแปลงที่ใหญ่กว่าที่ประกาศซึ่งควรให้การผ่อนปรนสำหรับหน้าที่มีอายุการใช้งานยาวนานเช่น Single Page Apps (SPA) และหน้าเลื่อนที่ไม่มีที่สิ้นสุดซึ่งหลายคนรู้สึกว่าถูกลงโทษอย่างไม่เป็นธรรมใน CLS แทนที่จะสะสมกะในช่วงเวลาทั้งหน้าเพื่อคำนวณคะแนน CLS เหมือนที่เคยทำมาจนถึงตอนนี้ คะแนนจะถูกคำนวณตามชุดกะที่ใหญ่ที่สุดภายในกรอบเวลาที่กำหนด

ซึ่งหมายความว่าถ้าคุณมี CLS สามส่วนเท่ากับ 0.05, 0.06 และ 0.04 ก่อนหน้านี้ ค่านี้จะถูกบันทึกเป็น 0.15 (กล่าวคือ เกินขีดจำกัด "ดี" ที่ 0.1) ในขณะที่ตอนนี้จะมีคะแนน 0.06 ยังคง สะสม ในแง่ที่ว่าคะแนนอาจประกอบด้วยกะที่แยกจากกันภายในกรอบเวลานั้น (เช่น ถ้าคะแนน CLS 0.06 นั้นเกิดจากการแยกกันสามครั้งที่ 0.02) แต่จะไม่สะสมตลอดอายุทั้งหมดของหน้าอีกต่อไป .

กล่าวคือ หากคุณแก้ไขสาเหตุของการเปลี่ยนแปลง 0.06 นั้น CLS ของคุณจะถูกรายงานเป็นการเปลี่ยนแปลง ครั้งใหญ่ถัดไป (0.05) ดังนั้นจึงยังคงดูการเปลี่ยนแปลงทั้งหมดตลอดอายุของหน้า — เป็นเพียงการเลือกรายงานเท่านั้น ที่ใหญ่ที่สุดเป็นคะแนน CLS

ด้วยการแนะนำสั้น ๆ เกี่ยวกับวิธีการบางอย่างเกี่ยวกับ CLS มาดู วิธีแก้ปัญหา กัน ! เทคนิคทั้งหมดเหล่านี้เกี่ยวข้องกับการตั้งค่าพื้นที่ว่างที่ถูกต้องก่อนที่จะโหลดเนื้อหาเพิ่มเติม ไม่ว่าจะเป็นสื่อหรือเนื้อหาที่ฉีดด้วย JavaScript แต่นักพัฒนาเว็บมีตัวเลือกต่างๆ ที่จะทำเช่นนี้

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

ตั้งค่าความกว้างและความสูงบนรูปภาพและ iFrames

ฉันเคยเขียนเกี่ยวกับเรื่องนี้มาก่อนแล้ว แต่สิ่งหนึ่งที่ง่ายที่สุดที่คุณสามารถทำได้เพื่อลด CLS คือต้องแน่ใจว่าคุณมี แอตทริบิวต์ width และ height ที่ตั้งค่าไว้ในรูปภาพของคุณ หากไม่มีพวกเขา รูปภาพจะทำให้เนื้อหาที่ตามมาเปลี่ยนไปเพื่อหลีกเลี่ยงหลังจากดาวน์โหลด:

ตัวอย่างเลย์เอาต์ที่มีชื่อเรื่องและสองย่อหน้า โดยที่ย่อหน้าที่สองต้องเลื่อนลงมาเพื่อให้มีที่ว่างสำหรับรูปภาพ
การเปลี่ยนเลย์เอาต์หลังจากโหลดรูปภาพ (ตัวอย่างขนาดใหญ่)

นี่เป็นเพียงเรื่องของการเปลี่ยนมาร์กอัปรูปภาพของคุณจาก:

 <img src="hero_image.jpg" alt="...">

ถึง:

 <img src="hero_image.jpg" alt="..." width="400" height="400">

คุณสามารถค้นหาขนาดของรูปภาพได้โดยเปิด DevTools แล้ววางเมาส์เหนือ (หรือแตะผ่าน) องค์ประกอบ

ภาพหน้าจอของ Chrome Dev Tools ที่แสดงภาพ ขนาดที่แสดงผล อัตราส่วนภาพที่แสดงผล ขนาดภายใน อัตราส่วนขนาดที่แท้จริง ขนาดไฟล์ และแหล่งที่มาปัจจุบัน
Chrome DevTools แสดงขนาดภาพและอัตราส่วนภาพเมื่อวางเมาส์เหนือองค์ประกอบ (ตัวอย่างขนาดใหญ่)

ฉันแนะนำให้ใช้ Intrinsic Size (ซึ่งเป็นขนาดจริงของแหล่งที่มาของรูปภาพ) จากนั้นเบราว์เซอร์จะย่อขนาดให้เหลือขนาดที่แสดงผลเมื่อคุณใช้ CSS เพื่อเปลี่ยนแปลงสิ่งเหล่านี้

เคล็ดลับง่ายๆ : เช่นฉัน คุณจำไม่ได้ว่ามันคือความกว้างความสูงหรือความสูงและความกว้าง ให้คิดว่ามันเป็นพิกัด X และ Y ดังนั้นเช่น X จะมีการกำหนดความกว้างก่อนเสมอ

หากคุณมี รูปภาพที่ตอบสนอง และใช้ CSS เพื่อเปลี่ยนขนาดรูปภาพ (เช่น จำกัดให้มี max-width 100% ของขนาดหน้าจอ) คุณสามารถใช้แอตทริบิวต์เหล่านี้ในการคำนวณ height ได้ โดยคุณต้องไม่ลืมที่จะแทนที่สิ่งนี้ auto ใน CSS ของคุณ:

 img { max-width: 100%; height: auto; }

เบราว์เซอร์ที่ทันสมัยทั้งหมดรองรับสิ่งนี้ในขณะนี้ แม้ว่าจะไม่ได้เป็นเช่นนั้นจนกระทั่งเมื่อเร็วๆ นี้ตามที่กล่าวถึงในบทความของฉัน สิ่งนี้ยังใช้ได้กับองค์ประกอบ <picture> และรูปภาพ srcset (ตั้งค่า width และ height ในองค์ประกอบ img ทางเลือก) แม้ว่าจะยังใช้ไม่ได้สำหรับรูปภาพที่มีอัตราส่วนกว้างยาวต่างกัน — กำลังดำเนินการอยู่ และคุณยังคงควรตั้งค่า width และ height เนื่องจากค่าใด ๆ จะดีกว่าค่าเริ่มต้น 0 โดย 0 !

สิ่งนี้ยังใช้ได้กับ ภาพที่โหลด แบบ Lazy Loading ดั้งเดิม (แม้ว่า Safari ยังไม่รองรับการโหลดแบบ Lazy Loading ตามค่าเริ่มต้น)

คุณสมบัติ CSS aspect-ratio ใหม่

เทคนิค width และ height ข้างต้น ในการ aspect-ratio ความสูงของรูปภาพที่ตอบสนอง สามารถปรับให้เป็นองค์ประกอบทั่วไปกับองค์ประกอบอื่นๆ ได้โดยใช้คุณสมบัติ CSS ใหม่ ซึ่งขณะนี้ได้รับการสนับสนุนโดยเบราว์เซอร์ที่ใช้ Chromium และ Firefox แต่ยังอยู่ใน Safari Technology Preview ด้วย หวังว่าจะเป็นเวอร์ชั่นเสถียรเร็วๆ นี้

คุณสามารถใช้มันกับวิดีโอที่ฝังไว้ได้ เช่น ในอัตราส่วน 16:9:

 video { max-width: 100%; height: auto; aspect-ratio: 16 / 9; }
 <video controls width="1600" height="900" poster="..."> <source src="/media/video.webm" type="video/webm"> <source src="/media/video.mp4" type="video/mp4"> Sorry, your browser doesn't support embedded videos. </video>

ที่น่าสนใจโดยไม่ต้องกำหนดคุณสมบัติ aspect-ratio เบราว์เซอร์จะละเว้นความสูงขององค์ประกอบวิดีโอที่ตอบสนองและใช้อัตราส่วนกว้างยาวเริ่มต้นที่ 2: 1 ดังนั้นจึงจำเป็นต้องหลีกเลี่ยงการเปลี่ยนแปลงรูปแบบที่นี่

ในอนาคต ควรจะเป็นไปได้ที่จะตั้งค่า aspect-ratio แบบไดนามิก ตามแอตทริบิวต์องค์ประกอบโดยใช้ aspect-ratio: attr(width) / attr(height); แต่น่าเสียดายที่ยังไม่รองรับ

หรือคุณสามารถใช้ aspect-ratio กับองค์ประกอบ <div> สำหรับการควบคุมแบบกำหนดเองบางประเภทที่คุณกำลังสร้างเพื่อให้ตอบสนองได้:

 #my-square-custom-control { max-width: 100%; height: auto; width: 500px; aspect-ratio: 1; }
 <div></div>

สำหรับเบราว์เซอร์ที่ไม่รองรับ aspect-ratio คุณสามารถใช้แฮ็ก padding-bottom รุ่นเก่าได้ แต่ด้วยความเรียบง่ายของ aspect-ratio กว้างยาวที่ใหม่กว่าและการสนับสนุนที่กว้างขวาง (โดยเฉพาะอย่างยิ่งเมื่อสิ่งนี้ย้ายจาก Safari Technical Preview เป็น Safari ปกติ) มันคือ ยากที่จะพิสูจน์วิธีที่เก่ากว่านั้น

Chrome เป็นเบราว์เซอร์เดียวที่ ดึงข้อมูล CLS กลับคืนสู่ Google และสนับสนุนความหมาย aspect-ratio ที่จะแก้ปัญหา CLS ของคุณในแง่ของ Core Web Vitals ฉันไม่ชอบการจัดลำดับความสำคัญของตัวชี้วัดมากกว่าผู้ใช้ แต่ความจริงที่ว่าเบราว์เซอร์ Chromium และ Firefox อื่น ๆ มีสิ่งนี้และ Safari หวังว่าจะเร็ว ๆ นี้และนี่คือการปรับปรุงแบบก้าวหน้าหมายความว่าฉันจะบอกว่าเราอยู่ในจุดที่เรา สามารถทิ้งการแฮ็กช่องว่างภายในไว้เบื้องหลังและเขียนโค้ดที่ทำความสะอาดได้

ใช้ min-height เสรี

สำหรับองค์ประกอบที่ไม่ต้องการขนาดที่ตอบสนอง แต่มีความสูงคงที่แทน ให้พิจารณาใช้ min-height ต่ำสุด ซึ่งอาจใช้สำหรับ ส่วนหัวที่มีความสูงคงที่ ตัวอย่างเช่น และเราสามารถมีส่วนหัวที่แตกต่างกันสำหรับจุดพักต่างๆ โดยใช้การสืบค้นสื่อตามปกติ:

 header { min-height: 50px; } @media (min-width: 600px) { header { min-height: 200px; } }
 <header> ... </header>

แน่นอน เช่นเดียวกับ min-width สำหรับองค์ประกอบที่วางในแนวนอน แต่โดยปกติความสูงที่ทำให้เกิดปัญหา CLS

เทคนิคขั้นสูงสำหรับเนื้อหาที่ฉีดและตัวเลือก CSS ขั้นสูงคือการกำหนดเป้าหมายเมื่อยังไม่ได้แทรกเนื้อหาที่คาดไว้ ตัวอย่างเช่น หากคุณมีเนื้อหาดังต่อไปนี้:

 <div class="container"> <div class="main-content">...</div> </div>

และมีการแทรก div พิเศษผ่าน JavaScript:

 <div class="container"> <div class="additional-content">.../div> <div class="main-content">...</div> </div>

จากนั้น คุณสามารถใช้ข้อมูลโค้ดต่อไปนี้เพื่อ เว้นที่ว่างสำหรับเนื้อหาเพิ่มเติม เมื่อสร้าง div main-content ในตอนแรก

 .main-content:first-child { margin-top: 20px; }

รหัสนี้จะ สร้างการเปลี่ยนแปลง ไปยังองค์ประกอบ main-content หลักโดยที่ระยะขอบถูกนับเป็นส่วนหนึ่งขององค์ประกอบนั้น ดังนั้นมันจึงดูเหมือนจะเปลี่ยนไปเมื่อองค์ประกอบนั้นถูกลบออก (แม้ว่าจะไม่ได้เคลื่อนไหวบนหน้าจอจริง ๆ ก็ตาม) อย่างไรก็ตาม อย่างน้อยเนื้อหาด้านล่างจะไม่ถูกเปลี่ยน ดังนั้นควรลด CLS

หรือคุณสามารถใช้ ::before pseudo-element เพื่อเพิ่มช่องว่างเพื่อ หลีกเลี่ยงการเปลี่ยนแปลง ในองค์ประกอบ main-content หลักเช่นกัน:

 .main-content:first-child::before { content: ''; min-height: 20px; display: block; }

แต่ความจริงแล้ว ทางออกที่ดีกว่าคือการมี div ใน HTML และใช้ min-height กับสิ่งนั้น

ตรวจสอบองค์ประกอบทางเลือก

ฉันชอบใช้การเพิ่มประสิทธิภาพแบบก้าวหน้าเพื่อจัดหาเว็บไซต์พื้นฐาน แม้จะไม่มี JavaScript หากเป็นไปได้ น่าเสียดายที่สิ่งนี้ทำให้ฉันสนใจเมื่อเร็วๆ นี้ในไซต์เดียวที่ฉันดูแลเมื่อเวอร์ชันทางเลือกที่ไม่ใช่ JavaScript เป็นทางเลือกที่แตกต่างไปจากตอนที่ JavaScript เริ่มทำงาน

ปัญหานี้เกิดจากปุ่มเมนู "สารบัญ" ในส่วนหัว ก่อนที่จาวาสคริปต์จะเริ่มต้น นี่เป็นลิงก์ง่ายๆ ที่มีสไตล์ให้ดูเหมือนปุ่มที่นำคุณไปยังหน้าสารบัญ เมื่อ JavaScript เริ่มทำงาน มันจะกลายเป็น เมนูไดนามิก เพื่อให้คุณสามารถนำทางไปยังหน้าใดก็ได้ที่คุณต้องการจะไปจากหน้านั้นโดยตรง

ภาพหน้าจอขององค์ประกอบการนำทางสารบัญสองรายการซึ่งมีสไตล์เหมือนปุ่ม ด้วย JavaScript สิ่งนี้จะเปิดเมนูไดนามิกตามที่แสดงในรูปภาพที่สอง
ส่วนประกอบส่วนหัวของสารบัญซึ่งเริ่มแสดงเป็นลิงก์ธรรมดา (บนสุด) แล้วปรับปรุงด้วย JavaScript ให้เป็นเมนูไดนามิก (ด้านล่าง) (ตัวอย่างขนาดใหญ่)

ฉันใช้องค์ประกอบเชิงความหมายและใช้องค์ประกอบจุดยึด ( <a href="#table-of-contents"> ) สำหรับลิงก์ทางเลือก แต่แทนที่ด้วย <button> สำหรับเมนูไดนามิกที่ขับเคลื่อนด้วย JavaScript สิ่งเหล่านี้ถูกจัดรูปแบบให้ดูเหมือนกัน แต่ลิงก์สำรองมีขนาดเล็กกว่าปุ่มสองสามพิกเซล!

สิ่งนี้มีขนาดเล็กมากและปกติแล้ว JavaScript ก็เริ่มทำงานอย่างรวดเร็ว โดยที่ฉันไม่ได้สังเกตว่ามันปิดอยู่ อย่างไรก็ตาม Chrome สังเกตเห็นเมื่อคำนวณ CLS และเนื่องจากสิ่งนี้อยู่ในส่วนหัว จึง เลื่อนทั้งหน้าลง สองสามพิกเซล ดังนั้นสิ่งนี้จึงค่อนข้างส่งผลกระทบต่อคะแนน CLS - มากพอที่จะทำให้หน้าทั้งหมดของเราอยู่ในหมวดหมู่ "ต้องปรับปรุง"

นี่เป็นข้อผิดพลาดในส่วนของฉัน และการแก้ไขก็แค่ ทำให้ทั้งสององค์ประกอบซิงค์ กัน (สามารถแก้ไขได้ด้วยการตั้งค่า min-height ที่ส่วนหัวตามที่กล่าวไว้ข้างต้น) แต่ทำให้ฉันสับสนเล็กน้อย ฉันแน่ใจว่าไม่ใช่ฉันคนเดียวที่ทำข้อผิดพลาดนี้ ดังนั้นโปรดระวังว่าหน้าแสดงผลโดยไม่มี JavaScript อย่างไร ไม่คิดว่าผู้ใช้ของคุณปิดการใช้งาน JavaScript? ผู้ใช้ทั้งหมดของคุณไม่ใช่ JS ในขณะที่กำลังดาวน์โหลด JS ของคุณ

แบบอักษรเว็บทำให้เกิดการเลื่อนเค้าโครง

แบบอักษรของเว็บเป็นสาเหตุทั่วไปอีกอย่างหนึ่งของ CLS เนื่องจากเบราว์เซอร์เริ่มคำนวณพื้นที่ที่ต้องการตามแบบอักษรสำรอง จากนั้นจึง คำนวณใหม่ เมื่อดาวน์โหลดแบบอักษรของเว็บ โดยปกติ CLS มีขนาดเล็ก เนื่องจากมีการใช้แบบอักษรทางเลือกที่มีขนาดใกล้เคียงกัน จึงมักไม่ก่อให้เกิดปัญหามากพอที่จะทำให้ Core Web Vitals ล้มเหลว แต่อาจทำให้ผู้ใช้รู้สึกไม่สบายใจได้

ภาพหน้าจอสองภาพในบทความ Smashing Magazine ที่มีแบบอักษรต่างกัน ข้อความมีขนาดแตกต่างกันอย่างเห็นได้ชัดและสามารถใส่ประโยคเพิ่มเติมได้เมื่อใช้แบบอักษรเว็บ
บทความ Smashing Magazine ที่มีแบบอักษรสำรองและแบบอักษรเว็บแบบเต็ม (ตัวอย่างขนาดใหญ่)

น่าเสียดายที่การโหลดฟอนต์เว็บล่วงหน้าก็ไม่ช่วยอะไร ในขณะที่นั่นจะลดเวลาที่ใช้ฟอนต์สำรอง (ดังนั้นจึงดีสำหรับการโหลดประสิทธิภาพ — LCP) ก็ ยังต้องใช้เวลาในการดึงข้อมูล ดังนั้นทางเลือกจะยังคงใช้อยู่ โดยเบราว์เซอร์ในกรณีส่วนใหญ่จึงไม่หลีกเลี่ยง CLS บอกว่า ถ้าคุณรู้ว่าต้องใช้แบบอักษรของเว็บในหน้าถัดไป (สมมติว่าคุณอยู่ในหน้าเข้าสู่ระบบและรู้ว่าหน้าถัดไปใช้แบบอักษรพิเศษ) คุณสามารถดึงข้อมูลล่วงหน้าได้

เพื่อหลีกเลี่ยง การเปลี่ยนเลย์เอาต์ที่เกิดจากฟอนต์ ทั้งหมด แน่นอนว่าเราไม่สามารถใช้ฟอนต์ของเว็บได้เลย รวมถึงการใช้ฟอนต์ของระบบแทน หรือใช้ font-display: optional ที่จะไม่ใช้หากไม่ได้ดาวน์โหลดทันเวลาสำหรับการเรนเดอร์ครั้งแรก แต่ทั้งสองอย่างไม่น่าพอใจมากพูดตามตรง

อีกทางเลือกหนึ่งคือทำให้แน่ใจว่าส่วนต่างๆ มี ขนาดเหมาะสม (เช่น min-height ) ดังนั้นในขณะที่ข้อความในนั้นอาจเปลี่ยนไปเล็กน้อย เนื้อหาด้านล่างจะไม่ถูกผลักลงแม้ว่าจะเกิดเหตุการณ์นี้ขึ้นก็ตาม ตัวอย่างเช่น การตั้งค่า min-height ในองค์ประกอบ <h1> อาจป้องกันไม่ให้ทั้งบทความเลื่อนลงมาหากโหลดฟอนต์ที่สูงกว่าเล็กน้อยเข้ามา การที่ฟอนต์ที่แตกต่างกันจะไม่ทำให้จำนวนบรรทัดต่างกัน สิ่งนี้จะลดผลกระทบของกะ อย่างไรก็ตาม สำหรับกรณีการใช้งานจำนวนมาก (เช่น ย่อหน้าทั่วไป) จะเป็นการยากที่จะสรุปความสูงขั้นต่ำ

สิ่งที่ฉันตื่นเต้นที่สุดในการแก้ปัญหานี้คือ CSS Font Descriptors ใหม่ ซึ่งช่วยให้คุณปรับแบบอักษรทางเลือกใน CSS ได้ง่ายขึ้น:

 @font-face { font-family: 'Lato'; src: url('/static/fonts/Lato.woff2') format('woff2'); font-weight: 400; } @font-face { font-family: "Lato-fallback"; size-adjust: 97.38%; ascent-override: 99%; src: local("Arial"); } h1 { font-family: Lato, Lato-fallback, sans-serif; }

ก่อนหน้านี้ การปรับแบบอักษรทางเลือกที่ต้องใช้โดยใช้ Font Loading API ใน JavaScript ซึ่งซับซ้อนกว่า แต่ตัวเลือกนี้ที่ใกล้จะหมดอายุในเร็วๆ นี้ อาจทำให้เรามีวิธีแก้ปัญหาที่ง่ายกว่าและมีแนวโน้มว่าจะได้รับแรงฉุดลากมากกว่า ดูบทความก่อนหน้าของฉันในหัวข้อนี้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับนวัตกรรมที่จะเกิดขึ้นและทรัพยากรเพิ่มเติมเกี่ยวกับเรื่องนี้

เทมเพลตเริ่มต้นสำหรับหน้าที่แสดงผลฝั่งไคลเอ็นต์

หน้าแสดงผลฝั่งไคลเอ็นต์จำนวนมาก หรือแอปหน้าเดียว แสดงผลหน้าพื้นฐานเริ่มต้นโดยใช้เพียง HTML และ CSS จากนั้น "ไฮเดรต" เทมเพลตหลังจากดาวน์โหลดและเรียกใช้ JavaScript

ง่ายสำหรับเทมเพลตเริ่มต้นเหล่านี้ที่จะไม่ซิงค์กับเวอร์ชัน JavaScript เนื่องจากมีการเพิ่มส่วนประกอบและคุณลักษณะใหม่ในแอปใน JavaScript แต่ไม่ได้เพิ่มลงในเทมเพลต HTML เริ่มต้นซึ่งแสดงผลก่อน สิ่งนี้ทำให้เกิด CLS เมื่อส่วนประกอบเหล่านี้ถูกฉีดโดย JavaScript

ดังนั้น ตรวจทานเทมเพลตเริ่มต้นทั้งหมดของคุณ เพื่อให้แน่ใจว่ายังคงเป็นตัวยึดตำแหน่งเริ่มต้นที่ดี และหากเทมเพลตเริ่มต้นประกอบด้วย <div> ที่ว่างเปล่า ให้ใช้เทคนิคด้านบนเพื่อให้แน่ใจว่ามีขนาดเหมาะสมเพื่อหลีกเลี่ยงการเปลี่ยนแปลงใดๆ

นอกจากนี้ div เริ่มต้นที่แทรกด้วยแอปควรมี min-height เพื่อหลีกเลี่ยงไม่ให้มีการแสดงผลด้วยความสูง 0 ในตอนแรกก่อนที่จะแทรกเทมเพลตเริ่มต้น

 <div></div>

ตราบใดที่ min-height นั้น มากกว่าวิวพอร์ตส่วนใหญ่ สิ่งนี้ควรหลีกเลี่ยง CLS สำหรับส่วนท้ายของเว็บไซต์ เป็นต้น CLS จะถูกวัดก็ต่อเมื่ออยู่ในวิวพอร์ตและส่งผลต่อผู้ใช้ ตามค่าเริ่มต้น div ที่ว่างเปล่าจะมีความสูงเป็น 0px ดังนั้นให้กำหนด min-height ที่ใกล้เคียงกับความสูงจริงเมื่อแอปโหลด

ตรวจสอบให้แน่ใจว่าการโต้ตอบกับผู้ใช้เสร็จสมบูรณ์ภายใน 500ms

การโต้ตอบของผู้ใช้ที่ทำให้เนื้อหาเปลี่ยนไปไม่รวมอยู่ในคะแนน CLS สิ่งเหล่านี้ถูกจำกัดไว้ที่ 500 ms หลังจากการโต้ตอบ ดังนั้น หากคุณคลิกที่ปุ่ม และทำการประมวลผลที่ซับซ้อนซึ่งใช้เวลามากกว่า 500 มิลลิวินาที จากนั้นจึงแสดงผลเนื้อหาใหม่ คะแนน CLS ของคุณจะลดลง

คุณสามารถดูว่า กะนั้นไม่รวมอยู่ใน Chrome DevTools หรือไม่ โดยใช้ แท็บประสิทธิภาพ เพื่อบันทึกหน้า จากนั้นค้นหากะตามที่แสดงในภาพหน้าจอถัดไป เปิด DevTools ไปที่แท็บ ประสิทธิภาพ (แต่มีประโยชน์มากเมื่อคุณเข้าใจ) จากนั้นคลิกที่ปุ่มบันทึกที่ด้านบนซ้าย (วงกลมบนภาพด้านล่าง) และโต้ตอบกับเพจของคุณ และหยุดการบันทึกเพียงครั้งเดียว เสร็จสิ้น.

ภาพหน้าจอของเครื่องมือ Chrome Dev ที่เลือกกะไว้ และบทสรุปนี้แสดงว่ามีอินพุตล่าสุด ดังนั้นการเปลี่ยนแปลงจึงไม่รวมอยู่ในคะแนนสะสม
การใช้แท็บประสิทธิภาพในเครื่องมือ Chrome Dev เพื่อดูว่ากะถูกแยกออกเนื่องจากการป้อนข้อมูลล่าสุดหรือไม่ (ตัวอย่างขนาดใหญ่)

คุณจะเห็นแถบฟิล์มของหน้าซึ่งฉันโหลดความคิดเห็นบางส่วนในบทความ Smashing Magazine อีกบทความหนึ่ง ดังนั้นในส่วนที่ฉันได้วงกลมไว้ คุณจะสามารถแสดงความคิดเห็นที่กำลังโหลดและส่วนท้ายสีแดงถูกเลื่อนลงนอกจอ ถัดจากแท็บ ประสิทธิภาพ ใต้บรรทัด ประสบการณ์ Chrome จะใส่กล่องสีแดงอมชมพูสำหรับแต่ละกะ และเมื่อคุณคลิกที่คุณจะได้รับรายละเอียดเพิ่มเติมในแท็บ สรุป ด้านล่าง

ที่นี่คุณจะเห็นว่าเราได้ คะแนน 0.3359 มหาศาล — ผ่านเกณฑ์ 0.1 ที่เราตั้งเป้าไว้ต่ำกว่าเกณฑ์ แต่ คะแนนสะสม ไม่ได้รวมไว้เพราะว่า อินพุตล่าสุด ถูกตั้งค่าเป็น "ใช้"

ตรวจสอบให้แน่ใจว่าการโต้ตอบเปลี่ยนเฉพาะเนื้อหาภายในขอบเขต 500 ms กับสิ่งที่ First Input Delay พยายามวัด แต่มีบางกรณีที่ผู้ใช้อาจเห็นว่าอินพุตมีผล (เช่น สปินเนอร์การโหลดจะปรากฏขึ้น) ดังนั้น FID นั้นดี แต่เนื้อหาอาจ ไม่ถูกเพิ่มลงในหน้าจนกว่าจะถึงขีดจำกัด 500 ms ดังนั้น CLS จึงไม่ดี

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

รายการอื่นๆ ที่ต้องระวังคือ แอนิเมชัน ที่ใช้เวลานานกว่า 500 มิลลิวินาที และอาจส่งผลกระทบต่อ CLS ได้ แม้ว่าสิ่งนี้อาจดูค่อนข้างจำกัด แต่เป้าหมายของ CLS ไม่ได้จำกัด "ความสนุก" แต่เพื่อกำหนดความคาดหวังที่สมเหตุสมผลสำหรับประสบการณ์ของผู้ใช้ และฉันไม่คิดว่าการคาดหวังสิ่งเหล่านี้จะใช้เวลา 500 มิลลิวินาทีหรือต่ำกว่านั้นไม่สมจริง แต่ถ้าคุณไม่เห็นด้วย หรือมีกรณีการใช้งานที่พวกเขาอาจไม่ได้พิจารณา ทีมงาน Chrome ก็ยินดีรับฟังความคิดเห็นเกี่ยวกับเรื่องนี้

JavaScript แบบซิงโครนัส

เทคนิคสุดท้ายที่ฉันจะพูดถึงนั้นค่อนข้างขัดแย้งกัน เนื่องจากขัดกับคำแนะนำด้านประสิทธิภาพเว็บที่เป็นที่รู้จัก แต่เป็นวิธีเดียวในบางสถานการณ์ โดยพื้นฐานแล้ว หากคุณมีเนื้อหาที่คุณรู้ว่าจะทำให้เกิดการเปลี่ยนแปลง วิธีแก้ปัญหาหนึ่งวิธีหลีกเลี่ยงการเปลี่ยนแปลงคืออย่าแสดงผลจนกว่าจะเรียบร้อย!

HTML ด้านล่างจะซ่อน div ในขั้นต้น จากนั้นโหลด JavaScript ที่บล็อกการแสดงผลเพื่อเติม div จากนั้นเลิกซ่อน เนื่องจาก JavaScript กำลังบล็อกการแสดงผล ไม่มีอะไรด้านล่างจึงแสดงผล (รวมถึงบล็อก style ที่สองเพื่อเลิกซ่อน) ดังนั้นจึงไม่มีการเปลี่ยนแปลงเกิดขึ้น

 <style> .cls-inducing-div { display: none; } </style> <div class="cls-inducing-div"></div> <script> ... </script> <style> .cls-inducing-div { display: block; } </style>

สิ่งสำคัญคือต้อง อินไลน์ CSS ใน HTML ด้วยเทคนิคนี้ ดังนั้นจึงใช้ตามลำดับ อีกทางเลือกหนึ่งคือเลิกซ่อนเนื้อหาด้วย JavaScript เอง แต่สิ่งที่ฉันชอบเกี่ยวกับเทคนิคข้างต้นคือมันยังคงเลิกซ่อนเนื้อหาแม้ว่า JavaScript จะล้มเหลวหรือถูกปิดโดยเบราว์เซอร์

เทคนิคนี้ยังสามารถนำไปใช้กับ JavaScript ภายนอกได้ แต่จะทำให้ล่าช้ากว่า script แบบอินไลน์เมื่อมีการร้องขอและดาวน์โหลด JavaScript ภายนอก ความล่าช้านั้นสามารถลดลงได้ด้วยการโหลดทรัพยากร JavaScript ล่วงหน้า เพื่อให้พร้อมใช้งานเร็วขึ้นเมื่อ parser ไปถึงส่วนของโค้ดนั้น:

 <head> ... <link rel="preload" href="cls-inducing-javascript.js" as="script"> ... </head> <body> ... <style> .cls-inducing-div { display: none; } </style> <div class="cls-inducing-div"></div> <script src="cls-inducing-javascript.js"></script> <style> .cls-inducing-div { display: block; } </style> ... </body>

อย่างที่ฉันพูด ฉันแน่ใจว่าจะทำให้ประสิทธิภาพของเว็บบางคนประจบประแจง ตามคำแนะนำคือการใช้ async, defer หรือ newer type="module" (ซึ่งเป็น defer -ed โดยค่าเริ่มต้น) บน JavaScript โดยเฉพาะเพื่อ หลีกเลี่ยงการบล็อก render ในขณะที่เราทำตรงกันข้ามที่นี่! อย่างไรก็ตาม หากไม่สามารถกำหนดเนื้อหาล่วงหน้าได้และจะทำให้เกิดการเปลี่ยนแปลงที่สั่นสะเทือน ก็แทบไม่มีประโยชน์ในการแสดงเนื้อหาตั้งแต่เนิ่นๆ

ฉันใช้เทคนิคนี้สำหรับ แบนเนอร์คุกกี้ ที่โหลดไว้ที่ด้านบนของหน้าและเลื่อนเนื้อหาลงด้านล่าง:

ภาพหน้าจอของหน้าเว็บที่เนื้อหาถูกเลื่อนลงเมื่อมีการเพิ่มแบนเนอร์คุกกี้ที่ด้านบนของหน้า
ประกาศเกี่ยวกับคุกกี้ที่ด้านบนของหน้าหรือแบนเนอร์อื่นๆ สามารถเลื่อนเนื้อหาลงได้ (ตัวอย่างขนาดใหญ่)

สิ่งนี้จำเป็นต้องอ่านคุกกี้เพื่อดูว่าจะแสดงแบนเนอร์คุกกี้หรือไม่ และแม้ว่าจะสามารถทำได้ในฝั่งเซิร์ฟเวอร์ แต่ก็เป็นไซต์คงที่ที่ไม่มีความสามารถในการแก้ไข HTML ที่ส่งคืนแบบไดนามิก

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

ฉันยังใช้เทคนิคนี้ในหน้าอื่นที่ JavaScript ย้ายเนื้อหาไปรอบๆ ลงในคอลัมน์ "หลัก" และ "ด้านข้าง" (ด้วยเหตุผลที่ฉันจะไม่เข้าไป มันเป็นไปไม่ได้ที่จะสร้างสิ่งนี้อย่างถูกต้องในฝั่งเซิร์ฟเวอร์ HTML) ซ่อนเนื้อหาอีกครั้ง จนกว่า JavaScript จะจัดเรียงเนื้อหาใหม่และแสดงเท่านั้น จึงหลีกเลี่ยงปัญหา CLS ที่ลากคะแนน CLS ของหน้าเหล่านี้ลง และอีกครั้ง เนื้อหาจะถูกยกเลิกการซ่อนโดยอัตโนมัติแม้ว่า JavaScript จะไม่ทำงานด้วยเหตุผลบางประการและแสดงเนื้อหาที่ไม่ได้เปลี่ยน

การใช้เทคนิคนี้อาจส่งผลต่อเมตริกอื่นๆ (โดยเฉพาะ LCP และ First Contentful Paint) เนื่องจากคุณกำลังชะลอการเรนเดอร์ และอาจบล็อกเบราว์เซอร์ที่รอโหลดล่วงหน้า แต่เป็นเครื่องมืออีกตัวที่ต้องพิจารณาสำหรับกรณีที่ไม่มีตัวเลือกอื่น

บทสรุป

Cumulative Layout Shift เกิดจากการเปลี่ยนแปลงขนาดเนื้อหา หรือเนื้อหาใหม่ถูกแทรกเข้าไปในหน้าโดย JavaScript ที่ทำงานช้า ในโพสต์นี้ เราได้พูดถึงเคล็ดลับและกลเม็ดต่างๆ เพื่อหลีกเลี่ยงปัญหานี้ ฉันดีใจที่ Core Web Vitals ได้รับความสนใจจากประเด็นที่น่ารำคาญนี้ — นักพัฒนาเว็บ (และฉันก็รวมตัวเองอยู่ในเรื่องนี้ด้วย) เพิกเฉยมานานเกินไป

การทำความสะอาดเว็บไซต์ของฉันเองทำให้ผู้เยี่ยมชมทุกคนได้รับประสบการณ์ที่ดีขึ้น เราขอแนะนำให้คุณ ดูปัญหา CLS ของคุณด้วย และหวังว่าเคล็ดลับเหล่านี้จะเป็นประโยชน์เมื่อคุณดำเนินการ ใครจะไปรู้ คุณอาจจะจัดการเพื่อให้ได้คะแนน CLS 0 ที่เข้าใจยากสำหรับหน้าเว็บทั้งหมดของคุณ!

แหล่งข้อมูลเพิ่มเติม

  • บทความ Core Web Vitals ที่นี่ใน Smashing Magazine รวมถึงบทความเกี่ยวกับการตั้งค่าความกว้างและความสูงบนรูปภาพ การวัด Core Web Vitals และ CSS Font Descriptors
  • เอกสาร Core Web Vitals ของ Google รวมถึงหน้าใน CLS
  • รายละเอียดเพิ่มเติมเกี่ยวกับการเปลี่ยนแปลงล่าสุดของ CLS จากนั้นการเปลี่ยนแปลงนี้ก็เริ่มอัปเดตในเครื่องมือต่างๆ ของ Google
  • CLS Changelog รายละเอียดการเปลี่ยนแปลงใน Chrome แต่ละเวอร์ชัน
  • คู่มือฉบับสมบูรณ์สำหรับการเปลี่ยนเค้าโครงสะสม โดย Jess Peck
  • การเปลี่ยนแปลงเค้าโครงสะสม: วัดและหลีกเลี่ยงความไม่เสถียรของภาพโดย Karolina Szczur
  • Layout Shift GIF Generator เพื่อช่วยสร้างการสาธิต CLS ที่แชร์ได้