จัดแต่งทรงผมส่วนประกอบเว็บโดยใช้สไตล์ชีตที่ใช้ร่วมกัน
เผยแพร่แล้ว: 2022-03-10องค์ประกอบของเว็บเป็นคุณลักษณะใหม่ที่น่าทึ่งของเว็บ ทำให้นักพัฒนาสามารถกำหนดองค์ประกอบ HTML ที่กำหนดเองได้ เมื่อรวมกับคู่มือสไตล์ ส่วนประกอบของเว็บสามารถสร้าง API ส่วนประกอบได้ ซึ่งช่วยให้นักพัฒนาหยุดการคัดลอกและวางข้อมูลโค้ด และใช้เพียงองค์ประกอบ DOM แทน ด้วยการใช้ shadow DOM เราสามารถสรุปองค์ประกอบเว็บและไม่ต้องกังวลกับสงครามเฉพาะกับสไตล์ชีตอื่น ๆ บนหน้า
อย่างไรก็ตาม องค์ประกอบของเว็บและคู่มือสไตล์ในปัจจุบันดูเหมือนจะไม่ตรงกัน ในอีกด้านหนึ่ง คู่มือสไตล์จะจัดเตรียมชุดของกฎและสไตล์ที่นำไปใช้กับเพจทั่วโลก และรับรองความสอดคล้องกันทั่วทั้งเว็บไซต์ ในทางกลับกัน ส่วนประกอบของเว็บที่มี Shadow DOM จะป้องกันไม่ให้สไตล์โกลบอลแทรกซึมการห่อหุ้ม ดังนั้นจึงป้องกันไม่ให้คู่มือสไตล์ส่งผลกระทบต่อสไตล์เหล่านั้น
อ่านเพิ่มเติม เกี่ยวกับ SmashingMag:
- การบังคับใช้แนวทางปฏิบัติที่ดีที่สุดในระบบที่ใช้ส่วนประกอบ
- วิธีใช้ตัวประมวลผลล่วงหน้า LESS CSS สำหรับสไตล์ชีตที่ชาญฉลาด
- เจาะลึก Adobe Edge Reflow
ดังนั้น ทั้งสองจะสามารถอยู่ร่วมกันได้อย่างไร โดยคู่มือสไตล์สากลยังคงให้ความสอดคล้องและสไตล์อย่างต่อเนื่อง แม้กระทั่งองค์ประกอบเว็บที่มี Shadow DOM โชคดีที่มีโซลูชันที่ใช้งานได้ในปัจจุบัน และโซลูชันอื่นๆ ที่จะตามมา ซึ่งช่วยให้คู่มือสไตล์ทั่วโลกสามารถจัดสไตล์ให้กับส่วนประกอบเว็บได้ (สำหรับส่วนที่เหลือของบทความนี้ ฉันจะใช้คำว่า "ส่วนประกอบเว็บ" เพื่ออ้างถึงองค์ประกอบที่กำหนดเองด้วย Shadow DOM)
สไตล์คู่มือสไตล์สากลควรเป็นอย่างไรในคอมโพเนนต์ของเว็บ
ก่อนพูดคุยถึงวิธีรับคู่มือสไตล์ส่วนกลางเพื่อจัดรูปแบบองค์ประกอบเว็บ เราควรหารือเกี่ยวกับสิ่งที่ควรและไม่ควรพยายามจัดรูปแบบ
ประการแรก แนวทางปฏิบัติที่ดีที่สุดในปัจจุบันสำหรับองค์ประกอบของเว็บระบุว่าควรมีการห่อหุ้มคอมโพเนนต์ของเว็บ รวมถึงรูปแบบขององค์ประกอบ เพื่อไม่ให้ต้องพึ่งพาทรัพยากรภายนอกในการทำงาน ซึ่งช่วยให้สามารถใช้งานได้ทุกที่ทั้งในและนอกเว็บไซต์ แม้ในขณะที่คู่มือสไตล์ไม่พร้อมใช้งาน
ด้านล่างนี้คือส่วนประกอบเว็บแบบฟอร์มการเข้าสู่ระบบอย่างง่ายที่สรุปสไตล์ทั้งหมด
<template> <style> :host { color: #333333; font: 16px Arial, sans-serif; } p { margin: 0; } p + p { margin-top: 20px; } a { color: #1f66e5; } label { display: block; margin-bottom: 5px; } input[type="text"], input[type="password"] { background-color: #eaeaea; border: 1px solid grey; border-radius: 4px; box-sizing: border-box; color: inherit; font: inherit; padding: 10px 10px; width: 100%; } input[type="submit"] { font: 16px/1.6 Arial, sans-serif; color: white; background: cornflowerblue; border: 1px solid #1f66e5; border-radius: 4px; padding: 10px 10px; width: 100%; } .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <div class="container"> <form action="#"> <p> <label for="username">User Name</label> <input type="text" name="username"> </p> <p> <label for="password">Password</label> <input type="password" name="password"> </p> <p> <input type="submit" value="Login"> </p> <p class="footnote">Not registered? <a href="#">Create an account</a></p> </form> </div> </template> <script> const doc = (document._currentScript || document.currentScript).ownerDocument; const template = doc.querySelector('#login-form-template'); customElements.define('login-form', class extends HTMLElement { constructor() { super(); const root = this.attachShadow({mode: 'closed'}); const temp = document.importNode(template.content, true); root.appendChild(temp); } }); </script>
หมายเหตุ: ตัวอย่างโค้ดเขียนในข้อกำหนดเวอร์ชัน 1 สำหรับส่วนประกอบเว็บ

อย่างไรก็ตาม การห่อหุ้มองค์ประกอบเว็บทั้งหมดอย่างหลีกเลี่ยงไม่ได้จะนำไปสู่ CSS ที่ซ้ำกันจำนวนมาก โดยเฉพาะอย่างยิ่งเมื่อพูดถึงการตั้งค่าการออกแบบตัวอักษรและการจัดสไตล์ขององค์ประกอบดั้งเดิม หากนักพัฒนาต้องการใช้ย่อหน้า แท็ก anchor หรือช่องป้อนข้อมูลในคอมโพเนนต์เว็บ ควรจัดรูปแบบให้เหมือนกับส่วนอื่นๆ ของเว็บไซต์
หากเราสรุปลักษณะทั้งหมดที่องค์ประกอบเว็บต้องการโดยสมบูรณ์ CSS สำหรับการจัดรูปแบบย่อหน้า แท็กจุดยึด ฟิลด์อินพุต และอื่นๆ จะถูกทำซ้ำในส่วนประกอบเว็บทั้งหมดที่ใช้รูปแบบเหล่านี้ ซึ่งจะไม่เพียงแต่เพิ่มค่าใช้จ่ายในการบำรุงรักษา แต่ยังนำไปสู่ขนาดการดาวน์โหลดที่ใหญ่ขึ้นสำหรับผู้ใช้อีกด้วย
แทนที่จะห่อหุ้มสไตล์ทั้งหมด องค์ประกอบของเว็บควรสรุปเฉพาะสไตล์ที่เป็นเอกลักษณ์ จากนั้นจึงใช้ชุดของสไตล์ที่ใช้ร่วมกันเพื่อจัดการกับสไตล์สำหรับอย่างอื่น สไตล์ที่ใช้ร่วมกันเหล่านี้โดยพื้นฐานแล้วจะกลายเป็น Normalize.css ซึ่งคอมโพเนนต์ของเว็บสามารถใช้เพื่อให้แน่ใจว่าองค์ประกอบดั้งเดิมได้รับการจัดสไตล์ตามคู่มือสไตล์
ในตัวอย่างก่อนหน้านี้ เว็บคอมโพเนนต์ของแบบฟอร์มการเข้าสู่ระบบจะประกาศสไตล์สำหรับสองคลาสที่ไม่ซ้ำกันเท่านั้น: .container
และ . .footnote
สไตล์ที่เหลือจะอยู่ในสไตล์ชีตที่ใช้ร่วมกัน และจะจัดรูปแบบย่อหน้า แท็กสมอ ฟิลด์อินพุต และอื่นๆ
กล่าวโดยย่อ คู่มือสไตล์ไม่ควรพยายามจัดรูปแบบองค์ประกอบเว็บ แต่ควรจัดเตรียมชุดของสไตล์ที่ใช้ร่วมกันซึ่งส่วนประกอบของเว็บสามารถใช้เพื่อให้ได้รูปลักษณ์ที่สอดคล้องกัน
การใส่สไตล์ Shadow DOM ด้วยสไตล์ชีตภายนอกที่ใช้ทำเสร็จแล้ว
ข้อมูลจำเพาะเบื้องต้นสำหรับส่วนประกอบเว็บ (เรียกว่าเวอร์ชัน 0) อนุญาตให้สไตล์ชีตภายนอกเจาะเข้าไปใน Shadow DOM ผ่านการใช้ตัวเลือก ::shadow
หรือ /deep/
CSS การใช้ ::shadow
และ /deep/
ช่วยให้คุณมีไกด์สไตล์เจาะลึก Shadow DOM และตั้งค่าสไตล์ที่ใช้ร่วมกันได้ ไม่ว่าองค์ประกอบของเว็บจะต้องการให้คุณทำหรือไม่ก็ตาม
/* Style all p tags inside a web components shadow DOM */ login-form::shadow p { color: red; }
ด้วยการถือกำเนิดของข้อกำหนดองค์ประกอบของเว็บเวอร์ชันใหม่ล่าสุด (หรือที่เรียกว่าเวอร์ชัน 1) ผู้เขียนได้นำความสามารถของสไตล์ชีตภายนอกเพื่อเจาะเข้าไปใน Shadow DOM และไม่มีทางเลือกอื่น ปรัชญาได้เปลี่ยนจากการใช้มังกรเป็นองค์ประกอบเว็บที่มีสไตล์เป็นการใช้บริดจ์แทน กล่าวอีกนัยหนึ่ง ผู้เขียนองค์ประกอบเว็บควรรับผิดชอบกฎของสไตล์ภายนอกที่ได้รับอนุญาตให้จัดรูปแบบองค์ประกอบ แทนที่จะถูกบังคับให้อนุญาต
น่าเสียดายที่ปรัชญานั้นยังไม่ทันกับเว็บจริงๆ ซึ่งทำให้เราต้องลำบากหน่อย โชคดีที่มีโซลูชันบางอย่างในปัจจุบัน และบางโซลูชันที่กำลังจะมีขึ้นในอนาคตอันใกล้ จะช่วยให้สไตล์ชีตที่ใช้ร่วมกันจัดรูปแบบองค์ประกอบเว็บได้
วันนี้คุณทำอะไรได้บ้าง
มีสามเทคนิคที่คุณสามารถใช้ได้ในปัจจุบัน ซึ่งจะช่วยให้คอมโพเนนต์ของเว็บแชร์สไตล์ได้: @import
องค์ประกอบที่กำหนดเอง และไลบรารีคอมโพเนนต์ของเว็บ
ใช้ @import
วิธีเดียวที่จะนำสไตล์ชีตมาไว้ในองค์ประกอบเว็บในปัจจุบันคือการใช้ @import
แม้ว่าจะใช้งานได้ แต่ก็เป็นรูปแบบต่อต้าน อย่างไรก็ตาม สำหรับองค์ประกอบของเว็บ ปัญหาด้านประสิทธิภาพที่ใหญ่กว่านั้น
<template> <style> @import "styleguide.css" </style> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- rest of template DOM --> </template>
โดยปกติ @import
จะเป็น anti-pattern เพราะมันดาวน์โหลดสไตล์ชีตทั้งหมดเป็นชุด แทนที่จะทำแบบคู่ขนาน โดยเฉพาะอย่างยิ่งถ้าพวกมันซ้อนกัน ในสถานการณ์ของเรา การดาวน์โหลดสไตล์ชีตเดียวในซีรีส์ไม่สามารถช่วยได้ ดังนั้นในทางทฤษฎีแล้ว ก็น่าจะเป็นเรื่องปกติ แต่เมื่อฉันทดสอบสิ่งนี้ใน Chrome ผลลัพธ์พบว่าการใช้ @import
ทำให้หน้าเว็บแสดงผลช้ากว่าเมื่อเพียงแค่ฝังสไตล์ลงในส่วนประกอบเว็บโดยตรงถึงครึ่งวินาที
หมายเหตุ: เนื่องจากความแตกต่างในการทำงานของ polyfill ของการนำเข้า HTML เมื่อเทียบกับการนำเข้า HTML ดั้งเดิม WebPagetest.org จึงสามารถใช้ได้เฉพาะเพื่อให้ผลลัพธ์ที่เชื่อถือได้ในเบราว์เซอร์ที่สนับสนุนการนำเข้า HTML ดั้งเดิม (เช่น Chrome)

@import
ทำให้เบราว์เซอร์แสดงผลช้ากว่าเมื่อเพียงแค่ฝังสไตล์ลงในองค์ประกอบเว็บโดยตรงถึงครึ่งวินาที ในท้ายที่สุด @import
ยังคงเป็นรูปแบบต่อต้านและอาจเป็นปัญหาด้านประสิทธิภาพในส่วนประกอบเว็บ ดังนั้นจึงไม่ใช่วิธีแก้ปัญหาที่ดี
อย่าใช้ Shadow DOM
เนื่องจากปัญหาในการพยายามจัดเตรียมรูปแบบที่ใช้ร่วมกันให้กับคอมโพเนนต์ของเว็บนั้นเกิดจากการใช้ Shadow DOM วิธีหนึ่งในการหลีกเลี่ยงปัญหาทั้งหมดคือการไม่ใช้ Shadow DOM
โดยไม่ใช้ Shadow DOM คุณจะสร้างองค์ประกอบที่กำหนดเองแทนองค์ประกอบเว็บ (ดูด้านล่าง) ความแตกต่างเพียงอย่างเดียวคือการขาด DOM เงาและการกำหนดขอบเขต องค์ประกอบของคุณจะขึ้นอยู่กับสไตล์ของหน้า แต่วันนี้เราต้องจัดการกับมันแล้ว ไม่มีอะไรที่เรายังไม่รู้ว่าจะจัดการอย่างไร องค์ประกอบที่กำหนดเองได้รับการสนับสนุนอย่างเต็มที่โดย webcomponentjs polyfill ซึ่งรองรับเบราว์เซอร์ที่ยอดเยี่ยม
ประโยชน์สูงสุดขององค์ประกอบแบบกำหนดเองคือคุณสามารถสร้างไลบรารีรูปแบบได้โดยใช้องค์ประกอบเหล่านี้วันนี้ และไม่ต้องรอจนกว่าปัญหาของการจัดสไตล์ที่ใช้ร่วมกันจะได้รับการแก้ไข และเนื่องจากความแตกต่างเพียงอย่างเดียวระหว่างองค์ประกอบของเว็บและองค์ประกอบที่กำหนดเองคือ Shadow DOM คุณจึงสามารถเปิดใช้งาน Shadow DOM ในองค์ประกอบที่กำหนดเองได้เสมอเมื่อมีโซลูชันสำหรับสไตล์ที่ใช้ร่วมกัน
หากคุณตัดสินใจที่จะสร้างองค์ประกอบแบบกำหนดเอง โปรดระวังความแตกต่างเล็กน้อยระหว่างองค์ประกอบแบบกำหนดเองและส่วนประกอบเว็บ
ประการแรก เนื่องจากสไตล์สำหรับองค์ประกอบที่กำหนดเองจะขึ้นอยู่กับสไตล์ของเพจและในทางกลับกัน คุณจะต้องแน่ใจว่าตัวเลือกของคุณไม่ก่อให้เกิดความขัดแย้งใดๆ หากหน้าเว็บของคุณใช้สไตล์ไกด์อยู่แล้ว ให้ปล่อยสไตล์สำหรับองค์ประกอบที่กำหนดเองไว้ในคู่มือสไตล์ และให้องค์ประกอบนั้นส่งออก DOM และโครงสร้างคลาสที่คาดไว้
เมื่อปล่อยให้สไตล์อยู่ในคู่มือสไตล์ คุณจะสร้างเส้นทางการย้ายที่ราบรื่นสำหรับนักพัฒนาของคุณ เนื่องจากพวกเขาสามารถใช้คู่มือสไตล์ต่อไปได้เหมือนเมื่อก่อน แต่จะค่อยย้ายไปใช้องค์ประกอบที่กำหนดเองใหม่เมื่อสามารถทำได้ เมื่อทุกคนใช้องค์ประกอบที่กำหนดเองแล้ว คุณสามารถย้ายสไตล์ให้อยู่ภายในองค์ประกอบเพื่อรวมเข้าด้วยกันและเพื่อให้สามารถจัดองค์ประกอบเว็บใหม่ได้ง่ายขึ้นในภายหลัง
ประการที่สอง ต้องแน่ใจว่าได้แค็ปซูลโค้ด JavaScript ใดๆ ภายในนิพจน์ฟังก์ชันที่เรียกใช้ทันที (IFFE) เพื่อที่คุณจะได้ไม่ตกตัวแปรใดๆ ไปยังขอบเขตส่วนกลาง นอกเหนือจากการไม่ให้การกำหนดขอบเขต CSS แล้ว องค์ประกอบที่กำหนดเองไม่ได้จัดเตรียมการกำหนดขอบเขต JavaScript
ประการที่สาม คุณจะต้องใช้ฟังก์ชัน connectedCallback
ขององค์ประกอบที่กำหนดเองเพื่อเพิ่ม DOM เทมเพลตให้กับองค์ประกอบ ตามข้อกำหนดของส่วนประกอบเว็บ องค์ประกอบที่กำหนดเองไม่ควรเพิ่มลูกระหว่างฟังก์ชันตัวสร้าง ดังนั้น คุณจะต้องเลื่อนการเพิ่ม DOM ไปที่ฟังก์ชัน connectedCallback
สุดท้าย <slot>
องค์ประกอบไม่ทำงานนอก DOM เงา ซึ่งหมายความว่า คุณจะต้องใช้วิธีการอื่นเพื่อให้นักพัฒนาสามารถแทรกเนื้อหาของตนลงในองค์ประกอบที่คุณกำหนดเองได้ โดยปกติ สิ่งนี้เกี่ยวข้องกับการจัดการ DOM ด้วยตัวคุณเองเพื่อแทรกเนื้อหาในที่ที่คุณต้องการ
อย่างไรก็ตาม เนื่องจากไม่มีการแบ่งแยกระหว่าง Shadow DOM และ light DOM กับองค์ประกอบที่กำหนดเอง คุณจึงต้องระมัดระวังไม่ให้จัดรูปแบบ DOM ที่แทรก เนื่องจากรูปแบบการเรียงซ้อนขององค์ประกอบของคุณ
<!-- login-form.html --> <template> <style> login-form .container { max-width: 300px; padding: 50px; border: 1px solid grey; } login-form .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template> <script> (function() { const doc = (document._currentScript || document.currentScript).ownerDocument; const template = doc.querySelector('#login-form-template'); customElements.define('login-form', class extends HTMLElement { constructor() { super(); } // Without the shadow DOM, we have to manipulate the custom element // after it has been inserted in the DOM. connectedCallback() { const temp = document.importNode(template.content, true); this.appendChild(temp); } }); })(); </script>
<!-- index.html --> <link rel="stylesheet" href="styleguide.css"> <link rel="import" href="login-form.html"> <login-form></login-form>
ในแง่ของประสิทธิภาพ องค์ประกอบที่กำหนดเองนั้นเกือบจะเร็วเท่ากับส่วนประกอบเว็บที่ไม่ได้ใช้ (เช่น การเชื่อมโยงสไตล์ชีตที่ใช้ร่วมกันในส่วน head
และใช้เฉพาะองค์ประกอบ DOM ดั้งเดิม) ในบรรดาเทคนิคทั้งหมดที่คุณสามารถใช้ได้ในปัจจุบัน วิธีนี้เป็นวิธีที่เร็วที่สุด

นอกเหนือจากนั้น: องค์ประกอบที่กำหนดเองยังคงเป็นองค์ประกอบเว็บสำหรับเจตนาและวัตถุประสงค์ทั้งหมด คำว่า "ส่วนประกอบเว็บ" ใช้เพื่ออธิบายเทคโนโลยีสี่แยก: องค์ประกอบที่กำหนดเอง แท็กเทมเพลต การนำเข้า HTML และ DOM เงา
ขออภัย คำนี้ถูกใช้เพื่ออธิบายสิ่งที่ใช้เทคโนโลยีทั้งสี่ร่วมกัน สิ่งนี้ทำให้เกิดความสับสนอย่างมากเกี่ยวกับความหมายของผู้คนเมื่อพูดว่า "องค์ประกอบเว็บ" เช่นเดียวกับที่ Rob Dodson ค้นพบ ฉันพบว่าการใช้คำที่แตกต่างกันเมื่อพูดถึงองค์ประกอบแบบกำหนดเองที่มีและไม่มี Shadow DOM นั้นมีประโยชน์
นักพัฒนาส่วนใหญ่ที่ฉันคุยด้วยมักจะเชื่อมโยงคำว่า "องค์ประกอบเว็บ" กับองค์ประกอบที่กำหนดเองซึ่งใช้ Shadow DOM ดังนั้น เพื่อจุดประสงค์ของบทความนี้ ฉันได้สร้างความแตกต่างที่ประดิษฐ์ขึ้นระหว่างส่วนประกอบเว็บและองค์ประกอบที่กำหนดเอง
การใช้ไลบรารีส่วนประกอบเว็บ
โซลูชันอื่นที่คุณสามารถใช้ได้ในปัจจุบันคือไลบรารีเว็บคอมโพเนนต์ เช่น Polymer, SkateJS หรือ X-Tag ไลบรารีเหล่านี้ช่วยเติมเต็มช่องโหว่ของการสนับสนุนในปัจจุบัน และยังช่วยลดความซับซ้อนของโค้ดที่จำเป็นในการสร้างส่วนประกอบเว็บ พวกเขามักจะมีคุณลักษณะเพิ่มเติมที่ทำให้การเขียนองค์ประกอบของเว็บง่ายขึ้น
ตัวอย่างเช่น Polymer ให้คุณสร้างส่วนประกอบเว็บอย่างง่ายใน JavaScript เพียงไม่กี่บรรทัด ข้อดีเพิ่มเติมคือ พอลิเมอร์จัดเตรียมโซลูชันสำหรับการใช้ shadow DOM และสไตล์ชีตที่ใช้ร่วมกัน ซึ่งหมายความว่าคุณสามารถสร้างส่วนประกอบเว็บที่แชร์สไตล์ได้ในปัจจุบัน
เมื่อต้องการทำสิ่งนี้ ให้สร้างสิ่งที่พวกเขาเรียกว่าโมดูลสไตล์ ซึ่งมีสไตล์ที่ใช้ร่วมกันทั้งหมด อาจเป็นแท็ก <style>
ที่มีสไตล์ที่แชร์อยู่ในบรรทัดหรือแท็ก <link rel=“import”>
ที่ชี้ไปยังสไตล์ชีตที่ใช้ร่วมกัน ไม่ว่าในกรณีใด ให้ใส่สไตล์ในองค์ประกอบเว็บของคุณด้วยแท็ก <style include>
จากนั้น Polymer จะแยกวิเคราะห์สไตล์และเพิ่มเป็นแท็ก <style>
แบบอินไลน์ให้กับองค์ประกอบเว็บของคุณ

<!-- shared-styles.html --> <dom-module> <!-- Link to a shared style sheet --> <!-- <link rel="import" href="styleguide.css"> --> <!-- Inline the shared styles --> <template> <style> :host { color: #333333; font: 16px Arial, sans-serif; } /* Rest of shared CSS */ </style> </template> </dom-module>
<!-- login-form.html --> <link rel="import" href="../polymer/polymer.html"> <link rel="import" href="../shared-styles/shared-styles.html"> <dom-module> <template> <!-- Include the shared styles --> <style include="shared-styles"></style> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template> <script> Polymer({ is: 'login-form' }); </script> </dom-module>
ข้อเสียเพียงอย่างเดียวของการใช้ไลบรารีคืออาจทำให้เวลาในการแสดงผลของส่วนประกอบเว็บของคุณล่าช้า ไม่น่าแปลกใจเลยเพราะการดาวน์โหลดโค้ดของไลบรารีและการประมวลผลต้องใช้เวลา คอมโพเนนต์ของเว็บใดๆ บนหน้าไม่สามารถเริ่มแสดงผลได้จนกว่าไลบรารีจะประมวลผลเสร็จสิ้น
ในกรณีของโพลีเมอร์ มันสามารถชะลอเวลาในการแสดงผลหน้าได้ถึงครึ่งวินาทีเมื่อเทียบกับส่วนประกอบเว็บดั้งเดิม โมดูลสไตล์ที่ฝังสไตล์นั้นช้ากว่าโมดูลสไตล์ที่เชื่อมโยงสไตล์เล็กน้อย และการฝังสไตล์ลงในองค์ประกอบเว็บโดยตรงนั้นเร็วพอๆ กับการใช้โมดูลสไตล์
อีกครั้งที่โพลิเมอร์ไม่ได้ทำอะไรเป็นพิเศษเพื่อทำให้เวลาในการแสดงผลช้าลง การดาวน์โหลดไลบรารี่ Polymer และประมวลผลคุณสมบัติที่ยอดเยี่ยมทั้งหมด รวมถึงการสร้างการผูกแม่แบบทั้งหมด ต้องใช้เวลา เป็นเพียงการประนีประนอมที่คุณต้องทำเพื่อใช้ไลบรารีเว็บคอมโพเนนต์

ผลลัพธ์จากการทดสอบประสิทธิภาพแสดงให้เห็นว่า เมื่อใช้โพลีเมอร์ ส่วนประกอบของเว็บจะแสดงผลช้ากว่าส่วนประกอบเว็บดั้งเดิมถึงครึ่งวินาที
สัญญาแห่งอนาคต
หากวิธีแก้ปัญหาในปัจจุบันไม่เหมาะกับคุณ อย่าสิ้นหวัง หากทุกอย่างเป็นไปด้วยดี ภายในเวลาไม่กี่เดือนถึงสองสามปี เราจะสามารถใช้สไตล์ที่ใช้ร่วมกันได้โดยใช้วิธีการที่แตกต่างกันสองสามวิธี
คุณสมบัติที่กำหนดเอง
คุณสมบัติที่กำหนดเอง (หรือตัวแปร CSS ตามที่เรียก) เป็นวิธีการตั้งค่าและใช้ตัวแปรใน CSS แนวคิดนี้ไม่ใช่เรื่องใหม่สำหรับตัวประมวลผลล่วงหน้าของ CSS แต่เนื่องจากเป็นคุณสมบัติ CSS ดั้งเดิม คุณสมบัติที่กำหนดเองจึงมีประสิทธิภาพมากกว่าตัวแปรตัวประมวลผลล่วงหน้า
หากต้องการประกาศคุณสมบัติที่กำหนดเอง ให้ใช้สัญลักษณ์คุณสมบัติที่กำหนดเองของ –my-variable: value
และเข้าถึงตัวแปรโดยใช้ property: var(–my-variable)
คุณสมบัติที่กำหนดเองลดหลั่นกันเหมือนกฎ CSS อื่นๆ ดังนั้นค่าของคุณสมบัตินี้จะสืบทอดมาจากพาเรนต์และสามารถแทนที่ได้ ข้อแม้เพียงประการเดียวสำหรับคุณสมบัติแบบกำหนดเองคือต้องประกาศในตัวเลือกและไม่สามารถประกาศด้วยตนเองได้ ซึ่งแตกต่างจากตัวแปรตัวประมวลผลล่วงหน้า
<style> /* Declare the custom property */ html { --main-bg-color: red; } /* Use the custom property */ input { background: var(--main-bg-color); } </style>
สิ่งหนึ่งที่ทำให้คุณสมบัติที่กำหนดเองมีประสิทธิภาพมากคือความสามารถในการเจาะเงา DOM นี่ไม่ใช่แนวคิดเดียวกับตัวเลือก /deep/
และ ::shadow
เนื่องจากไม่ได้บังคับให้เข้าสู่องค์ประกอบเว็บ ผู้เขียนองค์ประกอบเว็บต้องใช้คุณสมบัติที่กำหนดเองใน CSS ของตนแทนจึงจะนำไปใช้ได้ ซึ่งหมายความว่าผู้สร้างองค์ประกอบเว็บสามารถสร้าง API คุณสมบัติที่กำหนดเองซึ่งผู้บริโภคขององค์ประกอบเว็บสามารถใช้เพื่อใช้สไตล์ของตนเองได้
<template> <style> /* Declare the custom property API */ :host { --main-bg-color: brown; } .one { color: var(--main-bg-color); } </style> <div class="one">Hello World</div> </template> <script> /* Code to set up my-element web component */ </script> <my-element></my-element> <style> /* Override the custom variable with own value */ my-element { --main-bg-color: red; } </style>
การสนับสนุนเบราว์เซอร์สำหรับคุณสมบัติที่กำหนดเองนั้นดีอย่างน่าประหลาดใจ เหตุผลเดียวที่มันไม่ใช่โซลูชันที่คุณสามารถใช้ได้ในวันนี้คือไม่มี polyfill ที่ใช้งานได้หากไม่มีองค์ประกอบที่กำหนดเองเวอร์ชัน 1 ทีมงานที่อยู่เบื้องหลัง polyfill ของ webcomponentjs กำลังทำงานเพื่อเพิ่มมัน แต่ยังไม่เผยแพร่และอยู่ในสถานะที่สร้างขึ้น หมายความว่าหากคุณแฮชทรัพย์สินเพื่อการผลิต คุณจะไม่สามารถใช้งานได้ เท่าที่ผมเข้าใจ มีกำหนดออกประมาณต้นปีหน้า
ถึงกระนั้น คุณสมบัติที่กำหนดเองก็ไม่ใช่วิธีที่ดีในการแชร์สไตล์ระหว่างส่วนประกอบเว็บ เนื่องจากสามารถใช้เพื่อประกาศค่าคุณสมบัติเดียว คอมโพเนนต์ของเว็บจึงยังคงต้องฝังสไตล์ทั้งหมดของคู่มือสไตล์ แม้ว่าจะมีค่าที่แทนที่ด้วยตัวแปรก็ตาม
คุณสมบัติที่กำหนดเองเหมาะสมกับตัวเลือกชุดรูปแบบมากกว่าสไตล์ที่ใช้ร่วมกัน ด้วยเหตุนี้ คุณสมบัติที่กำหนดเองจึงไม่ใช่วิธีแก้ปัญหาของเรา
/* ใช้คุณสมบัติที่กำหนดเอง */ อินพุต { พื้นหลัง: var(–main-bg-color); } </style>
สิ่งหนึ่งที่ทำให้คุณสมบัติที่กำหนดเองมีประสิทธิภาพมากคือความสามารถในการเจาะเงา DOM นี่ไม่ใช่แนวคิดเดียวกับตัวเลือก /deep/
และ ::shadow
เนื่องจากไม่ได้บังคับให้เข้าสู่องค์ประกอบเว็บ ผู้เขียนองค์ประกอบเว็บต้องใช้คุณสมบัติที่กำหนดเองใน CSS ของตนแทนจึงจะนำไปใช้ได้ ซึ่งหมายความว่าผู้สร้างองค์ประกอบเว็บสามารถสร้าง API คุณสมบัติที่กำหนดเองซึ่งผู้บริโภคขององค์ประกอบเว็บสามารถใช้เพื่อใช้สไตล์ของตนเองได้
<template> <style> /* Declare the custom property API */ :host { --main-bg-color: brown; } .one { color: var(--main-bg-color); } </style> <div class="one">Hello World</div> </template> <script> /* Code to set up my-element web component */ </script> <my-element></my-element> <style> /* Override the custom variable with own value */ my-element { --main-bg-color: red; } </style>
การสนับสนุนเบราว์เซอร์สำหรับคุณสมบัติที่กำหนดเองนั้นดีอย่างน่าประหลาดใจ เหตุผลเดียวที่มันไม่ใช่โซลูชันที่คุณสามารถใช้ได้ในวันนี้คือไม่มี polyfill ที่ใช้งานได้หากไม่มีองค์ประกอบที่กำหนดเองเวอร์ชัน 1 ทีมงานที่อยู่เบื้องหลัง polyfill ของ webcomponentjs กำลังทำงานเพื่อเพิ่มมัน แต่ยังไม่เผยแพร่และอยู่ในสถานะที่สร้างขึ้น หมายความว่าหากคุณแฮชทรัพย์สินเพื่อการผลิต คุณจะไม่สามารถใช้งานได้ เท่าที่ผมเข้าใจ มีกำหนดออกประมาณต้นปีหน้า
ถึงกระนั้น คุณสมบัติที่กำหนดเองก็ไม่ใช่วิธีที่ดีในการแชร์สไตล์ระหว่างส่วนประกอบเว็บ เนื่องจากสามารถใช้เพื่อประกาศค่าคุณสมบัติเดียว คอมโพเนนต์ของเว็บจึงยังคงต้องฝังสไตล์ทั้งหมดของคู่มือสไตล์ แม้ว่าจะมีค่าที่แทนที่ด้วยตัวแปรก็ตาม
คุณสมบัติที่กำหนดเองเหมาะสมกับตัวเลือกชุดรูปแบบมากกว่าสไตล์ที่ใช้ร่วมกัน ด้วยเหตุนี้ คุณสมบัติที่กำหนดเองจึงไม่ใช่วิธีแก้ปัญหาของเรา
@สมัครกฎ
นอกจากคุณสมบัติที่กำหนดเองแล้ว CSS ยังได้รับกฎ @apply
ใช้กฎเป็นหลักมิกซ์อินสำหรับโลก CSS มีการประกาศในลักษณะที่คล้ายกับคุณสมบัติที่กำหนดเอง แต่สามารถใช้เพื่อประกาศกลุ่มของคุณสมบัติแทนที่จะเป็นเพียงค่าคุณสมบัติ เช่นเดียวกับคุณสมบัติที่กำหนดเอง ค่าสามารถสืบทอดและแทนที่ได้ และต้องประกาศในตัวเลือกจึงจะใช้งานได้
<style> /* Declare rule */ html { --typography: { font: 16px Arial, sans-serif; color: #333333; } } /* Use rule */ input { @apply --typography; } </style>
การสนับสนุนเบราว์เซอร์สำหรับกฎ @apply
นั้นไม่มีอยู่จริง ปัจจุบัน Chrome รองรับฟีเจอร์นี้หลังการตั้งค่าสถานะคุณลักษณะ (ซึ่งฉันหาไม่พบ) แต่ก็เท่านั้น นอกจากนี้ยังไม่มีโพลีฟิลที่ใช้งานได้ด้วยเหตุผลเดียวกัน เนื่องจากไม่มีโพลีฟิลสำหรับคุณสมบัติที่กำหนดเอง ทีม polyfill ของ webcomponentjs กำลังทำงานเพื่อเพิ่มกฎ @apply
พร้อมกับคุณสมบัติที่กำหนดเอง ดังนั้นทั้งสองจะพร้อมใช้งานเมื่อมีการเผยแพร่เวอร์ชันใหม่
ไม่เหมือนกับคุณสมบัติที่กำหนดเอง กฎ @apply
เป็นโซลูชันที่ดีกว่ามากสำหรับการแชร์สไตล์ เนื่องจากพวกเขาสามารถตั้งค่ากลุ่มของการประกาศคุณสมบัติ คุณจึงสามารถใช้พวกมันเพื่อตั้งค่าสไตล์เริ่มต้นสำหรับองค์ประกอบดั้งเดิมทั้งหมด แล้วใช้ในองค์ประกอบเว็บได้ ในการทำเช่นนี้ คุณจะต้องสร้างกฎ @apply
สำหรับทุกองค์ประกอบดั้งเดิม
อย่างไรก็ตาม ในการใช้สไตล์ คุณจะต้องปรับใช้กับองค์ประกอบเนทีฟแต่ละรายการด้วยตนเอง ซึ่งจะยังคงประกาศสไตล์ซ้ำในทุกองค์ประกอบเว็บ แม้ว่ามันจะดีกว่าการฝังสไตล์ทั้งหมด แต่ก็ไม่สะดวกนักเพราะมันจะกลายเป็นต้นแบบที่ด้านบนของทุกองค์ประกอบเว็บ ซึ่งคุณต้องไม่ลืมที่จะเพิ่มเพื่อให้สไตล์ทำงานได้อย่างถูกต้อง
/* styleguide.css */ html { --typography: { color: #333333; font: 16px Arial, sans-serif; } --paragraph: { margin: 0; } --label { display: block; margin-bottom: 5px; } --input-text { background-color: #eaeaea; border: 1px solid grey; border-radius: 4px; box-sizing: border-box; color: inherit; font: inherit; padding: 10px 10px; width: 100%; } --input-submit { font: 16px/1.6 Arial, sans-serif; color: white; background: cornflowerblue; border: 1px solid #1f66e5; border-radius: 4px; padding: 10px 10px; width: 100%; } /* And so on for every native element */ }
<!-- login-form.html --> <template> <style> :host { @apply --typography; } p { @apply --paragraph; } label { @apply --label; } input-text { @apply --input-text; } .input-submit { @apply --input-submit; } .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template>
เนื่องจากความต้องการต้นแบบที่กว้างขวาง ฉันไม่เชื่อว่ากฎ @apply
จะเป็นทางออกที่ดีสำหรับการแชร์สไตล์ระหว่างส่วนประกอบเว็บ พวกมันเป็นทางออกที่ยอดเยี่ยมสำหรับการสร้างธีม
ใน Shadow DOM
ตามข้อกำหนดของส่วนประกอบเว็บ เบราว์เซอร์จะไม่สนใจแท็ก <link rel=“stylesheet”>
ใดๆ ใน Shadow DOM โดยจะปฏิบัติกับแท็กเหล่านี้เหมือนกับที่ทำในส่วนย่อยของเอกสาร ซึ่งทำให้เราไม่สามารถเชื่อมโยงในรูปแบบที่ใช้ร่วมกันใดๆ ในส่วนประกอบเว็บของเราได้ ซึ่งน่าเสียดาย นั่นคือ จนกระทั่งเมื่อไม่กี่เดือนที่ผ่านมา เมื่อคณะทำงานคอมโพเนนต์ของเว็บเสนอว่าแท็ก <link rel=“stylesheet”>
ควรใช้งานได้ เงา DOM หลังจากพูดคุยกันเพียงสัปดาห์เดียว ทุกคนเห็นพ้องกันว่าควรทำ และอีกไม่กี่วันต่อมาพวกเขาก็เพิ่มลงในข้อกำหนด HTML
<template> <link rel="stylesheet" href="styleguide.css"> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- rest of template DOM --> </template>
ถ้านั่นฟังดูเร็วเกินไปสำหรับคณะทำงานที่จะตกลงเรื่องข้อกำหนด นั่นก็เพราะว่ามันไม่ใช่ข้อเสนอใหม่ จริงๆ แล้วการจัดทำแท็ก link
ทำงานใน Shadow DOM นั้น จริง ๆ แล้วมีการเสนออย่างน้อยเมื่อสามปีที่แล้ว แต่มีงานค้างอยู่จนกว่าพวกเขาจะสามารถมั่นใจได้ว่าไม่มีปัญหาสำหรับประสิทธิภาพ
หากการยอมรับข้อเสนอไม่น่าตื่นเต้นเพียงพอ Chrome 55 (ปัจจุบันคือ Chrome Canary) ได้เพิ่มฟังก์ชันการทำงานเริ่มต้นในการทำให้แท็ก link
ทำงานใน Shadow DOM ดูเหมือนว่าฟังก์ชันนี้จะอยู่ใน Chrome เวอร์ชันปัจจุบันแล้ว แม้แต่ Safari ก็ยังใช้ฟีเจอร์นี้ใน Safari 18
ความสามารถในการเชื่อมโยงในสไตล์ที่ใช้ร่วมกันนั้นเป็นวิธีที่สะดวกที่สุดสำหรับการแบ่งปันสไตล์ระหว่างส่วนประกอบเว็บ สิ่งที่คุณต้องทำคือสร้างแท็ก link
และองค์ประกอบดั้งเดิมทั้งหมดจะได้รับการจัดรูปแบบตามนั้น โดยไม่ต้องดำเนินการใดๆ เพิ่มเติม
แน่นอนว่าวิธีที่ผู้ผลิตเบราว์เซอร์ใช้คุณลักษณะนี้จะเป็นตัวกำหนดว่าโซลูชันนี้ใช้ได้จริงหรือไม่ เพื่อให้ทำงานได้อย่างถูกต้อง แท็ก link
จะต้องถูกขจัดความซ้ำซ้อน ดังนั้นส่วนประกอบเว็บหลายรายการที่ขอไฟล์ CSS เดียวกันจะทำให้เกิดคำขอ HTTP เพียงรายการเดียว CSS จะต้องแยกวิเคราะห์เพียงครั้งเดียวด้วย ดังนั้นแต่ละอินสแตนซ์ขององค์ประกอบเว็บจะไม่ต้องคำนวณสไตล์ที่ใช้ร่วมกันใหม่ แต่จะนำสไตล์ที่คำนวณแล้วมาใช้ใหม่แทน
Chrome ทำทั้งสองอย่างอยู่แล้ว ดังนั้น หากผู้ผลิตเบราว์เซอร์รายอื่นทั้งหมดใช้วิธีเดียวกัน แท็ก link
ที่ทำงานใน Shadow DOM จะช่วยแก้ปัญหาเกี่ยวกับวิธีการแชร์สไตล์ระหว่างส่วนประกอบเว็บได้อย่างแน่นอน
สไตล์ชีตที่สร้างได้
คุณอาจพบว่ามันยากที่จะเชื่อ เนื่องจากเรายังไม่ได้รับมัน แต่แท็ก link
ที่ทำงานใน Shadow DOM ไม่ใช่วิธีแก้ปัญหาระยะยาว แต่เป็นเพียงวิธีแก้ปัญหาระยะสั้นเท่านั้นที่จะนำเราไปสู่โซลูชันที่แท้จริง นั่นคือ สไตล์ชีตที่สร้างได้
สไตล์ชีตที่สร้างได้คือข้อเสนอที่อนุญาตให้สร้างออบเจ็กต์ StyleSheet
ใน JavaScript ผ่านฟังก์ชันคอนสตรัคเตอร์ คุณสามารถเพิ่มสไตล์ชีตที่สร้างไปยัง Shadow DOM ผ่าน API ซึ่งจะทำให้ Shadow DOM ใช้ชุดของสไตล์ที่ใช้ร่วมกันได้
ขออภัย นี่คือทั้งหมดที่ฉันรวบรวมได้จากข้อเสนอ ฉันพยายามค้นหาข้อมูลเพิ่มเติมเกี่ยวกับสไตล์ชีตที่สร้างได้โดยการถาม Web Components Working Group แต่พวกเขาเปลี่ยนเส้นทางฉันไปยังรายชื่อส่งเมลของ CSS Working Group ของ W3C ซึ่งฉันถามอีกครั้ง แต่ไม่มีใครตอบ ฉันไม่รู้ด้วยซ้ำว่าข้อเสนอนี้คืบหน้าไปอย่างไร เพราะข้อเสนอนี้ไม่มีการปรับปรุงมานานกว่าสองปีแล้ว
ถึงกระนั้นก็ตาม Web Components Working Group ใช้ เป็น โซลูชันสำหรับการแชร์สไตล์ระหว่างส่วนประกอบเว็บ หวังว่าข้อเสนอจะได้รับการอัปเดตหรือ Web Components Working Group จะเปิดเผยข้อมูลเพิ่มเติมเกี่ยวกับข้อเสนอนี้และการนำไปใช้ ก่อนหน้านั้น วิธีแก้ปัญหา "ระยะยาว" ดูเหมือนจะไม่เกิดขึ้นในอนาคตอันใกล้
บทเรียนที่ได้รับ
หลังจากการวิจัยและทดสอบเป็นเวลาหลายเดือน ฉันก็ค่อนข้างมีความหวังสำหรับอนาคต รู้สึกสบายใจที่รู้ว่าหลังจากหลายปีที่ไม่มีวิธีแก้ปัญหาสำหรับการแชร์สไตล์ระหว่างส่วนประกอบเว็บ ในที่สุดก็มีคำตอบ คำตอบเหล่านั้นอาจไม่ได้กำหนดขึ้นอีกสองสามปี แต่อย่างน้อยก็อยู่ที่นั่น
ถ้าคุณต้องการใช้คู่มือสไตล์ที่ใช้ร่วมกันเพื่อจัดรูปแบบองค์ประกอบเว็บในวันนี้ คุณอาจไม่สามารถใช้ Shadow DOM และสร้างองค์ประกอบที่กำหนดเองแทนได้ หรือคุณสามารถใช้ไลบรารีองค์ประกอบเว็บที่ polyfills รองรับรูปแบบการแชร์ได้ โซลูชันทั้งสองมีข้อดีและข้อเสีย ดังนั้นควรใช้วิธีใดดีที่สุดสำหรับโครงการของคุณ
หากคุณตัดสินใจที่จะรอสักครู่ก่อนที่จะเจาะลึกเกี่ยวกับองค์ประกอบของเว็บ ในอีกไม่กี่ปีข้างหน้า เราควรมีวิธีแก้ไขปัญหาที่ยอดเยี่ยมสำหรับการแบ่งปันสไตล์ระหว่างกัน ดังนั้น โปรดกลับมาตรวจสอบความคืบหน้าอยู่เสมอ
สิ่งที่ควรทราบ
โปรดคำนึงถึงบางสิ่งหากคุณตัดสินใจใช้องค์ประกอบที่กำหนดเองหรือส่วนประกอบเว็บในปัจจุบัน
สิ่งสำคัญที่สุดคือ ข้อมูลจำเพาะของส่วนประกอบเว็บยังคงได้รับการพัฒนาอย่างจริงจัง ซึ่งหมายความว่าสิ่งต่างๆ สามารถและจะเปลี่ยนแปลงได้ ส่วนประกอบของเว็บยังคงเป็นส่วนสำคัญที่ทำให้ต้องเสียเลือด ดังนั้นจงเตรียมพร้อมที่จะจดจ่ออยู่กับการพัฒนา
หากคุณตัดสินใจที่จะใช้ Shadow DOM ให้รู้ว่ามันค่อนข้างช้าและไม่มีประสิทธิภาพในเบราว์เซอร์แบบ polyfilled ด้วยเหตุผลนี้เองที่ผู้พัฒนาของ Polymer ได้สร้างการนำ DOM ไปใช้อย่างร่มรื่นและทำให้เป็นค่าเริ่มต้น
Chrome, Opera และเมื่อเร็ว ๆ นี้ Safari เป็นเบราว์เซอร์เดียวที่รองรับ Shadow DOM เวอร์ชัน 0 Firefox ยังอยู่ในระหว่างการพัฒนาแม้ว่าจะได้รับการสนับสนุนเบื้องหลังการทดสอบตั้งแต่เวอร์ชัน 29 Microsoft ยังคงพิจารณาสำหรับ Edge และมีไว้เป็น ลำดับความสำคัญสูงบนแผนที่ถนน
อย่างไรก็ตาม shadow DOM เวอร์ชัน 0 เป็นข้อกำหนดเก่า Shadow DOM เวอร์ชัน 1 เป็นเวอร์ชันใหม่และมีเพียง Chrome, Safari และ Opera เท่านั้นที่สนับสนุนอย่างเต็มที่ ไม่ต้องพูดถึงว่าองค์ประกอบที่กำหนดเองเวอร์ชัน 0 ผ่านการอัปเกรดแบบเดียวกัน และมีเพียง Chrome เท่านั้นที่รองรับองค์ประกอบที่กำหนดเองเวอร์ชัน 1 ได้อย่างเต็มที่ ในขณะที่ตัวอย่างทางเทคนิคของ Safari รองรับตั้งแต่เวอร์ชัน 17 องค์ประกอบที่กำหนดเองเวอร์ชัน 1 มีการเปลี่ยนแปลงที่สำคัญบางประการในการเขียนคอมโพเนนต์ของเว็บ ดังนั้นจงเข้าใจอย่างถ่องแท้ถึงสิ่งที่เกี่ยวข้อง
สุดท้ายนี้ polyfill ของ webcomponentjs รองรับการใช้งานเวอร์ชัน 0 ของ Shadow DOM และองค์ประกอบที่กำหนดเองเท่านั้น Polyfill สาขาเวอร์ชัน 1 จะรองรับเวอร์ชัน 1 แต่ยังไม่เผยแพร่