คู่มือกลยุทธ์สำหรับคุณสมบัติที่กำหนดเอง CSS
เผยแพร่แล้ว: 2022-03-10คุณสมบัติที่กำหนดเองของ CSS (บางครั้งเรียกว่า 'ตัวแปร CSS') ได้รับการสนับสนุนในเบราว์เซอร์สมัยใหม่ทั้งหมด และผู้คนเริ่มใช้งานจริงในเวอร์ชันที่ใช้งานจริง นี่เป็นสิ่งที่ยอดเยี่ยม แต่พวกมันแตกต่างจากตัวแปรในตัวประมวลผลล่วงหน้า และฉันได้เห็นตัวอย่างมากมายของผู้ที่ใช้พวกมันโดยไม่พิจารณาถึงข้อดีที่พวกเขาเสนอ
คุณสมบัติที่กำหนดเองมีศักยภาพมหาศาลในการเปลี่ยนแปลงวิธีที่เราเขียนและจัดโครงสร้าง CSS และวิธีที่เราใช้ JavaScript เพื่อโต้ตอบกับส่วนประกอบ UI ในระดับที่น้อยกว่า ฉันจะไม่เน้นที่ไวยากรณ์และวิธีการทำงาน (เพื่อที่ฉันแนะนำให้คุณอ่าน “ถึงเวลาที่จะเริ่มใช้คุณสมบัติที่กำหนดเอง”) แต่ฉันต้องการเจาะลึกถึงกลยุทธ์ในการใช้ประโยชน์สูงสุดจากคุณสมบัติที่กำหนดเองของ CSS
พวกมันคล้ายกับตัวแปรในตัวประมวลผลล่วงหน้าอย่างไร
คุณสมบัติที่กำหนดเองนั้นคล้ายกับตัวแปรในตัวประมวลผลล่วงหน้าเล็กน้อย แต่มีข้อแตกต่างที่สำคัญบางประการ ความแตกต่างแรกและชัดเจนที่สุดคือไวยากรณ์
ด้วย SCSS
เราใช้สัญลักษณ์ดอลลาร์เพื่อแสดงถึงตัวแปร:
$smashing-red: #d33a2c;
ใน Less เราใช้สัญลักษณ์ @
:
@smashing-red: #d33a2c;
คุณสมบัติที่กำหนดเองเป็นไปตามข้อตกลงที่คล้ายกันและใช้ --
คำนำหน้า:
:root { --smashing-red: #d33a2c; } .smashing-text { color: var(--smashing-red); }
ความแตกต่างที่สำคัญอย่างหนึ่งระหว่างคุณสมบัติแบบกำหนดเองและตัวแปรในตัวประมวลผลล่วงหน้าคือ คุณสมบัติที่กำหนดเองมีไวยากรณ์ที่แตกต่างกันสำหรับการกำหนดค่าและการดึงค่านั้น เมื่อดึงค่าของคุณสมบัติที่กำหนดเอง เราใช้ฟังก์ชัน var()
ความแตกต่างที่ชัดเจนที่สุดคือในชื่อ พวกเขาเรียกว่า 'คุณสมบัติที่กำหนดเอง' เพราะเป็นคุณสมบัติ CSS จริงๆ ในตัวประมวลผลล่วงหน้า คุณสามารถประกาศและใช้ตัวแปรได้เกือบทุกที่ รวมถึงบล็อกการประกาศภายนอก ในกฎของสื่อ หรือแม้แต่เป็นส่วนหนึ่งของตัวเลือก
$breakpoint: 800px; $smashing-red: #d33a2c; $smashing-things: ".smashing-text, .cats"; @media screen and (min-width: $breakpoint) { #{$smashing-things} { color: $smashing-red; } }
ตัวอย่างส่วนใหญ่ข้างต้นจะไม่ถูกต้องโดยใช้คุณสมบัติที่กำหนดเอง
คุณสมบัติที่กำหนดเองมีกฎเดียวกันเกี่ยวกับตำแหน่งที่สามารถใช้เป็นคุณสมบัติ CSS ปกติได้ ดีกว่ามากที่จะมองว่ามันเป็นคุณสมบัติไดนามิกมากกว่าตัวแปร ซึ่งหมายความว่าสามารถใช้ได้เฉพาะในบล็อกการประกาศ หรือกล่าวอีกนัยหนึ่ง คุณสมบัติที่กำหนดเองจะเชื่อมโยงกับตัวเลือก นี่อาจเป็น :root
ตัวเลือกหรือตัวเลือกอื่นที่ถูกต้อง
:root { --smashing-red: #d33a2c; } @media screen and (min-width: 800px) { .smashing-text, .cats { --margin-left: 1em; } }
คุณสามารถดึงค่าของคุณสมบัติที่กำหนดเองได้ทุกที่ที่คุณจะใช้ค่าในการประกาศคุณสมบัติ ซึ่งหมายความว่าสามารถใช้เป็นค่าเดียว เป็นส่วนหนึ่งของคำสั่งชวเลข หรือแม้แต่ในสมการ calc()
.smashing-text, .cats { color: var(--smashing-red); margin: 0 var(--margin-horizontal); padding: calc(var(--margin-horizontal) / 2) }
อย่างไรก็ตาม ไม่สามารถใช้ในคิวรีสื่อ หรือตัวเลือกต่างๆ รวมถึง :nth-child()
อาจมีอีกมากที่คุณต้องการทราบเกี่ยวกับไวยากรณ์และวิธีการทำงานของคุณสมบัติที่กำหนดเอง เช่น วิธีใช้ค่าทางเลือกและคุณสามารถกำหนดตัวแปรให้กับตัวแปรอื่นๆ ได้หรือไม่ (ใช่) แต่การแนะนำพื้นฐานนี้น่าจะเพียงพอที่จะเข้าใจส่วนที่เหลือของ แนวคิดในบทความนี้ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทำงานของคุณสมบัติแบบกำหนดเอง คุณสามารถอ่าน "ได้เวลาเริ่มใช้คุณสมบัติที่กำหนดเอง" ที่เขียนโดย Serg Hospodarets
ไดนามิกกับสแตติก
นอกเหนือจากความแตกต่างด้านความสวยงามแล้ว ความแตกต่างที่สำคัญที่สุดระหว่างตัวแปรในตัวประมวลผลล่วงหน้าและคุณสมบัติที่กำหนดเองคือวิธีการกำหนดขอบเขต เราสามารถอ้างถึงตัวแปรเป็นการกำหนดขอบเขตแบบคงที่หรือแบบไดนามิก ตัวแปรในตัวประมวลผลล่วงหน้าเป็นแบบคงที่ ในขณะที่คุณสมบัติแบบกำหนดเองจะเป็นแบบไดนามิก
ในกรณีที่ CSS เป็นกังวล สแตติกหมายความว่าคุณสามารถอัปเดตค่าของตัวแปรที่จุดต่างๆ ในกระบวนการคอมไพล์ได้ แต่สิ่งนี้ไม่สามารถเปลี่ยนค่าของโค้ดที่อยู่ก่อนหน้าได้
$background: blue; .blue { background: $background; } $background: red; .red { background: $background; }
ส่งผลให้:
.blue { background: blue; } .red { background: red; }
เมื่อแสดงผลเป็น CSS แล้ว ตัวแปรจะหายไป ซึ่งหมายความว่าเราอาจอ่านไฟล์ .scss
และกำหนดผลลัพธ์ได้โดยไม่ต้องรู้อะไรเกี่ยวกับ HTML เบราว์เซอร์ หรืออินพุตอื่นๆ นี่ไม่ใช่กรณีที่มีคุณสมบัติแบบกำหนดเอง
ตัวประมวลผลล่วงหน้ามี "ขอบเขตของบล็อก" ซึ่งตัวแปรสามารถเปลี่ยนแปลงได้ชั่วคราวภายในตัวเลือก ฟังก์ชัน หรือมิกซ์อิน สิ่งนี้จะเปลี่ยนค่าของตัวแปรภายในบล็อก แต่ก็ยังคงที่ สิ่งนี้ผูกติดอยู่กับบล็อก ไม่ใช่ตัวเลือก ในตัวอย่างด้านล่าง ตัวแปร $background
จะเปลี่ยนแปลงภายในบล็อก . .example
มันเปลี่ยนกลับเป็นค่าเริ่มต้นนอกบล็อกแม้ว่าเราจะใช้ตัวเลือกเดียวกันก็ตาม
$background: red; .example { $background: blue; background: $background; } .example { background: $background; }
ซึ่งจะส่งผลให้:
.example { background: blue; } .example { background: red; }
คุณสมบัติที่กำหนดเองทำงานแตกต่างกัน ในกรณีที่เกี่ยวข้องกับคุณสมบัติแบบกำหนดเอง การกำหนดขอบเขตแบบไดนามิกหมายความว่าคุณสมบัติเหล่านั้นอยู่ภายใต้การสืบทอดและลำดับขั้น คุณสมบัติเชื่อมโยงกับตัวเลือก และหากค่าเปลี่ยนแปลง จะมีผลกับองค์ประกอบ DOM ที่ตรงกันทั้งหมด เช่นเดียวกับคุณสมบัติ CSS อื่นๆ
นี่เป็นสิ่งที่ดีเพราะคุณสามารถเปลี่ยนค่าของคุณสมบัติที่กำหนดเองภายในแบบสอบถามสื่อด้วยตัวเลือกหลอก เช่น โฮเวอร์ หรือแม้กระทั่งกับ JavaScript
a { --link-color: black; } a:hover, a:focus { --link-color: tomato; } @media screen and (min-width: 600px) { a { --link-color: blue; } } a { color: var(--link-color); }
เราไม่จำเป็นต้องเปลี่ยนตำแหน่งที่ใช้คุณสมบัติที่กำหนดเอง — เราเปลี่ยนค่าของคุณสมบัติที่กำหนดเองด้วย CSS ซึ่งหมายความว่าใช้คุณสมบัติที่กำหนดเองเดียวกัน เราสามารถมีค่าต่างกันในตำแหน่งหรือบริบทที่แตกต่างกันในหน้าเดียวกัน
ทั่วโลกกับท้องถิ่น
นอกจากจะเป็นสแตติกหรือไดนามิกแล้ว ตัวแปรยังสามารถเป็นได้ทั้งแบบโกลบอลหรือแบบโลคัล หากคุณเขียน JavaScript คุณจะคุ้นเคยกับสิ่งนี้ ตัวแปรสามารถใช้ได้กับทุกอย่างภายในแอปพลิเคชัน หรือขอบเขตของตัวแปรสามารถจำกัดเฉพาะฟังก์ชันหรือบล็อกของโค้ด
CSS มีความคล้ายคลึงกัน เรามีบางสิ่งที่นำไปใช้ทั่วโลกและบางสิ่งที่เป็นของท้องถิ่นมากกว่า สีของแบรนด์ ระยะห่างในแนวตั้ง และรูปแบบตัวอักษรล้วนเป็นตัวอย่างของสิ่งที่คุณอาจต้องการใช้งานทั่วโลกและสม่ำเสมอทั่วทั้งเว็บไซต์หรือแอปพลิเคชันของคุณ เราก็มีของพื้นเมือง ตัวอย่างเช่น ส่วนประกอบของปุ่มอาจมีรูปแบบขนาดเล็กและขนาดใหญ่ คุณคงไม่อยากใช้ขนาดจากปุ่มเหล่านี้กับองค์ประกอบอินพุตทั้งหมดหรือแม้แต่ทุกองค์ประกอบในหน้า
นี่คือสิ่งที่เราคุ้นเคยใน CSS เราได้พัฒนาระบบการออกแบบ หลักการตั้งชื่อและไลบรารี JavaScript ทั้งหมดเพื่อช่วยในการแยกส่วนประกอบภายในเครื่องและองค์ประกอบการออกแบบทั่วโลก คุณสมบัติที่กำหนดเองมีตัวเลือกใหม่ในการจัดการกับปัญหาเก่านี้
คุณสมบัติที่กำหนดเอง CSS ตามค่าเริ่มต้นจะกำหนดขอบเขตในเครื่องให้กับตัวเลือกเฉพาะที่เรานำไปใช้กับ ดังนั้นพวกมันจึงเหมือนกับตัวแปรท้องถิ่น อย่างไรก็ตาม คุณสมบัติที่กำหนดเองยังได้รับการสืบทอดมา ดังนั้นในหลาย ๆ สถานการณ์คุณสมบัติเหล่านี้จึงทำงานเหมือนกับตัวแปรส่วนกลาง โดยเฉพาะอย่างยิ่งเมื่อใช้กับตัวเลือก :root
ซึ่งหมายความว่าเราจำเป็นต้องไตร่ตรองถึงวิธีการใช้งาน
ตัวอย่างมากมายแสดงให้เห็นคุณสมบัติที่กำหนดเองซึ่งถูกนำไปใช้กับองค์ประกอบ :root
และถึงแม้ว่านี่จะดีสำหรับการสาธิต แต่ก็อาจส่งผลให้เกิดขอบเขตทั่วโลกที่ยุ่งเหยิงและปัญหาที่ไม่ได้ตั้งใจเกี่ยวกับการสืบทอด โชคดีที่เราได้เรียนรู้บทเรียนเหล่านี้แล้ว
ตัวแปรทั่วโลกมีแนวโน้มที่จะคงที่
มีข้อยกเว้นเล็กๆ น้อยๆ สองสามข้อ แต่โดยทั่วไปแล้ว สิ่งที่ทั่วโลกส่วนใหญ่ใน CSS นั้นคงที่เช่นกัน
ตัวแปรทั่วโลก เช่น สีของแบรนด์ การพิมพ์ และการเว้นวรรคมักจะไม่เปลี่ยนแปลงมากนักจากองค์ประกอบหนึ่งไปอีกองค์ประกอบหนึ่ง เมื่อมีการเปลี่ยนแปลง สิ่งนี้มักจะเป็นการรีแบรนด์ทั่วโลกหรือการเปลี่ยนแปลงที่สำคัญอื่นๆ ที่ไม่ค่อยเกิดขึ้นกับผลิตภัณฑ์ที่โตเต็มที่ ยังคงเหมาะสมสำหรับสิ่งเหล่านี้ที่จะเป็นตัวแปร พวกมันถูกใช้ในหลาย ๆ ที่ และตัวแปรช่วยให้มีความสอดคล้องกัน แต่มันไม่สมเหตุสมผลเลยที่พวกเขาจะเป็นไดนามิก ค่าของตัวแปรเหล่านี้จะไม่เปลี่ยนแปลงในลักษณะไดนามิกใดๆ
ด้วยเหตุผลนี้ ฉันขอแนะนำอย่างยิ่งให้ใช้ตัวประมวลผลล่วงหน้าสำหรับตัวแปรโกลบอล (คงที่) สิ่งนี้ไม่เพียงแต่ทำให้มั่นใจได้ว่าพวกมันจะคงที่อยู่เสมอ แต่ยังแสดงให้เห็นด้วยสายตาภายในโค้ด ซึ่งจะทำให้ CSS อ่านง่ายขึ้นและดูแลรักษาได้ง่ายขึ้น
ตัวแปรคงที่ในเครื่องนั้นใช้ได้ (บางครั้ง)
คุณอาจคิดว่าเนื่องจากจุดยืนที่แข็งแกร่งเกี่ยวกับตัวแปรส่วนกลางเป็นแบบคงที่ ซึ่งโดยการสะท้อนกลับ ตัวแปรในเครื่องทั้งหมดอาจต้องเป็นไดนามิก แม้ว่าจะเป็นความจริงที่ตัวแปรโลคัลมีแนวโน้มที่จะเป็นไดนามิก แต่ก็ไม่ได้แข็งแกร่งเท่ากับแนวโน้มที่ตัวแปรส่วนกลางจะคงที่
ตัวแปรสแตติกในเครื่องนั้นใช้ได้อย่างสมบูรณ์ในหลายสถานการณ์ ฉันใช้ตัวแปรตัวประมวลผลล่วงหน้าในไฟล์ส่วนประกอบเป็นส่วนใหญ่เพื่อความสะดวกของนักพัฒนา
พิจารณาตัวอย่างคลาสสิกของส่วนประกอบปุ่มที่มีขนาดแตกต่างกัน
scss
ของฉันอาจมีลักษณะดังนี้:
$button-sml: 1em; $button-med: 1.5em; $button-lrg: 2em; .btn { // Visual styles } .btn-sml { font-size: $button-sml; } .btn-med { font-size: $button-med; } .btn-lrg { font-size: $button-lrg; }
เห็นได้ชัดว่า ตัวอย่างนี้จะเหมาะสมกว่าถ้าฉันใช้ตัวแปรหลายครั้งหรือได้รับค่าระยะขอบและช่องว่างภายในจากตัวแปรขนาด อย่างไรก็ตาม ความสามารถในการสร้างต้นแบบขนาดต่างๆ ได้อย่างรวดเร็วอาจเป็นเหตุผลที่เพียงพอ
เนื่องจากตัวแปรสแตติกส่วนใหญ่เป็นแบบโกลบอล ฉันชอบแยกความแตกต่างของตัวแปรสแตติกที่ใช้ภายในส่วนประกอบเท่านั้น ในการทำเช่นนี้ คุณสามารถนำหน้าตัวแปรเหล่านี้ด้วยชื่อส่วนประกอบ หรือคุณสามารถใช้คำนำหน้าอื่น เช่น c-variable-name
สำหรับส่วนประกอบ หรือ l-variable-name
สำหรับ local คุณสามารถใช้คำนำหน้าอะไรก็ได้ตามต้องการ หรือจะใช้คำนำหน้าตัวแปรส่วนกลางก็ได้ ไม่ว่าคุณจะเลือกอะไร การแยกความแตกต่างโดยเฉพาะอย่างยิ่งหากแปลง codebase ที่มีอยู่ไปใช้คุณสมบัติที่กำหนดเองจะเป็นประโยชน์
เมื่อใดควรใช้คุณสมบัติที่กำหนดเอง
หากใช้ตัวแปรสแตติกภายในส่วนประกอบได้ เราควรใช้คุณสมบัติที่กำหนดเองเมื่อใด การแปลงตัวแปรตัวประมวลผลล่วงหน้าที่มีอยู่เป็นคุณสมบัติที่กำหนดเองมักจะไม่สมเหตุสมผล ท้ายที่สุดแล้ว เหตุผลสำหรับคุณสมบัติที่กำหนดเองนั้นแตกต่างอย่างสิ้นเชิง คุณสมบัติที่กำหนดเองเหมาะสมเมื่อเรามีคุณสมบัติ CSS ที่เปลี่ยนแปลงโดยสัมพันธ์กับเงื่อนไขใน DOM โดยเฉพาะอย่างยิ่งเงื่อนไขแบบไดนามิก เช่น :focus
, :hover
, การสืบค้นสื่อ หรือ JavaScript
ฉันสงสัยว่าเราจะใช้ตัวแปรสแตติกบางรูปแบบเสมอ แม้ว่าเราอาจต้องการน้อยลงในอนาคต เนื่องจากคุณสมบัติที่กำหนดเองเสนอวิธีใหม่ในการจัดระเบียบตรรกะและโค้ด ถึงเวลานั้น ฉันคิดว่าในสถานการณ์ส่วนใหญ่ เราจะทำงานร่วมกับตัวแปรตัวประมวลผลล่วงหน้าและคุณสมบัติที่กำหนดเองร่วมกัน
การรู้ว่าเราสามารถกำหนดตัวแปรสแตติกให้กับคุณสมบัติที่กำหนดเองได้จะเป็นประโยชน์ ไม่ว่าจะเป็นโกลบอลหรือโลคัล การแปลงตัวแปรสแตติกเป็นคุณสมบัติกำหนดเองแบบไดนามิกในเครื่องในหลายสถานการณ์ในสถานการณ์ต่างๆ
หมายเหตุ : คุณทราบหรือไม่ว่า $var
เป็นค่าที่ถูกต้องสำหรับคุณสมบัติที่กำหนดเอง Sass เวอร์ชันล่าสุดรู้จักสิ่งนี้ ดังนั้นเราจึงจำเป็นต้องสอดแทรกตัวแปรที่กำหนดให้กับคุณสมบัติที่กำหนดเอง เช่น #{$var}
สิ่งนี้บอก Sass ว่าคุณต้องการส่งออกค่าของตัวแปร แทนที่จะเป็นเพียง $var
ในสไตล์ชีต สิ่งนี้จำเป็นสำหรับสถานการณ์เช่นคุณสมบัติที่กำหนดเองเท่านั้น โดยที่ชื่อตัวแปรสามารถเป็น CSS ที่ถูกต้องได้เช่นกัน
หากเราใช้ตัวอย่างปุ่มด้านบนและตัดสินใจว่าปุ่มทั้งหมดควรใช้รูปแบบเล็กๆ บนอุปกรณ์มือถือ โดยไม่คำนึงถึงคลาสที่ใช้ใน HTML นี่เป็นสถานการณ์ที่มีไดนามิกมากขึ้น สำหรับสิ่งนี้ เราควรใช้คุณสมบัติแบบกำหนดเอง
$button-sml: 1em; $button-med: 1.5em; $button-lrg: 2em; .btn { --button-size: #{$button-sml}; } @media screen and (min-width: 600px) { .btn-med { --button-size: #{$button-med}; } .btn-lrg { --button-size: #{$button-lrg}; } } .btn { font-size: var(--button-size); }
ที่นี่ฉันสร้างคุณสมบัติกำหนดเองเดียว: --button-size
คุณสมบัติที่กำหนดเองนี้เริ่มกำหนดขอบเขตให้กับองค์ประกอบปุ่มทั้งหมดโดยใช้คลาส btn
จากนั้นฉันก็เปลี่ยนค่าของ --button-size
สูงกว่า 600px สำหรับคลาส btn-med
และ btn-lrg
สุดท้าย ฉันใช้คุณสมบัติที่กำหนดเองนี้กับองค์ประกอบปุ่มทั้งหมดในที่เดียว
อย่าฉลาดเกินไป
ลักษณะแบบไดนามิกของคุณสมบัติที่กำหนดเองทำให้เราสร้างส่วนประกอบที่ชาญฉลาดและซับซ้อนได้
ด้วยการแนะนำตัวประมวลผลล่วงหน้า พวกเราหลายคนได้สร้างไลบรารีที่มีนามธรรมที่ชาญฉลาดโดยใช้มิกซ์อินและฟังก์ชันที่กำหนดเอง ในบางกรณี ตัวอย่างเช่นนี้ยังคงมีประโยชน์อยู่ในปัจจุบัน แต่โดยส่วนใหญ่ ยิ่งฉันทำงานกับตัวประมวลผลล่วงหน้านานเท่าไร ฉันก็ยิ่งใช้คุณสมบัติน้อยลงเท่านั้น วันนี้ ฉันใช้ตัวประมวลผลล่วงหน้าสำหรับตัวแปรสแตติกโดยเฉพาะ
คุณสมบัติที่กำหนดเองจะไม่ (และไม่ควร) ได้รับการยกเว้นจากการทดลองประเภทนี้ และฉันหวังว่าจะได้เห็นตัวอย่างที่ชาญฉลาดมากมาย แต่ในระยะยาว โค้ดที่อ่านได้และบำรุงรักษาได้จะชนะนามธรรมที่ชาญฉลาดเสมอ (อย่างน้อยก็ในเวอร์ชันที่ใช้งานจริง)
ฉันได้อ่านบทความที่ยอดเยี่ยมเกี่ยวกับหัวข้อนี้ในสื่อ Free Code Camp เมื่อเร็วๆ นี้ เขียนโดย Bill Sourour และมีชื่อว่า Don't Do It At Runtime ทำในเวลาออกแบบ” แทนที่จะถอดความข้อโต้แย้งของเขา ฉันจะให้คุณอ่าน
ความแตกต่างที่สำคัญอย่างหนึ่งระหว่างตัวแปรตัวประมวลผลล่วงหน้าและคุณสมบัติแบบกำหนดเองคือ คุณสมบัติแบบกำหนดเองทำงานที่รันไทม์ ซึ่งหมายความว่าสิ่งที่อาจเป็นที่ยอมรับได้ในแง่ของความซับซ้อน โดยตัวประมวลผลล่วงหน้าอาจไม่ใช่แนวคิดที่ดีกับคุณสมบัติที่กำหนดเอง
ตัวอย่างหนึ่งที่แสดงให้เห็นสิ่งนี้สำหรับฉันเมื่อเร็ว ๆ นี้คือ:
:root { --font-scale: 1.2; --font-size-1: calc(var(--font-scale) * var(--font-size-2)); --font-size-2: calc(var(--font-scale) * var(--font-size-3)); --font-size-3: calc(var(--font-scale) * var(--font-size-4)); --font-size-4: 1rem; }
สิ่งนี้สร้างมาตราส่วนแบบแยกส่วน มาตราส่วนแบบแยกส่วนคือชุดของตัวเลขที่เกี่ยวข้องกันโดยใช้อัตราส่วน มักใช้ในการออกแบบและพัฒนาเว็บเพื่อกำหนดขนาดตัวอักษรหรือระยะห่าง
ในตัวอย่างนี้ คุณสมบัติที่กำหนดเองแต่ละรายการถูกกำหนดโดยใช้ calc()
โดยนำค่าของคุณสมบัติที่กำหนดเองก่อนหน้ามาคูณด้วยอัตราส่วน การทำเช่นนี้ เราจะได้ตัวเลขถัดไปในมาตราส่วน
ซึ่งหมายความว่าอัตราส่วนจะถูกคำนวณ ณ รันไทม์ และคุณสามารถเปลี่ยนได้โดยการอัปเดตเฉพาะค่าของคุณสมบัติ --font-scale
ตัวอย่างเช่น:
@media screen and (min-width: 800px) { :root { --font-scale: 1.33; } }
วิธีนี้เป็นวิธีที่ชาญฉลาด รัดกุม และเร็วกว่าการคำนวณค่าทั้งหมดอีกครั้ง หากคุณต้องการเปลี่ยนมาตราส่วน เป็นสิ่งที่ฉันจะ ไม่ ทำในรหัสการผลิต
แม้ว่าตัวอย่างข้างต้นจะมีประโยชน์สำหรับการสร้างต้นแบบ แต่ในการใช้งานจริง ฉันอยากเห็นสิ่งนี้มากกว่า:
:root { --font-size-1: 1.728rem; --font-size-2: 1.44rem; --font-size-3: 1.2em; --font-size-4: 1em; } @media screen and (min-width: 800px) { :root { --font-size-1: 2.369rem; --font-size-2: 1.777rem; --font-size-3: 1.333rem; --font-size-4: 1rem; } }
คล้ายกับตัวอย่างในบทความของ Bill ฉันพบว่าการดูว่าค่าที่แท้จริงคืออะไร เราอ่านโค้ดมากกว่าที่เราเขียนหลายครั้ง และค่าส่วนกลาง เช่น ขนาดฟอนต์เปลี่ยนแปลงไม่บ่อยนักในการผลิต
ตัวอย่างข้างต้นยังไม่สมบูรณ์ มันละเมิดกฎตั้งแต่ก่อนหน้านี้ว่า ค่าส่วนกลางควรเป็นแบบคงที่ ฉันต้องการใช้ตัวแปรตัวประมวลผลล่วงหน้าและแปลงเป็นคุณสมบัติที่กำหนดเองแบบไดนามิกในเครื่องโดยใช้เทคนิคที่แสดงไว้ก่อนหน้านี้
สิ่งสำคัญคือต้องหลีกเลี่ยงสถานการณ์ที่เราเปลี่ยนจากการใช้คุณสมบัติแบบกำหนดเองหนึ่งไปเป็นคุณสมบัติกำหนดเองอื่น สิ่งนี้สามารถเกิดขึ้นได้เมื่อเราตั้งชื่อคุณสมบัติเช่นนี้
เปลี่ยนค่าไม่ใช่ตัวแปร
เปลี่ยนค่าไม่ใช่ตัวแปรเป็นหนึ่งในกลยุทธ์ที่สำคัญที่สุดสำหรับการใช้คุณสมบัติที่กำหนดเองอย่างมีประสิทธิภาพ
ตามกฎทั่วไป คุณไม่ควรเปลี่ยนคุณสมบัติที่กำหนดเองที่ใช้เพื่อวัตถุประสงค์เดียว ทำได้ง่ายมากเพราะนี่คือวิธีที่เราทำกับตัวประมวลผลล่วงหน้า แต่คุณสมบัติที่กำหนดเองนั้นไม่สมเหตุสมผล
ในตัวอย่างนี้ เรามีคุณสมบัติแบบกำหนดเองสองคุณสมบัติที่ใช้กับส่วนประกอบตัวอย่าง ฉันเปลี่ยนจากการใช้ค่า --font-size-small
เป็น --font-size-large
ขึ้นอยู่กับขนาดหน้าจอ
:root { --font-size-small: 1.2em; --font-size-large: 2em; } .example { font-size: var(--font-size-small); } @media screen and (min-width: 800px) { .example { font-size: var(--font-size-large); } }
วิธีที่ดีกว่าในการทำเช่นนี้คือการกำหนดคุณสมบัติที่กำหนดเองรายการเดียวซึ่งกำหนดขอบเขตไว้ที่ส่วนประกอบ จากนั้นใช้คิวรีสื่อหรือตัวเลือกอื่นๆ เปลี่ยนค่า
.example { --example-font-size: 1.2em; } @media screen and (min-width: 800px) { .example { --example-font-size: 2em; } }
สุดท้ายนี้ ในที่เดียว ฉันใช้ค่าของคุณสมบัติที่กำหนดเองนี้:
.example { font-size: var(--example-font-size); }
ในตัวอย่างนี้และอื่น ๆ ก่อนหน้านั้น คิวรีสื่อใช้เพื่อเปลี่ยนค่าของคุณสมบัติที่กำหนดเองเท่านั้น คุณอาจสังเกตเห็นว่ามีเพียงที่เดียวที่ใช้คำสั่ง var()
และคุณสมบัติ CSS ปกติจะได้รับการอัปเดต
การแยกระหว่างการประกาศตัวแปรและการประกาศคุณสมบัตินี้เป็นการจงใจ มีเหตุผลหลายประการ แต่ข้อดีจะชัดเจนที่สุดเมื่อคิดถึงการออกแบบที่ตอบสนอง
การออกแบบที่ตอบสนองด้วยคุณสมบัติที่กำหนดเอง
ปัญหาอย่างหนึ่งของการออกแบบที่ตอบสนองตามอุปกรณ์เมื่อต้องอาศัยการสืบค้นข้อมูลสื่อเป็นอย่างมากคือ ไม่ว่าคุณจะจัดระเบียบ CSS อย่างไร สไตล์ที่เกี่ยวข้องกับองค์ประกอบเฉพาะจะกระจัดกระจายไปทั่วสไตล์ชีต
เป็นเรื่องยากมากที่จะทราบว่าคุณสมบัติ CSS ใดจะเปลี่ยนแปลง อย่างไรก็ตาม คุณสมบัติที่กำหนดเองของ CSS สามารถช่วยเราจัดระเบียบตรรกะบางอย่างที่เกี่ยวข้องกับการออกแบบที่ตอบสนองและทำให้การทำงานกับการสืบค้นสื่อง่ายขึ้นมาก
ถ้ามันเปลี่ยนแปลง มันก็เป็นตัวแปร
คุณสมบัติที่เปลี่ยนแปลงโดยใช้เคียวรีสื่อเป็นไดนามิกโดยเนื้อแท้ และคุณสมบัติแบบกำหนดเองให้วิธีการแสดงค่าไดนามิกใน CSS ซึ่งหมายความว่าหากคุณใช้แบบสอบถามสื่อเพื่อเปลี่ยนคุณสมบัติ CSS ใด ๆ คุณควรวางค่านี้ในคุณสมบัติที่กำหนดเอง
จากนั้น คุณสามารถย้ายสิ่งนี้ไปพร้อมกับกฎของสื่อ สถานะโฮเวอร์ หรือตัวเลือกไดนามิกใดๆ ที่กำหนดการเปลี่ยนแปลงค่า ไปที่ด้านบนสุดของเอกสาร
แยกตรรกะออกจากการออกแบบ
เมื่อทำอย่างถูกต้อง การแยกตรรกะและการออกแบบหมายความว่าคิวรี สื่อจะใช้เพื่อเปลี่ยนค่าของคุณสมบัติที่กำหนดเอง เท่านั้น หมายความว่าตรรกะทั้งหมดที่เกี่ยวข้องกับการออกแบบที่ตอบสนองควรอยู่ที่ด้านบนสุดของเอกสาร และทุกที่ที่เราเห็นคำสั่ง var()
ใน CSS เรารู้ทันทีว่าคุณสมบัตินี้เปลี่ยนแปลงไป ด้วยวิธีการเขียน CSS แบบเดิมๆ ไม่มีทางรู้เรื่องนี้ได้ในพริบตา
พวกเราหลายคนสามารถอ่านและตีความ CSS ได้อย่างรวดเร็วในขณะที่ติดตามในหัวว่าคุณสมบัติใดเปลี่ยนแปลงไปในสถานการณ์ต่างๆ เบื่อแล้ว ไม่อยากทำอีกแล้ว! คุณสมบัติที่กำหนดเองในขณะนี้มีการเชื่อมโยงระหว่างตรรกะและการนำไปใช้งาน ดังนั้นเราไม่จำเป็นต้องติดตามสิ่งนี้ และนั่นก็มีประโยชน์อย่างเหลือเชื่อ!
ลอจิกพับ
แนวคิดในการประกาศตัวแปรที่ด้านบนของเอกสารหรือฟังก์ชันไม่ใช่แนวคิดใหม่ เป็นสิ่งที่เราทำในภาษาส่วนใหญ่ และตอนนี้ก็เป็นสิ่งที่เราสามารถทำได้ใน CSS เช่นกัน การเขียน CSS ในลักษณะนี้จะสร้างความแตกต่างทางภาพที่ชัดเจนระหว่าง CSS ที่ด้านบนสุดของเอกสารและด้านล่าง ฉันต้องการวิธีแยกแยะส่วนเหล่านี้เมื่อฉันพูดถึงพวกเขา และแนวคิดของ "ตรรกะพับ" เป็นคำอุปมาที่ฉันเริ่มใช้
ครึ่งหน้าบนมีตัวแปรตัวประมวลผลล่วงหน้าและคุณสมบัติที่กำหนดเองทั้งหมด ซึ่งรวมถึงค่าต่างๆ ที่คุณสมบัติแบบกำหนดเองสามารถมีได้ การติดตามการเปลี่ยนแปลงคุณสมบัติที่กำหนดเองควรเป็นเรื่องง่าย
CSS ครึ่งหน้าล่างนั้นตรงไปตรงมาและมีการประกาศอย่างสูงและอ่านง่าย รู้สึกเหมือน CSS ก่อนการสืบค้นสื่อและความซับซ้อนที่จำเป็นอื่น ๆ ของ CSS สมัยใหม่
มาดูตัวอย่างง่ายๆ ของระบบกริด flexbox แบบหกคอลัมน์:
.row { --row-display: block; } @media screen and (min-width: 600px) { .row { --row-display: flex; } }
คุณสมบัติที่กำหนดเอง --row-display
เริ่มแรกตั้งค่าให้ block
สูงกว่า 600px โหมดการแสดงผลถูกตั้งค่าเป็น flex
ครึ่งหน้าล่างอาจมีลักษณะดังนี้:
.row { display: var(--row-display); flex-direction: row; flex-wrap: nowrap; } .col-1, .col-2, .col-3, .col-4, .col-5, .col-6 { flex-grow: 0; flex-shrink: 0; } .col-1 { flex-basis: 16.66%; } .col-2 { flex-basis: 33.33%; } .col-3 { flex-basis: 50%; } .col-4 { flex-basis: 66.66%; } .col-5 { flex-basis: 83.33%; } .col-6 { flex-basis: 100%; }
เรารู้ทันทีว่า --row-display
เป็นค่าที่เปลี่ยนแปลง ในขั้นต้น จะเป็น block
ดังนั้นค่า flex จะถูกละเว้น
ตัวอย่างนี้ค่อนข้างง่าย แต่ถ้าเราขยายให้รวมคอลัมน์ความกว้างที่ยืดหยุ่นได้ซึ่งเติมพื้นที่ที่เหลือ ก็มีแนวโน้มว่าจะต้องแปลงค่า flex-grow
, flex-shrink
และ flex-basis
เป็นคุณสมบัติที่กำหนดเอง คุณสามารถลองทำสิ่งนี้หรือดูตัวอย่างโดยละเอียดเพิ่มเติมได้ที่นี่
คุณสมบัติที่กำหนดเองสำหรับธีม
ฉันมักจะโต้แย้งกับการใช้คุณสมบัติที่กำหนดเองสำหรับตัวแปรไดนามิกทั่วโลก และหวังว่าจะเป็นนัยว่าการแนบคุณสมบัติที่กำหนดเองเข้ากับตัวเลือก :root
นั้นในหลายกรณีถือว่าเป็นอันตราย แต่กฎทุกข้อมีข้อยกเว้น และสำหรับคุณสมบัติที่กำหนดเอง มันคือการกำหนดธีม
การใช้คุณสมบัติที่กำหนดเองทั่วโลกอย่างจำกัดจะทำให้การสร้างธีมง่ายขึ้นมาก
โดยทั่วไป ธีมหมายถึงการให้ผู้ใช้ปรับแต่ง UI ด้วยวิธีใดวิธีหนึ่ง นี่อาจเป็นบางอย่างเช่นการเปลี่ยนสีในหน้าโปรไฟล์ หรือมันอาจจะเป็นภาษาท้องถิ่นมากขึ้น ตัวอย่างเช่น คุณสามารถเลือกสีของโน้ตในแอปพลิเคชัน Google Keep
ธีมมักจะเกี่ยวข้องกับการรวบรวมสไตล์ชีตแยกต่างหากเพื่อแทนที่ค่าเริ่มต้นด้วยการตั้งค่าของผู้ใช้ หรือการรวบรวมสไตล์ชีตที่แตกต่างกันสำหรับผู้ใช้แต่ละราย ทั้งสองสิ่งนี้อาจเป็นเรื่องยากและมีผลกระทบต่อประสิทธิภาพการทำงาน
ด้วยคุณสมบัติแบบกำหนดเอง เราไม่จำเป็นต้องคอมไพล์สไตล์ชีตอื่น เราจำเป็นต้องอัปเดตค่าคุณสมบัติตามความชอบของผู้ใช้เท่านั้น เนื่องจากเป็นค่าที่สืบทอดมา หากเราทำสิ่งนี้กับองค์ประกอบรูท พวกมันสามารถใช้ที่ใดก็ได้ในแอปพลิเคชันของเรา
ใช้ประโยชน์จากคุณสมบัติไดนามิกทั่วโลก
คุณสมบัติแบบกำหนดเองจะคำนึงถึงขนาดตัวพิมพ์และเนื่องจากคุณสมบัติที่กำหนดเองส่วนใหญ่จะเป็นแบบโลคัล หากคุณใช้คุณสมบัติไดนามิกโกลบอล การใช้ประโยชน์จากคุณสมบัติเหล่านี้จึงเหมาะสม
:root { --THEME-COLOR: var(--user-theme-color, #d33a2c); }
การใช้อักษรตัวพิมพ์ใหญ่ของตัวแปรมักหมายถึงค่าคงที่ทั่วโลก สำหรับเรา นี่หมายความว่าพร็อพเพอร์ตี้ได้รับการตั้งค่าไว้ที่อื่นในแอปพลิเคชัน และเราไม่ควรเปลี่ยนในเครื่อง
หลีกเลี่ยงการตั้งค่า Global Dynamic Properties โดยตรง
คุณสมบัติที่กำหนดเองยอมรับค่าทางเลือก อาจเป็นประโยชน์ในการหลีกเลี่ยงการเขียนทับค่าของคุณสมบัติที่กำหนดเองส่วนกลางโดยตรง และแยกค่าของผู้ใช้ออกจากกัน เราสามารถใช้ค่าทางเลือกเพื่อทำสิ่งนี้
ตัวอย่างข้างต้นตั้งค่าของ --THEME-COLOR
เป็นค่า --user-theme-color
หากมี หากไม่ได้ตั้งค่า --user-theme-color
ค่าของ #d33a2c
จะถูกนำมาใช้ ด้วยวิธีนี้ เราไม่จำเป็นต้องจัดเตรียมทางเลือกสำรองทุกครั้งที่ใช้ --THEME-COLOR
คุณอาจคาดหวังในตัวอย่างด้านล่างว่าพื้นหลังจะถูกตั้งค่าเป็น green
อย่างไรก็ตาม ค่าของ --user-theme-color
ยังไม่ได้ตั้งค่าบนองค์ประกอบรูท ดังนั้นค่าของ --THEME-COLOR
จึงไม่เปลี่ยนแปลง
:root { --THEME-COLOR: var(--user-theme-color, #d33a2c); } body { --user-theme-color: green; background: var(--THEME-COLOR); }
การตั้งค่าคุณสมบัติไดนามิกทั่วโลกโดยอ้อมเช่นนี้จะปกป้องพวกเขาจากการถูกเขียนทับในเครื่อง และทำให้มั่นใจได้ว่าการตั้งค่าของผู้ใช้จะสืบทอดมาจากองค์ประกอบรูทเสมอ นี่เป็นแนวทางที่มีประโยชน์ในการปกป้องค่าธีมของคุณและหลีกเลี่ยงการสืบทอดโดยไม่ได้ตั้งใจ
หากเราต้องการเปิดเผยคุณสมบัติเฉพาะสำหรับการสืบทอด เราสามารถแทนที่ :root
ตัวเลือกด้วยตัวเลือก *
:
* { --THEME-COLOR: var(--user-theme-color, #d33a2c); } body { --user-theme-color: green; background: var(--THEME-COLOR); }
ตอนนี้ ค่าของ --THEME-COLOR
จะถูกคำนวณใหม่สำหรับทุกองค์ประกอบ ดังนั้นจึงสามารถใช้ค่าท้องถิ่นของ --user-theme-color
ได้ กล่าวคือ สีพื้นหลังในตัวอย่างนี้จะเป็น green
คุณสามารถดูตัวอย่างรายละเอียดเพิ่มเติมของรูปแบบนี้ได้ในส่วนการจัดการสีด้วยคุณสมบัติที่กำหนดเอง
กำลังอัปเดตคุณสมบัติที่กำหนดเองด้วย JavaScript
หากคุณต้องการตั้งค่าคุณสมบัติที่กำหนดเองโดยใช้ JavaScript มี API ที่ค่อนข้างเรียบง่ายและมีลักษณะดังนี้:
const elm = document.documentElement; elm.style.setProperty('--USER-THEME-COLOR', 'tomato');
ที่นี่ฉันกำลังตั้งค่า --USER-THEME-COLOR
บนองค์ประกอบเอกสารหรือกล่าวอีกนัยหนึ่งคือองค์ประกอบ :root
ที่องค์ประกอบทั้งหมดจะสืบทอดมา
นี่ไม่ใช่ API ใหม่ มันเป็นวิธี JavaScript เดียวกันสำหรับการอัปเดตสไตล์บนองค์ประกอบ นี่คือรูปแบบอินไลน์ ดังนั้นพวกมันจะมีความจำเพาะที่สูงกว่า CSS ปกติ
ซึ่งหมายความว่าง่ายต่อการใช้การปรับแต่งในเครื่อง:
.note { --note-color: #eaeaea; } .note { background: var(--note-color); }
ที่นี่ฉันตั้งค่าเริ่มต้นสำหรับ --note-color
และกำหนดขอบเขตเป็นองค์ประกอบ . .note
ฉันแยกการประกาศตัวแปรแยกจากการประกาศคุณสมบัติ แม้ในตัวอย่างง่ายๆ นี้
const elm = document.querySelector('#note-uid'); elm.style.setProperty('--note-color', 'yellow');
จากนั้นฉันกำหนดเป้าหมายอินสแตนซ์เฉพาะขององค์ประกอบ .note
และเปลี่ยนค่าของคุณสมบัติที่กำหนดเอง --note-color
สำหรับองค์ประกอบนั้นเท่านั้น ตอนนี้จะมีความจำเพาะสูงกว่าค่าเริ่มต้น
คุณสามารถดูว่าสิ่งนี้ทำงานอย่างไรกับตัวอย่างนี้โดยใช้ React การกำหนดค่าตามความชอบของผู้ใช้เหล่านี้สามารถบันทึกในที่จัดเก็บในตัวเครื่องหรือในฐานข้อมูลในกรณีของแอพพลิเคชั่นขนาดใหญ่
การจัดการสีด้วยคุณสมบัติที่กำหนดเอง
นอกจากค่าฐานสิบหกและสีที่มีชื่อแล้ว CSS ยังมีฟังก์ชันสี เช่น rgb()
และ hsl()
สิ่งเหล่านี้ช่วยให้เราสามารถระบุองค์ประกอบแต่ละส่วนของสีได้ เช่น เฉดสีหรือความสว่าง คุณสมบัติที่กำหนดเองสามารถใช้ร่วมกับฟังก์ชันสีได้
:root { --hue: 25; } body { background: hsl(var(--hue), 80%, 50%); }
สิ่งนี้มีประโยชน์ แต่คุณสมบัติบางอย่างที่ใช้กันอย่างแพร่หลายที่สุดของพรีโปรเซสเซอร์คือฟังก์ชันสีขั้นสูงที่ช่วยให้เราสามารถจัดการสีโดยใช้ฟังก์ชันต่างๆ เช่น ทำให้สว่างขึ้น ทำให้มืดลง หรือลดความอิ่มตัว:
darken($base-color, 10%); lighten($base-color, 10%); desaturate($base-color, 20%);
การมีคุณสมบัติเหล่านี้ในเบราว์เซอร์จะเป็นประโยชน์ พวกเขากำลังมา แต่จนกว่าเราจะมีฟังก์ชันการปรับเปลี่ยนสีดั้งเดิมใน CSS คุณสมบัติที่กำหนดเองสามารถเติมช่องว่างบางส่วนนั้นได้
เราได้เห็นแล้วว่าคุณสมบัติที่กำหนดเองสามารถใช้ได้ในฟังก์ชันสีที่มีอยู่ เช่น rgb()
และ hsl()
แต่ก็สามารถใช้ใน calc()
ได้เช่นกัน ซึ่งหมายความว่าเราสามารถแปลงจำนวนจริงเป็นเปอร์เซ็นต์ได้โดยการคูณมัน เช่น calc(50 * 1%)
= 50%
:root { --lightness: 50; } body { background: hsl(25, 80%, calc(var(--lightness) * 1%)); }
เหตุผลที่เราต้องการจัดเก็บค่าความสว่างเป็นจำนวนจริงคือเพื่อให้เราสามารถจัดการกับการคำนวณด้วยการ calc
ก่อนที่จะแปลงเป็นเปอร์เซ็นต์ ตัวอย่างเช่น ถ้าฉันต้องการทำให้สีมืดลง 20%
ฉันสามารถคูณความสว่างของสีด้วย 0.8
เราสามารถทำให้อ่านง่ายขึ้นเล็กน้อยโดยแยกการคำนวณความสว่างออกเป็นคุณสมบัติที่กำหนดเองที่มีขอบเขตในเครื่อง:
:root { --lightness: 50; } body { --lightness: calc(var(--lightness * 0.8)); background: hsl(25, 80%, calc(var(--lightness) * 1%)); }
เรา สามารถ สรุปการคำนวณเพิ่มเติมและสร้างบางอย่างเช่นฟังก์ชันการปรับเปลี่ยนสีใน CSS โดยใช้คุณสมบัติที่กำหนดเอง ตัวอย่างนี้น่าจะซับซ้อนเกินไปสำหรับกรณีการใช้งานจริงส่วนใหญ่ของชุดรูปแบบ แต่แสดงให้เห็นถึงพลังเต็มรูปแบบของคุณสมบัติกำหนดเองแบบไดนามิก
ลดความซับซ้อนของธีม
ข้อดีอย่างหนึ่งของการใช้คุณสมบัติแบบกำหนดเองคือความสามารถในการทำให้ชุดรูปแบบง่ายขึ้น แอปพลิเคชันไม่จำเป็นต้องทราบว่ามีการใช้คุณสมบัติแบบกำหนดเองอย่างไร เราใช้ JavaScript หรือโค้ดฝั่งเซิร์ฟเวอร์เพื่อตั้งค่าคุณสมบัติที่กำหนดเองแทน วิธีการใช้ค่าเหล่านี้จะถูกกำหนดโดยสไตล์ชีต
ซึ่งหมายความว่าเราสามารถแยกตรรกะออกจากการออกแบบได้อีกครั้ง หากคุณมีทีมออกแบบทางเทคนิค ผู้เขียนสามารถอัปเดตสไตล์ชีตและตัดสินใจว่าจะใช้คุณสมบัติที่กำหนดเองได้อย่างไรโดยไม่ต้องเปลี่ยน JavaScript หรือโค้ดแบ็กเอนด์แม้แต่บรรทัดเดียว
คุณสมบัติที่กำหนดเองยังช่วยให้สามารถย้ายความซับซ้อนของธีมไปยัง CSS และความซับซ้อนนี้อาจส่งผลเสียต่อความสามารถในการบำรุงรักษา CSS ของคุณ ดังนั้นอย่าลืมทำให้ง่ายในทุกที่ที่ทำได้
ใช้คุณสมบัติที่กำหนดเองวันนี้
แม้ว่าคุณจะรองรับ IE10 และ 11 คุณก็เริ่มใช้คุณสมบัติที่กำหนดเองได้ตั้งแต่วันนี้ ตัวอย่างส่วนใหญ่ในบทความนี้เกี่ยวข้องกับวิธีที่เราเขียนและจัดโครงสร้าง CSS ประโยชน์มีนัยสำคัญในแง่ของความสามารถในการบำรุงรักษา อย่างไรก็ตาม ตัวอย่างส่วนใหญ่ลดเฉพาะสิ่งที่สามารถทำได้ด้วยโค้ดที่ซับซ้อนมากขึ้นเท่านั้น
ฉันใช้เครื่องมือที่เรียกว่า postcss-css-variables เพื่อแปลงคุณสมบัติส่วนใหญ่ของคุณสมบัติที่กำหนดเองให้เป็นการแสดงโค้ดแบบคงที่ เครื่องมืออื่นที่คล้ายคลึงกันจะละเว้นคุณสมบัติที่กำหนดเองภายในการสืบค้นสื่อหรือตัวเลือกที่ซับซ้อน โดยถือว่าคุณสมบัติที่กำหนดเองเหมือนกับตัวแปรตัวประมวลผลล่วงหน้า
สิ่งที่เครื่องมือเหล่านี้ไม่สามารถทำได้คือเลียนแบบคุณลักษณะรันไทม์ของคุณสมบัติที่กำหนดเอง ซึ่งหมายความว่าไม่มีคุณลักษณะแบบไดนามิก เช่น ธีมหรือการเปลี่ยนแปลงคุณสมบัติด้วย JavaScript ซึ่งอาจเป็นเรื่องปกติในหลาย ๆ สถานการณ์ การปรับแต่ง UI อาจได้รับการพิจารณาว่าเป็นการปรับปรุงแบบก้าวหน้าและธีมเริ่มต้นอาจเป็นที่ยอมรับได้อย่างสมบูรณ์สำหรับเบราว์เซอร์รุ่นเก่า ทั้งนี้ขึ้นอยู่กับสถานการณ์
กำลังโหลดสไตล์ชีตที่ถูกต้อง
คุณสามารถใช้ postCSS ได้หลายวิธี ฉันใช้กระบวนการ gulp
เพื่อรวบรวมสไตล์ชีตที่แยกจากกันสำหรับเบราว์เซอร์ที่ใหม่กว่าและเก่ากว่า งาน gulp
รุ่นง่ายของฉันมีลักษณะดังนี้:
import gulp from "gulp"; import sass from "gulp-sass"; import postcss from "gulp-postcss"; import rename from "gulp-rename"; import cssvariables from "postcss-css-variables"; import autoprefixer from "autoprefixer"; import cssnano from "cssnano"; gulp.task("css-no-vars", () => gulp .src("./src/css/*.scss") .pipe(sass().on("error", sass.logError)) .pipe(postcss([cssvariables(), cssnano()])) .pipe(rename({ extname: ".no-vars.css" })) .pipe(gulp.dest("./dist/css")) ); gulp.task("css", () => gulp .src("./src/css/*.scss") .pipe(sass().on("error", sass.logError)) .pipe(postcss([cssnano()])) .pipe(rename({ extname: ".css" })) .pipe(gulp.dest("./dist/css")) );
สิ่งนี้ส่งผลให้ไฟล์ CSS สองไฟล์: ไฟล์ปกติที่มีคุณสมบัติที่กำหนดเอง ( styles.css
) และอีกไฟล์สำหรับเบราว์เซอร์รุ่นเก่า ( styles.no-vars.css
) ฉันต้องการให้ IE10 และ 11 ให้บริการ styles.no-vars.css
และเบราว์เซอร์อื่นๆ เพื่อรับไฟล์ CSS ปกติ
โดยปกติ ฉันจะสนับสนุนโดยใช้การสืบค้นข้อมูลคุณลักษณะ แต่ IE11 ไม่สนับสนุนการสืบค้นข้อมูลคุณลักษณะ และเราใช้คุณสมบัติที่กำหนดเองอย่างกว้างขวางเพื่อให้แสดงสไตล์ชีตที่แตกต่างกันได้ในกรณีนี้
การแสดงสไตล์ชีตอื่นอย่างชาญฉลาดและการหลีกเลี่ยงเนื้อหาที่ไม่ได้จัดสไตล์อย่างรวดเร็วไม่ใช่เรื่องง่าย หากคุณไม่ต้องการคุณสมบัติไดนามิกของคุณสมบัติแบบกำหนดเอง คุณสามารถพิจารณาให้บริการเบราว์เซอร์ styles.no-vars.css
และใช้คุณสมบัติแบบกำหนดเองเป็นเครื่องมือในการพัฒนา
หากคุณต้องการใช้ประโยชน์อย่างเต็มที่จากคุณลักษณะไดนามิกทั้งหมดของคุณสมบัติที่กำหนดเอง ฉันขอแนะนำให้ใช้เทคนิค CSS ที่สำคัญ ตามเทคนิคเหล่านี้ สไตล์ชีตหลักจะถูกโหลดแบบอะซิงโครนัสในขณะที่ CSS ที่สำคัญแสดงผลแบบอินไลน์ ส่วนหัวของเพจอาจมีลักษณะดังนี้:
<head> <style> /* inlined critical CSS */ </style> <script> loadCSS('non-critical.css'); </script> </head>
เราสามารถขยายให้โหลดได้ทั้ง styles.css
หรือ styles.no-vars.css
ขึ้นอยู่กับว่าเบราว์เซอร์รองรับคุณสมบัติที่กำหนดเองหรือไม่ เราสามารถตรวจพบการสนับสนุนเช่นนี้:
if ( window.CSS && CSS.supports('color', 'var(--test)') ) { loadCSS('styles.css'); } else { loadCSS('styles.no-vars.css'); }
บทสรุป
หากคุณประสบปัญหาในการจัดระเบียบ CSS อย่างมีประสิทธิภาพ มีปัญหากับส่วนประกอบที่ตอบสนอง ต้องการใช้ชุดรูปแบบฝั่งไคลเอ็นต์ หรือเพียงแค่ต้องการเริ่มต้นอย่างถูกวิธีด้วยคุณสมบัติที่กำหนดเอง คู่มือนี้จะบอกคุณทุกสิ่งที่คุณจำเป็นต้องรู้
เป็นการทำความเข้าใจความแตกต่างระหว่างตัวแปรไดนามิกและสแตติกใน CSS รวมถึงกฎง่ายๆ สองสามข้อ:
- แยกตรรกะออกจากการออกแบบ
- หากคุณสมบัติ CSS เปลี่ยนไป ให้พิจารณาใช้คุณสมบัติที่กำหนดเอง
- เปลี่ยนค่าของคุณสมบัติแบบกำหนดเอง ไม่ใช่คุณสมบัติแบบกำหนดเองที่ใช้
- ตัวแปรส่วนกลางมักจะเป็นแบบคงที่
If you follow these conventions, you will find that working with custom properties is a whole lot easier than you think. This might even change how you approach CSS in general.
อ่านเพิ่มเติม
- “It's Time To Start Using Custom Properties,” Serg Hospodarets
A general introduction to the syntax and the features of custom properties. - “Pragmatic, Practical, And Progressive Theming With Custom Properties,” Harry Roberts
More useful information on theming. - Custom Properties Collection, Mike Riethmuller on CodePen
A number of different examples you can experiment with.