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

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

ในโพสต์ก่อนหน้านี้ ฉันได้เขียนเกี่ยวกับการวัดการเปลี่ยนแปลงเลย์เอาต์สะสม (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 เสถียรแล้ว API ความไม่เสถียรของเลย์เอาต์จะเปิดใช้โดยค่าเริ่มต้น คุณจึงควรเรียกใช้ข้อมูลโค้ด JS นั้นในเว็บไซต์ใดก็ได้ภายใน Chrome 77 และรับผลลัพธ์ได้ทันที ใน WebPageTest คุณสามารถใช้เบราว์เซอร์ Chrome เริ่มต้นได้โดยไม่ต้องกังวลเกี่ยวกับแฟล็กบรรทัดคำสั่งหรือการใช้ 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});
});

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

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

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

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

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

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

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

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

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

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

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

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