ปลดล็อกพลังของคําค้นหาคอนเทนเนอร์ CSS: บทเรียนจากทีม Netflix

Jeremy Weeks
Jeremy Weeks
Stefan Heymanns
Stefan Heymanns

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

1. การออกแบบคอมโพเนนต์ที่เรียบง่าย "จากล่างขึ้นบน" เทียบกับ "จากบนลงล่าง"

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

ตัวอย่าง: การค้นหาคอนเทนเนอร์เทียบกับ Media Query และ JavaScript

ก่อน (ต้องใช้ JavaScript):

/* Layout with media queries */
.card {
    width: 100%;
}

@media (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@media (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}
// JavaScript to detect parent container size
const container = document.querySelector('.container');
const card = document.querySelector('.card');

function adjustLayout() {
    if (window.innerWidth >= 900) {
        card.style.width = '33.33%';
    } else if (window.innerWidth >= 600) {
        card.style.width = '50%';
    } else {
        card.style.width = '100%';
    }
}

window.addEventListener('resize', adjustLayout);
adjustLayout();

หลัง:

/* Container Query */
.container {
    container-type: inline-size;
}

.card {
    width: 100%;
}

@container (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@container (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}

ตัวอย่างนี้แสดงว่าคอนเทนเนอร์หลักไม่จําเป็นต้องจัดการเลย์เอาต์ย่อยอีกต่อไป กฎ @container ช่วยให้ .card ตอบสนองต่อขนาดของคอนเทนเนอร์โดยรอบได้โดยตรง ซึ่งจะลดความซับซ้อนของตรรกะเลย์เอาต์และไม่จำเป็นต้องใช้ JavaScript เลย

2. การตอบสนองโดยไม่มี Media Query ที่ซับซ้อน

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

ตัวอย่าง: การตอบสนองของคอมโพเนนต์กับคำค้นหาคอนเทนเนอร์

ก่อน:

/* Desktop versus Mobile
this only works if.sidebar is directly contained by a viewport-width element */
.sidebar {
    width: 300px;
}

@media (max-width: 768px) {
    .sidebar {
        width: 100%;
    }
}

หลัง:

/* Responsive sidebar based on container,
.sidebar can be placed in any element of any width */
.container {
    container-type: inline-size;
}

.sidebar {
    width: 100%;
}

@container (min-width: 768px) {
    .sidebar {
        width: 300px;
    }
}

ตอนนี้ .sidebar จะตอบสนองต่อขนาดคอนเทนเนอร์แทนที่จะใช้ Media Query ตามวิวพอร์ต ซึ่งช่วยให้ปรับให้เข้ากับเลย์เอาต์แบบไดนามิกได้อย่างเป็นธรรมชาติมากขึ้นโดยไม่ต้องทราบขนาดของวิวพอร์ตหรือคอนเทนเนอร์หลัก

3. ลดการพึ่งพา JavaScript ในการจัดการเลย์เอาต์

ก่อนที่จะมีการค้นหาคอนเทนเนอร์ ทีมต่างๆ รวมถึง Netflix ต้องพึ่งพา JavaScript สําหรับเลย์เอาต์แบบไดนามิก การค้นหาขนาดหน้าต่างจะทำให้ JavaScript ทริกเกอร์การเปลี่ยนแปลงเลย์เอาต์ ซึ่งจะเพิ่มความซับซ้อนและอาจทำให้เกิดข้อบกพร่องได้ คิวรีคอนเทนเนอร์จะช่วยลดความจำเป็นนี้ด้วยการเปิดโอกาสให้ CSS จัดการการปรับเปลี่ยนเลย์เอาต์ตามขนาดคอนเทนเนอร์

ตัวอย่าง: การนำตรรกะเลย์เอาต์ที่อิงตาม JavaScript ออก

ก่อน:

const cardContainer = document.querySelector('.card-container');
const cards = cardContainer.children;

function adjustLayout() {
    if (cardContainer.offsetWidth > 900) {
        cards.forEach(card => card.style.width = '33.33%');
    } else if (cardContainer.offsetWidth > 600) {
        cards.forEach(card => card.style.width = '50%');
    } else {
        cards.forEach(card => card.style.width = '100%');
    }
}

window.addEventListener('resize', adjustLayout);
adjustLayout();

หลัง:

.card-container {
    container-type: inline-size;
}

.card {
    width: 100%;
}

@container (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@container (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}

แนวทางนี้ไม่เพียงช่วยลดจํานวน JavaScript ที่จําเป็น แต่ยังช่วยปรับปรุงประสิทธิภาพด้วยการหลีกเลี่ยงการคํานวณรันไทม์

4. โค้ดน้อยลง ข้อบกพร่องน้อยลง

ทีม Netflix พบว่าการใช้การค้นหาคอนเทนเนอร์ทำให้โค้ดมีจำนวนบรรทัดน้อยลงและข้อบกพร่องเกี่ยวกับเลย์เอาต์ลดลง การย้ายตรรกะเลย์เอาต์จาก JavaScript ไปยัง CSS และการไม่ต้องใช้ Media Queries ที่ยุ่งยากช่วยให้นักพัฒนาแอปเขียนโค้ดที่ดูแลรักษาได้ง่ายขึ้น

ตัวอย่าง: การลดโค้ดเลย์เอาต์

ทีม Netflix พบว่าหลังจากใช้การค้นหาคอนเทนเนอร์แล้ว โค้ด CSS ลดลงอย่างมาก โดยลดลงถึง 30% สำหรับคอมโพเนนต์บางรายการ ในขณะเดียวกัน ทีมก็สามารถลดความซับซ้อนของคําค้นหาสื่อที่ซับซ้อนและบางครั้งก็ทำให้เกิดข้อขัดแย้งได้ด้วยการแยกตรรกะที่ควบคุมคอมโพเนนต์ย่อยออก เพื่อให้แยกข้อกังวลต่างๆ ในระดับที่สูงขึ้น การลดจำนวนนี้ไม่เพียงแต่จะเร่งการพัฒนา แต่ยังช่วยลดจุดที่อาจเกิดข้อผิดพลาดได้ ซึ่งส่งผลให้มีข้อบกพร่องน้อยลง

ก่อน:

/* Before with complex media queries */
.card {
    width: 100%;
}

@media (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@media (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}

หลัง

.container {
    container-type: inline-size;
}

.card {
    width: 100%;
}

@container (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@container (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}

5. ประสบการณ์การใช้งานที่ดีขึ้นสำหรับนักพัฒนาแอป

bq. "สิ่งนี้ทำให้ชีวิตฉันง่ายขึ้นหลายร้อยเท่า"

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

ดังที่สมาชิกคนหนึ่งจากทีม Netflix กล่าวไว้ว่า "CSS ควรทำงานแบบนี้มาตั้งแต่ต้น"

6. การแสดงผลสำรองด้วย Polyfill

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

if (! CSS.supports("container-type:size")) {
  /*use polyfill from
  https://www.npmjs.com/package/container-query-polyfill */
 }

บทสรุป

การค้นหาคอนเทนเนอร์เป็นก้าวสำคัญในการพัฒนา CSS ซึ่งช่วยให้นักพัฒนาซอฟต์แวร์สร้างคอมโพเนนต์ที่ยืดหยุ่นและตอบสนองได้ ซึ่งสามารถนำไปใช้ซ้ำในส่วนต่างๆ ของเว็บไซต์ได้ เทมเพลตเหล่านี้มีข้อดีอย่างมากทั้งในด้านประสิทธิภาพและการบำรุงรักษา เนื่องจากลดการพึ่งพา JavaScript สำหรับเลย์เอาต์ กำจัด Media Query ที่ซับซ้อน และเร่งการพัฒนา ปัจจุบัน Use Case ส่วนใหญ่อยู่ในหน้า Tudum ของ Netflix โดยมีแผนที่จะใช้การค้นหาคอนเทนเนอร์ในส่วนอื่นๆ ของ Netflix ทีม Netflix ถือว่าการค้นหาคอนเทนเนอร์เป็นเครื่องมือชั้นยอดในกล่องเครื่องมือของนักพัฒนาซอฟต์แวร์ และการใช้งานจะขยายตัวมากขึ้นเมื่อนักพัฒนาซอฟต์แวร์จำนวนมากขึ้นยอมรับความยืดหยุ่นและประสิทธิภาพที่เครื่องมือนี้มอบให้ ไม่ว่าคุณจะปรับแต่งคอมโพเนนต์ที่มีอยู่หรือออกแบบคอมโพเนนต์ใหม่ทั้งหมด การค้นหาคอนเทนเนอร์เป็นเส้นทางที่ง่ายและสะอาดขึ้นสำหรับการออกแบบที่ปรับเปลี่ยนตามอุปกรณ์

หากยังไม่ได้ลองใช้การค้นหาคอนเทนเนอร์ ให้ลองใช้ดู คุณอาจพบว่าการค้นหานี้ช่วยลดความซับซ้อนของเวิร์กโฟลว์ในแบบที่คาดไม่ถึง