การแก้ไขความไม่เสถียรของเลย์เอาต์

คำแนะนำในการใช้ WebPageTest เพื่อระบุและแก้ไขปัญหาความเสถียรของเลย์เอาต์

ในโพสต์ก่อนหน้านี้ เราได้เขียนเกี่ยวกับการวัด Cumulative Layout Shift (CLS) ใน WebPageTest CLS คือการรวมการเปลี่ยนแปลงเลย์เอาต์ทั้งหมด ดังนั้นในโพสต์นี้ เราจึงคิดว่าการเจาะลึกและตรวจสอบการเปลี่ยนแปลงเลย์เอาต์แต่ละรายการในหน้าเว็บเพื่อพยายามทำความเข้าใจสิ่งที่อาจทำให้เกิดความไม่เสถียรและพยายามแก้ไขปัญหาจริงน่าจะน่าสนใจ

เมื่อใช้ Layout Instability API เราจะดูรายการเหตุการณ์การเปลี่ยนแปลงเลย์เอาต์ทั้งหมดในหน้าเว็บได้ ดังนี้

new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(list.getEntries().filter(entry => !entry.hadRecentInput));
  }).observe({type: "layout-shift", buffered: true});
}).then(console.log);

ซึ่งจะสร้างอาร์เรย์ของการเปลี่ยนเลย์เอาต์ที่ไม่มีเหตุการณ์อินพุตนำหน้า

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 210.78500000294298,
    "duration": 0,
    "value": 0.0001045969445437389,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

ในตัวอย่างนี้ มีการเลื่อนเพียงครั้งเดียวเพียง 0.01% ที่ 210 มิลลิวินาที

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

การวัดการเปลี่ยนแปลงเลย์เอาต์ใน WebPageTest

การวัดการเปลี่ยนแปลงเลย์เอาต์แต่ละรายการต้องใช้เมตริกที่กําหนดเอง ซึ่งคล้ายกับการวัด CLS ใน WebPageTest แต่โชคดีที่ตอนนี้ Chrome 77 เป็นเวอร์ชันเสถียรแล้ว กระบวนการนี้จึงง่ายขึ้น Layout Instability API จะเปิดใช้โดยค่าเริ่มต้น คุณจึงสามารถเรียกใช้สnippet JS นั้นในเว็บไซต์ใดก็ได้ภายใน Chrome 77 และรับผลลัพธ์ได้ทันที ใน WebPageTest คุณสามารถใช้เบราว์เซอร์ Chrome เริ่มต้นได้โดยไม่ต้องกังวลเกี่ยวกับ Flag บรรทัดคำสั่งหรือการใช้ Canary

มาแก้ไขสคริปต์นั้นเพื่อสร้างเมตริกที่กําหนดเองสําหรับ WebPageTest กัน

[LayoutShifts]
return new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(JSON.stringify(list.getEntries().filter(entry => !entry.hadRecentInput)));
  }).observe({type: "layout-shift", buffered: true});
});

พรอมต์ในสคริปต์นี้จะแสดงผลเป็นการแสดง JSON ของอาร์เรย์แทนที่จะเป็นอาร์เรย์ เนื่องจากเมตริกที่กําหนดเองจะสร้างได้เฉพาะประเภทข้อมูลพื้นฐาน เช่น สตริงหรือตัวเลข

เว็บไซต์ที่เราจะใช้ในการทดสอบคือ ismyhostfastyet.com ซึ่งเป็นเว็บไซต์ที่เราสร้างขึ้นเพื่อเปรียบเทียบประสิทธิภาพการโหลดของเว็บโฮสติ้งในชีวิตจริง

การระบุสาเหตุของเลย์เอาต์ที่ไม่เสถียร

ในผลลัพธ์ เราเห็นว่าเมตริกที่กําหนดเองของ LayoutShifts มีค่าดังนี้

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3087.2349999990547,
    "duration": 0,
    "value": 0.3422101449275362,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

โดยสรุปคือมีการเปลี่ยนเลย์เอาต์ 1 ครั้ง 34.2% ที่เกิดขึ้นที่ 3087 มิลลิวินาที เพื่อช่วยระบุตัวการ เรามาลองใช้มุมมองภาพสไลด์ของ WebPageTest

2 เซลล์ในแถบแสดงตัวอย่างภาพ ซึ่งแสดงภาพหน้าจอก่อนและหลังการเปลี่ยนแปลงเลย์เอาต์
2 เซลล์ในแถบแสดงตัวอย่างภาพ ซึ่งแสดงภาพหน้าจอก่อนและหลังการเปลี่ยนแปลงเลย์เอาต์

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

บรรทัดแรกแบบอักษรบนเว็บปรากฏขึ้นอย่างไม่ทราบสาเหตุ
ส่วนหัวแบบอักษรเว็บปรากฏขึ้นอย่างไม่ทราบที่มา

แต่ยังไม่หมดเพียงเท่านี้ เมื่อหน้าเว็บแสดงผลอย่างสมบูรณ์ใน ~4.3 วินาที เราจะเห็นว่า <h1> ของหน้า "โฮสต์ของฉันเร็วขึ้นหรือยัง" ปรากฏขึ้นอย่างกะทันหัน ปัญหานี้เกิดขึ้นเนื่องจากเว็บไซต์ใช้แบบอักษรเว็บและไม่ได้ดำเนินการใดๆ เพื่อเพิ่มประสิทธิภาพการแสดงผล เลย์เอาต์ไม่ได้ดูเหมือนจะเลื่อนไปเมื่อเกิดเหตุการณ์นี้ขึ้น แต่ประสบการณ์ของผู้ใช้ก็ยังคงแย่อยู่เนื่องจากต้องรอนานมากจึงจะอ่านชื่อได้

การแก้ไขความผันผวนของเลย์เอาต์

เมื่อทราบว่าตารางที่สร้างขึ้นแบบไม่พร้อมกันทําให้วิวพอร์ตเลื่อนไป 1 ใน 3 ของพื้นที่ทำงาน ก็ถึงเวลาแก้ไข เราจะไม่ทราบเนื้อหาของตารางจนกว่าระบบจะโหลดผลลัพธ์ JSON จริงๆ แต่เรายังคงป้อนข้อมูลตัวยึดตำแหน่งบางประเภทลงในตารางได้เพื่อให้เลย์เอาต์ค่อนข้างเสถียรเมื่อระบบแสดงผล DOM

โค้ดในการสร้างข้อมูลตัวยึดตําแหน่งมีดังนี้

function getRandomFiller(maxLength) {
  var filler = '█';
  var len = Math.ceil(Math.random() * maxLength);
  return new Array(len).fill(filler).join('');
}

function getRandomDistribution() {
  var fast = Math.random();
  var avg = (1 - fast) * Math.random();
  var slow = 1 - (fast + avg);
  return [fast, avg, slow];
}

// Temporary placeholder data.
window.data = [];
for (var i = 0; i < 36; i++) {
  var [fast, avg, slow] = getRandomDistribution();
  window.data.push({
    platform: getRandomFiller(10),
    client: getRandomFiller(5),
    n: getRandomFiller(1),
    fast,
    avg,
    slow
  });
}
updateResultsTable(sortResults(window.data, 'fast'));

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

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

ตัวยึดตําแหน่งมีลักษณะดังนี้ขณะที่โหลดข้อมูล JSON

ตารางข้อมูลจะแสดงผลด้วยข้อมูลตัวยึดตําแหน่ง
ตารางข้อมูลจะแสดงผลด้วยข้อมูลตัวยึดตําแหน่ง

การแก้ไขปัญหาแบบอักษรเว็บนั้นง่ายกว่ามาก เนื่องจากเว็บไซต์ใช้ Google Fonts เราจึงต้องส่งพร็อพเพอร์ตี้ display=swap ในคําขอ CSS ไม่มีแล้ว Fonts API จะเพิ่มรูปแบบ font-display: swap ในการประกาศแบบอักษร ซึ่งจะช่วยให้เบราว์เซอร์แสดงผลข้อความในรูปแบบอักษรสำรองได้ทันที มาร์กอัปที่เกี่ยวข้องพร้อมการแก้ไขมีดังนี้

<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">

ยืนยันการเพิ่มประสิทธิภาพ

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

ภาพสไลด์ของ WebPageTest ที่แสดงทั้ง 2 เว็บไซต์ที่โหลดอยู่เคียงข้างกันโดยมีและไม่มีการเพิ่มประสิทธิภาพเลย์เอาต์
แถบแสดงตัวอย่างของ WebPageTest ที่แสดงการโหลดเว็บไซต์ทั้ง 2 แห่งควบคู่กันโดยมีและไม่มีการเพิ่มประสิทธิภาพเลย์เอาต์
[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3070.9349999997357,
    "duration": 0,
    "value": 0.000050272187989256116,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

จากเมตริกที่กําหนดเอง พบว่ายังคงมีการเปลี่ยนเลย์เอาต์เกิดขึ้นที่ 3071 มิลลิวินาที (ประมาณเท่าเดิม) แต่ความรุนแรงของการเปลี่ยนแปลงนั้นลดลงมากเป็น 0.005% เรายอมรับผลลัพธ์นี้

นอกจากนี้ ฟีเจอร์นี้ยังช่วยให้ผู้ใช้อ่านได้เร็วขึ้นด้วย เนื่องจากจากแถบแสดงตัวอย่างจะเห็นว่าแบบอักษร <h1> จะเปลี่ยนไปใช้แบบอักษรของระบบทันที

บทสรุป

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

(อีกเรื่องหนึ่ง) การวัดความผันผวนของเลย์เอาต์ที่ผู้ใช้จริงพบ

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

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

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