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

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

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

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

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

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