ประโยชน์ของการใช้พร็อพเพอร์ตี้ที่กำหนดเองในระบบการออกแบบและไลบรารีคอมโพเนนต์
ผมชื่อ Dave เป็น Senior Front-End Developer ที่ Nordhealth ฉันทํางานด้านการออกแบบและพัฒนาระบบการออกแบบ Nord ซึ่งรวมถึงการสร้างคอมโพเนนต์เว็บสําหรับคลังคอมโพเนนต์ เราอยากแชร์วิธีแก้ปัญหาเกี่ยวกับการจัดสไตล์ Web Components โดยใช้พร็อพเพอร์ตี้ที่กำหนดเองของ CSS และประโยชน์อื่นๆ ของการใช้พร็อพเพอร์ตี้ที่กำหนดเองในระบบการออกแบบและไลบรารีคอมโพเนนต์
วิธีที่เราสร้างคอมโพเนนต์เว็บ
เราใช้ Lit ซึ่งเป็นไลบรารีที่มีโค้ดที่เขียนขึ้นซ้ำๆ จำนวนมาก เช่น สถานะ สไตล์ที่มีขอบเขต เทมเพลต และอื่นๆ เพื่อสร้างคอมโพเนนต์เว็บ Lit ไม่เพียงแต่จะเบา แต่ยังสร้างขึ้นจาก API ของ JavaScript ดั้งเดิมด้วย ซึ่งหมายความว่าเราสามารถส่งชุดโค้ดที่มีประสิทธิภาพสูงซึ่งใช้ประโยชน์จากฟีเจอร์ที่เบราว์เซอร์มีอยู่แล้ว
แต่สิ่งที่ดึงดูดใจที่สุดเกี่ยวกับ Web Components คือ Web Components ใช้งานได้กับเฟรมเวิร์ก JavaScript ที่มีอยู่เกือบทุกเฟรมเวิร์ก หรือแม้แต่ไม่มีเฟรมเวิร์กเลย เมื่อมีการอ้างอิงแพ็กเกจ JavaScript หลักในหน้าเว็บแล้ว การใช้คอมโพเนนต์เว็บจะคล้ายกับการใช้องค์ประกอบ HTML เดิมมาก สัญญาณที่บ่งบอกว่าองค์ประกอบดังกล่าวไม่ใช่องค์ประกอบ HTML เดิมคือเครื่องหมายขีดกลางที่สอดคล้องกันภายในแท็ก ซึ่งเป็นมาตรฐานที่บ่งบอกให้เบราว์เซอร์ทราบว่านี่คือคอมโพเนนต์เว็บ
การห่อหุ้มสไตล์ Shadow DOM
คอมโพเนนต์เว็บมี Shadow DOM เช่นเดียวกับองค์ประกอบ HTML ที่มีอยู่แต่เดิม Shadow DOM คือต้นไม้ของโหนดที่ซ่อนอยู่ภายในองค์ประกอบ วิธีที่ดีที่สุดในการเห็นภาพนี้คือเปิดเครื่องมือตรวจสอบเว็บและเปิดตัวเลือก "แสดงลําดับชั้น Shadow DOM" เมื่อดำเนินการเสร็จแล้ว ให้ลองดูองค์ประกอบอินพุตแบบเนทีฟในเครื่องมือตรวจสอบ ตอนนี้คุณจะมีตัวเลือกในการเปิดอินพุตนั้นและดูองค์ประกอบทั้งหมดภายใน คุณยังลองใช้กับ Web Component ของเราได้ด้วย ลองตรวจสอบคอมโพเนนต์อินพุตที่กําหนดเองเพื่อดู Shadow DOM
ข้อดีอย่างหนึ่ง (หรือข้อเสีย ทั้งนี้ขึ้นอยู่กับมุมมองของคุณ) ของ Shadow DOM คือการห่อหุ้มสไตล์ หากคุณเขียน CSS ภายในคอมโพเนนต์เว็บ สไตล์เหล่านั้นจะไม่แสดงออกมาและส่งผลต่อหน้าหลักหรือองค์ประกอบอื่นๆ เนื่องจากจะอยู่ในคอมโพเนนต์อย่างสมบูรณ์ นอกจากนี้ CSS ที่เขียนขึ้นสําหรับหน้าหลักหรือคอมโพเนนต์เว็บหลักจะไม่สามารถแทรกซึมเข้าไปในคอมโพเนนต์เว็บได้
การรวมสไตล์นี้ถือเป็นข้อดีในคลังคอมโพเนนต์ของเรา วิธีนี้ช่วยให้เรามั่นใจมากขึ้นว่าเมื่อมีคนใช้คอมโพเนนต์ใดคอมโพเนนต์หนึ่งของเรา คอมโพเนนต์นั้นจะมีลักษณะตามที่ตั้งใจไว้ ไม่ว่าจะใช้สไตล์ใดกับหน้าหลักก็ตาม และเพื่อเป็นการตรวจสอบเพิ่มเติม เรายังเพิ่ม all: unset;
ลงในรูทหรือ "โฮสต์" ของคอมโพเนนต์เว็บทั้งหมดด้วย
แต่จะเกิดอะไรขึ้นหากผู้ใช้คอมโพเนนต์เว็บของคุณมีเหตุผลอันสมควรในการเปลี่ยนรูปแบบบางอย่าง อาจเป็นเพราะข้อความบางบรรทัดมีความคมชัดไม่เพียงพอตามบริบท หรือเส้นขอบต้องหนาขึ้น หากไม่มีสไตล์ใดเข้าสู่คอมโพเนนต์ได้ คุณจะทำอย่างไรเพื่อปลดล็อกตัวเลือกการจัดสไตล์เหล่านั้น
พร็อพเพอร์ตี้ที่กำหนดเองของ CSS จึงเข้ามามีบทบาท
พร็อพเพอร์ตี้ที่กำหนดเองของ CSS
พร็อพเพอร์ตี้ที่กำหนดเองมีชื่อที่เหมาะเจาะมาก เนื่องจากเป็นพร็อพเพอร์ตี้ CSS ที่คุณตั้งชื่อเองได้ทั้งหมดและใช้ค่าใดก็ได้ที่ต้องการ ข้อกำหนดเพียงอย่างเดียวคือคุณต้องใส่ขีดกลาง 2 ตัวไว้ข้างหน้า เมื่อประกาศพร็อพเพอร์ตี้ที่กำหนดเองแล้ว คุณจะใช้ค่าใน CSS ได้โดยใช้ฟังก์ชัน var()
ในส่วนของการรับช่วงค่า ระบบจะรับค่าพร็อพเพอร์ตี้ที่กำหนดเองทั้งหมด ซึ่งเป็นไปตามลักษณะการทำงานทั่วไปของพร็อพเพอร์ตี้และค่า CSS ปกติ พร็อพเพอร์ตี้ที่กำหนดเองซึ่งใช้กับองค์ประกอบหลักหรือองค์ประกอบนั้นๆ เองสามารถใช้เป็นค่าในพร็อพเพอร์ตี้อื่นๆ ได้ เราใช้พร็อพเพอร์ตี้ที่กำหนดเองสำหรับโทเค็นการออกแบบอย่างแพร่หลายโดยนำไปใช้กับองค์ประกอบรูทผ่านเฟรมเวิร์ก CSS ซึ่งหมายความว่าองค์ประกอบทั้งหมดในหน้าเว็บสามารถใช้ค่าโทเค็นเหล่านี้ได้ ไม่ว่าจะเป็นคอมโพเนนต์เว็บ คลาสตัวช่วย CSS หรือนักพัฒนาซอฟต์แวร์ที่ต้องการดึงค่าจากรายการโทเค็น
ความสามารถในการรับค่าพร็อพเพอร์ตี้ที่กำหนดเองนี้ด้วยการใช้ฟังก์ชัน var()
เป็นวิธีที่เราจะเจาะผ่าน Shadow DOM ของ Web Component และช่วยให้นักพัฒนาซอฟต์แวร์ควบคุมรายละเอียดได้มากขึ้นเมื่อจัดสไตล์คอมโพเนนต์
คุณสมบัติที่กำหนดเองในคอมโพเนนต์เว็บ Nord
เมื่อใดก็ตามที่เราพัฒนาคอมโพเนนต์สําหรับระบบการออกแบบ เราจะใช้แนวทางที่รอบคอบกับ CSS ของคอมโพเนนต์นั้นๆ โดยมุ่งเน้นที่โค้ดที่เรียบง่ายแต่ดูแลรักษาได้ โทเค็นการออกแบบที่เรามีจะกำหนดเป็นพร็อพเพอร์ตี้ที่กำหนดเองภายในเฟรมเวิร์ก CSS หลักของเราในองค์ประกอบรูท
จากนั้นระบบจะอ้างอิงค่าโทเค็นเหล่านี้ภายในคอมโพเนนต์ ในบางกรณี เราจะใช้ค่าในพร็อพเพอร์ตี้ CSS โดยตรง แต่สำหรับบางกรณี เราจะกำหนดพร็อพเพอร์ตี้ที่กำหนดเองตามบริบทใหม่และใช้ค่ากับพร็อพเพอร์ตี้นั้น
นอกจากนี้ เราจะแยกค่าบางอย่างที่เจาะจงสำหรับคอมโพเนนต์แต่ไม่ได้อยู่ในโทเค็นของเรา และเปลี่ยนให้เป็นพร็อพเพอร์ตี้ที่กำหนดเองตามบริบท พร็อพเพอร์ตี้ที่กำหนดเองซึ่งสอดคล้องกับบริบทของคอมโพเนนต์จะให้ประโยชน์หลัก 2 อย่างแก่เรา ประการแรก หมายความว่าเราสามารถเขียน CSS ให้มีโค้ดน้อยลงได้ เนื่องจากค่าดังกล่าวสามารถใช้กับพร็อพเพอร์ตี้หลายรายการภายในคอมโพเนนต์
และประการที่ 2 คือช่วยให้การเปลี่ยนแปลงสถานะคอมโพเนนต์และรูปแบบมีความเรียบร้อยมาก คุณจะเปลี่ยนเฉพาะพร็อพเพอร์ตี้ที่กำหนดเองเพื่ออัปเดตพร็อพเพอร์ตี้ทั้งหมดได้ เช่น เมื่อคุณจัดสไตล์สถานะการโฮเวอร์หรือสถานะใช้งานอยู่ หรือในกรณีนี้คือรูปแบบ
แต่ประโยชน์ที่มีประสิทธิภาพมากที่สุดคือเมื่อเรากําหนดพร็อพเพอร์ตี้ที่กําหนดเองตามบริบทเหล่านี้ในคอมโพเนนต์ เราจะสร้าง CSS API ที่กําหนดเองสําหรับคอมโพเนนต์แต่ละรายการ ซึ่งผู้ใช้คอมโพเนนต์นั้นสามารถเข้าถึงได้
ตัวอย่างก่อนหน้านี้แสดง Web Component รายการใดรายการหนึ่งที่มีพร็อพเพอร์ตี้ที่กำหนดเองตามบริบทซึ่งเปลี่ยนแปลงผ่านตัวเลือก ผลลัพธ์ของแนวทางทั้งหมดนี้คือคอมโพเนนต์ที่ให้ความยืดหยุ่นในการจัดสไตล์แก่ผู้ใช้มากพอ ในขณะที่ยังคงควบคุมสไตล์จริงส่วนใหญ่ไว้ได้ นอกจากนี้ เราในฐานะนักพัฒนาคอมโพเนนต์ยังมีความสามารถพิเศษในการขัดจังหวะสไตล์เหล่านั้นที่ผู้ใช้นำมาใช้ หากต้องการปรับหรือขยายพร็อพเพอร์ตี้ใดพร็อพเพอร์ตี้หนึ่งเหล่านั้น เราสามารถทำได้โดยไม่ต้องให้ผู้ใช้เปลี่ยนแปลงโค้ดใดๆ
เราพบว่าแนวทางนี้มีประสิทธิภาพมาก ทั้งสำหรับเราในฐานะผู้สร้างคอมโพเนนต์ในระบบการออกแบบ และสำหรับทีมพัฒนาซอฟต์แวร์ของเราเมื่อใช้คอมโพเนนต์เหล่านี้ในผลิตภัณฑ์
การใช้พร็อพเพอร์ตี้ที่กำหนดเองเพิ่มเติม
ขณะเขียนบทความนี้ เรายังไม่ได้เปิดเผยพร็อพเพอร์ตี้ที่กำหนดเองตามบริบทเหล่านี้ในเอกสารประกอบ แต่เรามีแผนที่จะเปิดเผยเพื่อให้ทีมพัฒนาซอฟต์แวร์ส่วนกลางเข้าใจและใช้ประโยชน์จากพร็อพเพอร์ตี้เหล่านี้ได้ คอมโพเนนต์ของเราได้รับการจัดแพ็กเกจใน npm ด้วยไฟล์ Manifest ซึ่งมีข้อมูลทั้งหมดที่ควรทราบเกี่ยวกับคอมโพเนนต์ จากนั้นเราจะใช้ไฟล์ Manifest เป็นข้อมูลเมื่อมีการทำให้เว็บไซต์เอกสารประกอบใช้งานได้ ซึ่งทําโดยใช้ Eleventy และฟีเจอร์ข้อมูลส่วนกลาง เราวางแผนที่จะรวมพร็อพเพอร์ตี้ที่กำหนดเองตามบริบทเหล่านี้ไว้ในไฟล์ข้อมูลไฟล์ Manifest นี้
อีกด้านหนึ่งที่เราต้องการปรับปรุงคือวิธีที่พร็อพเพอร์ตี้ที่กำหนดเองตามบริบทเหล่านี้รับค่ามา ปัจจุบัน เช่น หากต้องการปรับสีของคอมโพเนนต์ตัวแบ่ง 2 รายการ คุณจะต้องกำหนดเป้าหมายคอมโพเนนต์ทั้ง 2 รายการนั้นโดยเฉพาะด้วยตัวเลือก หรือใช้พร็อพเพอร์ตี้ที่กำหนดเองกับองค์ประกอบโดยตรงโดยใช้แอตทริบิวต์ style การดำเนินการนี้อาจดูไม่มีปัญหา แต่นักพัฒนาซอฟต์แวร์จะกำหนดสไตล์เหล่านั้นในองค์ประกอบที่บรรจุหรือแม้แต่ที่ระดับรูทได้จะมีประโยชน์มากกว่า
สาเหตุที่คุณต้องตั้งค่าพร็อพเพอร์ตี้ที่กำหนดเองในคอมโพเนนต์โดยตรงเนื่องจากเรากําหนดค่าในองค์ประกอบเดียวกันผ่านตัวเลือกโฮสต์คอมโพเนนต์ โทเค็นการออกแบบส่วนกลางที่เราใช้ในคอมโพเนนต์โดยตรงจะส่งผ่านโดยตรงโดยไม่ได้รับผลกระทบจากปัญหานี้ และยังสามารถสกัดกั้นในองค์ประกอบหลักได้ เราจะทำอย่างไรให้ได้รับสิ่งที่ดีที่สุดจากทั้ง 2 โลก
พร็อพเพอร์ตี้ที่กำหนดเองแบบส่วนตัวและแบบสาธารณะ
พร็อพเพอร์ตี้ที่กำหนดเองแบบส่วนตัวคือสิ่งที่ Lea Verou รวบรวมไว้ ซึ่งเป็นพร็อพเพอร์ตี้ที่กำหนดเองแบบ "ส่วนตัว" ตามบริบทในคอมโพเนนต์เอง แต่ตั้งค่าเป็นพร็อพเพอร์ตี้ที่กำหนดเองแบบ "สาธารณะ" ที่มีค่าสำรอง
การกําหนดพร็อพเพอร์ตี้ที่กําหนดเองตามบริบทในลักษณะนี้หมายความว่าเรายังคงทําสิ่งต่างๆ ทั้งหมดที่เคยทําได้ เช่น รับค่าโทเค็นส่วนกลางและนําค่ามาใช้ซ้ำในโค้ดคอมโพเนนต์ แต่คอมโพเนนต์จะรับค่าคําจํากัดความใหม่ของพร็อพเพอร์ตี้นั้นในตัวเองหรือองค์ประกอบหลักอย่างราบรื่นด้วย
แม้ว่าอาจมีการโต้แย้งว่าวิธีการนี้ไม่ได้ "ส่วนตัว" อย่างแท้จริง แต่เรายังคงคิดว่านี่เป็นวิธีแก้ปัญหาที่ค่อนข้างแยบยลสำหรับปัญหาที่เรากังวล เมื่อมีโอกาส เราจะแก้ไขปัญหานี้ในคอมโพเนนต์เพื่อให้ทีมพัฒนาซอฟต์แวร์ของเราควบคุมการใช้งานคอมโพเนนต์ได้มากขึ้น ในขณะเดียวกันก็ยังคงได้รับประโยชน์จากขอบเขตที่เรากำหนดไว้
เราหวังว่าข้อมูลเชิงลึกเกี่ยวกับวิธีที่เราใช้ Web Components กับพร็อพเพอร์ตี้ที่กำหนดเองของ CSS นี้จะเป็นประโยชน์กับคุณ โปรดบอกให้เราทราบว่าคุณคิดเห็นอย่างไร และหากตัดสินใจที่จะใช้วิธีการเหล่านี้ในงานของคุณเอง โปรดติดต่อฉันทาง Twitter ที่ @DavidDarnes นอกจากนี้ คุณยังติดตาม Nordhealth ได้ที่ @NordhealthHQ ใน Twitter รวมถึงติดตามทีมที่เหลือของเราที่ทุ่มเททำงานเพื่อพัฒนาระบบการออกแบบนี้และทำให้ฟีเจอร์ที่กล่าวถึงในบทความนี้ใช้งานได้จริงได้ที่ @Viljamis, @WickyNilliams และ @eric_habich
รูปภาพหลักโดย Dan Cristian Pădureț