แนวทางปฏิบัติแนะนำสำหรับการโหลดแบบ Lazy Loading

แม้ว่าการโหลดแบบ Lazy Loading รูปภาพและวิดีโอจะให้ผลดีด้านประสิทธิภาพและวัดผลได้ แต่คุณไม่ควรมองข้าม ถ้าคุณเข้าใจผิด คุณอาจได้รับ ผลที่ตามมาโดยไม่เจตนา ดังนั้น คุณจึงควรตระหนักถึงข้อกังวลต่างๆ ต่อไปนี้

คำนึงถึงเส้นแบ่ง

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

การโหลดแบบ Lazy Loading จะทำให้การโหลดทรัพยากรล่าช้าลงจนกว่า DOM จะมีการโต้ตอบเมื่อสคริปต์โหลดเสร็จแล้วและเริ่มต้นการดำเนินการ สำหรับรูปภาพที่อยู่ครึ่งหน้าล่างก็ทำได้ แต่ทรัพยากรสำคัญในครึ่งหน้าบนควรโหลดด้วยองค์ประกอบ <img> มาตรฐานเพื่อให้แสดงได้โดยเร็วที่สุด

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

นอกจากนี้ คุณอาจไม่ต้องการความเข้มงวดกับเส้นแบ่งครึ่งเหมือนเกณฑ์สำหรับการทริกเกอร์การโหลดแบบ Lazy Loading การสร้างโซนบัฟเฟอร์ในช่วงครึ่งหน้าล่างอาจเหมาะสำหรับวัตถุประสงค์ของคุณมากกว่า เพื่อให้รูปภาพเริ่มโหลดได้ดีก่อนที่ผู้ใช้จะเลื่อนรูปภาพเข้าสู่วิวพอร์ต ตัวอย่างเช่น Intersection Observer API ช่วยให้คุณระบุพร็อพเพอร์ตี้ rootMargin ในออบเจ็กต์ตัวเลือกได้เมื่อสร้างอินสแตนซ์ IntersectionObserver ใหม่ การดำเนินการนี้จะทำให้องค์ประกอบมีบัฟเฟอร์ ซึ่งจะทริกเกอร์พฤติกรรมการโหลดแบบ Lazy Loading ก่อนที่องค์ประกอบจะอยู่ในวิวพอร์ต

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

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

หากต้องการผลลัพธ์เดียวกันนี้ในเบราว์เซอร์ที่ไม่รองรับ "Intersection Observe" ให้ใช้โค้ดการจัดการเหตุการณ์การเลื่อนและปรับการตรวจสอบ getBoundingClientRect เพื่อรวมบัฟเฟอร์

การเปลี่ยนเลย์เอาต์และตัวยึดตำแหน่ง

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

สำหรับแท็ก <img> ในขั้นต้น src ควรชี้ไปยังตัวยึดตำแหน่งจนกว่าจะอัปเดตแอตทริบิวต์ด้วย URL ของรูปภาพสุดท้าย ใช้แอตทริบิวต์ poster ในองค์ประกอบ <video> เพื่อชี้ไปยังรูปภาพตัวยึดตำแหน่ง นอกจากนี้ ให้ใช้แอตทริบิวต์ width และ height ทั้งในแท็ก <img> และ <video> วิธีนี้ช่วยให้มั่นใจว่าการเปลี่ยนจากตัวยึดตำแหน่งเป็นรูปภาพสุดท้ายจะไม่เปลี่ยนขนาดที่แสดงผลขององค์ประกอบเมื่อโหลดสื่อ

ความล่าช้าในการถอดรหัสรูปภาพ

การโหลดรูปภาพขนาดใหญ่ใน JavaScript แล้ววางลงใน DOM อาจเชื่อมโยงเทรดหลัก ทำให้อินเทอร์เฟซผู้ใช้ไม่ตอบสนองเป็นระยะเวลาสั้นๆ ขณะที่ถอดรหัส การถอดรหัสรูปภาพแบบไม่พร้อมกันโดยใช้เมธอด decode ก่อนการแทรกรูปภาพลงใน DOM จะช่วยลดความยุ่งยากประเภทนี้ได้ แต่โปรดระวัง: มีให้บริการในบางพื้นที่เท่านั้นและช่วยเพิ่มความซับซ้อนให้กับตรรกะการโหลดแบบ Lazy Loading หากต้องการใช้ คุณจะต้องตรวจสอบก่อน ด้านล่างนี้แสดงวิธีใช้ Image.decode() พร้อมทางเลือกสำรอง

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

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

เมื่อเนื้อหาไม่โหลด

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

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

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

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

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

ความพร้อมใช้งานของ JavaScript

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

ฉันเป็นรูปภาพ!

หากปิด JavaScript ไว้ ผู้ใช้จะเห็นทั้งรูปภาพตัวยึดตำแหน่งและรูปภาพที่มีองค์ประกอบ <noscript> ในการแก้ปัญหานี้ ให้วางคลาสของ no-js ในแท็ก <html> ดังนี้

<html class="no-js">

จากนั้นวางสคริปต์ในหน้า 1 บรรทัดใน <head> ก่อนที่จะมีการขอสไตล์ชีตใดๆ ผ่านแท็ก <link> ซึ่งนำคลาส no-js ออกจากองค์ประกอบ <html> หาก JavaScript เปิดอยู่

<script>document.documentElement.classList.remove("no-js");</script>

สุดท้าย ใช้ CSS บางส่วนเพื่อซ่อนองค์ประกอบด้วยคลาสแบบ Lazy Loading เมื่อ JavaScript ไม่พร้อมใช้งาน

.no-js .lazy {
  display: none;
}

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