ได้เวลาเริ่มใช้ CSS Custom Properties แล้ว

เผยแพร่แล้ว: 2022-03-10
สรุปอย่างรวดเร็ว ↬ ปัจจุบัน CSS พรีโปรเซสเซอร์เป็นมาตรฐานสำหรับการพัฒนาเว็บ ข้อดีหลักประการหนึ่งของพรีโปรเซสเซอร์คือช่วยให้คุณใช้ตัวแปรได้ วิธีนี้ช่วยให้คุณหลีกเลี่ยงการคัดลอกและวางโค้ด และทำให้การพัฒนาและการจัดโครงสร้างใหม่ง่ายขึ้น

เราใช้ตัวประมวลผลล่วงหน้าในการจัดเก็บสี การกำหนดลักษณะแบบอักษร รายละเอียดเลย์เอาต์ ซึ่งส่วนใหญ่เป็นทุกอย่างที่เราใช้ใน CSS

บทนำโดยละเอียดเกี่ยวกับองค์ประกอบที่กำหนดเอง

คุณคงเคยได้ยินเกี่ยวกับ Web Components และวิธีที่พวกเขาจะเปลี่ยนแปลงการพัฒนาเว็บตลอดไป เทคโนโลยีที่เปลี่ยนแปลงได้มากที่สุดคือองค์ประกอบที่กำหนดเอง ซึ่งเป็นวิธีการกำหนดองค์ประกอบของคุณเองด้วยลักษณะการทำงานและคุณสมบัติของตนเอง อ่านบทนำ →

แต่ตัวแปรพรีโปรเซสเซอร์มีข้อจำกัดบางประการ:

  • คุณไม่สามารถเปลี่ยนแปลงไดนามิกได้
  • พวกเขาไม่ทราบถึงโครงสร้างของ DOM
  • ไม่สามารถอ่านหรือเปลี่ยนจาก JavaScript

ในฐานะที่เป็นสัญลักษณ์แสดงหัวข้อย่อยสีเงินสำหรับปัญหาเหล่านี้และปัญหาอื่นๆ ชุมชนได้คิดค้นคุณสมบัติที่กำหนดเองของ CSS โดยพื้นฐานแล้ว รูปลักษณ์และการทำงานเหล่านี้เหมือนกับตัวแปร CSS และวิธีการทำงานของมันสะท้อนอยู่ในชื่อของพวกเขา

คุณสมบัติที่กำหนดเองกำลังเปิดโลกทัศน์ใหม่สำหรับการพัฒนาเว็บ

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

ไวยากรณ์ในการประกาศและใช้คุณสมบัติที่กำหนดเอง

ปัญหาปกติเมื่อคุณเริ่มต้นด้วยตัวประมวลผลล่วงหน้าหรือเฟรมเวิร์กใหม่คือ คุณต้องเรียนรู้ไวยากรณ์ใหม่

ตัวประมวลผลล่วงหน้าแต่ละตัวต้องการวิธีการประกาศตัวแปรที่แตกต่างกัน โดยปกติ จะเริ่มต้นด้วยสัญลักษณ์สงวนไว้ ตัวอย่างเช่น $ ใน Sass และ @ ใน LESS

คุณสมบัติที่กำหนดเองของ CSS เป็นไปในลักษณะเดียวกันและใช้ใน -​- แนะนำการประกาศ แต่ข้อดีของที่นี่คือ คุณสามารถเรียนรู้ไวยากรณ์นี้ได้เพียงครั้งเดียวและนำมาใช้ซ้ำในเบราว์เซอร์ต่างๆ!

คุณอาจถามว่า “ทำไมไม่นำไวยากรณ์ที่มีอยู่มาใช้ใหม่”

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

(เกี่ยวกับชื่อ: เนื่องจากแนวคิดและวัตถุประสงค์คล้ายกันมาก บางครั้งคุณสมบัติที่กำหนดเองจึงเรียกว่าตัวแปร CSS แม้ว่าชื่อที่ถูกต้องคือคุณสมบัติที่กำหนดเองของ CSS และอ่านเพิ่มเติม คุณจะเข้าใจว่าทำไมชื่อนี้จึงอธิบายได้ดีที่สุด)

ดังนั้น หากต้องการประกาศตัวแปรแทนคุณสมบัติ CSS ปกติ เช่น color หรือ padding เพียงระบุคุณสมบัติที่กำหนดเองที่ขึ้นต้นด้วย -​- :

 .box{ --box-color: #4d4e53; --box-padding: 0 10px; }

ค่าของคุณสมบัติอาจเป็นค่า CSS ที่ถูกต้อง ไม่ว่าจะเป็นสี สตริง ค่าเลย์เอาต์ แม้แต่นิพจน์

ต่อไปนี้คือตัวอย่างคุณสมบัติที่กำหนดเองที่ถูกต้อง:

 :root{ --main-color: #4d4e53; --main-bg: rgb(255, 255, 255); --logo-border-color: rebeccapurple; --header-height: 68px; --content-padding: 10px 20px; --base-line-height: 1.428571429; --transition-duration: .35s; --external-link: "external link"; --margin-top: calc(2vh + 20px); /* Valid CSS custom properties can be reused later in, say, JavaScript. */ --foo: if(x > 5) this.width = 10; }

ในกรณีที่คุณไม่แน่ใจว่า :root ตรงกันหรือไม่ ใน HTML จะเหมือนกับ html แต่มีความจำเพาะสูงกว่า

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

ในการใช้ตัวแปร คุณต้องใช้ฟังก์ชัน var() CSS และระบุชื่อของคุณสมบัติภายใน:

 .box{ --box-color:#4d4e53; --box-padding: 0 10px; padding: var(--box-padding); } .box div{ color: var(--box-color); }

คำประกาศและกรณีการใช้งาน

ฟังก์ชัน var() เป็นวิธีที่สะดวกในการระบุค่าเริ่มต้น คุณอาจทำเช่นนี้ได้หากคุณไม่แน่ใจว่ามีการกำหนดคุณสมบัติแบบกำหนดเองหรือไม่ และต้องการระบุค่าเพื่อใช้เป็นทางเลือก สามารถทำได้ง่าย ๆ โดยส่งพารามิเตอร์ที่สองไปยังฟังก์ชัน:

 .box{ --box-color:#4d4e53; --box-padding: 0 10px; /* 10px is used because --box-margin is not defined. */ margin: var(--box-margin, 10px); }

อย่างที่คุณคาดไว้ คุณสามารถใช้ตัวแปรอื่นซ้ำเพื่อประกาศตัวแปรใหม่ได้:

 .box{ /* The --main-padding variable is used if --box-padding is not defined. */ padding: var(--box-padding, var(--main-padding)); --box-text: 'This is my box'; /* Equal to --box-highlight-text:'This is my box with highlight'; */ --box-highlight-text: var(--box-text)' with highlight'; }

ปฏิบัติการ: +, -, *, /

เมื่อเราคุ้นเคยกับตัวประมวลผลล่วงหน้าและภาษาอื่นๆ เราต้องการใช้ตัวดำเนินการพื้นฐานเมื่อทำงานกับตัวแปร สำหรับสิ่งนี้ CSS มีฟังก์ชัน calc() ซึ่งทำให้เบราว์เซอร์คำนวณนิพจน์ใหม่หลังจากทำการเปลี่ยนแปลงใดๆ กับค่าของคุณสมบัติที่กำหนดเอง:

 :root{ --indent-size: 10px; --indent-xl: calc(2*var(--indent-size)); --indent-l: calc(var(--indent-size) + 2px); --indent-s: calc(var(--indent-size) - 2px); --indent-xs: calc(var(--indent-size)/2); }

ปัญหารออยู่หากคุณพยายามใช้ค่าที่น้อยกว่าหน่วย อีกครั้ง calc() เป็นเพื่อนของคุณเพราะถ้าไม่มีมันจะไม่ทำงาน:

 :root{ --spacer: 10; } .box{ padding: var(--spacer)px 0; /* DOESN'T work */ padding: calc(var(--spacer)*1px) 0; /* WORKS */ }

ขอบเขตและมรดก

ก่อนพูดถึงขอบเขตคุณสมบัติที่กำหนดเองของ CSS ให้เรียกคืนขอบเขตของ JavaScript และตัวประมวลผลล่วงหน้า เพื่อให้เข้าใจความแตกต่างได้ดีขึ้น

เรารู้ว่า ตัวอย่างเช่น ตัวแปร JavaScript ( var ) ขอบเขตจำกัดอยู่ที่ฟังก์ชันเท่านั้น

เรามีสถานการณ์ที่คล้ายกันกับ let และ const แต่เป็นตัวแปรโลคัลขอบเขตบล็อก

การ closure ใน JavaScript เป็นฟังก์ชันที่สามารถเข้าถึงตัวแปรของฟังก์ชันภายนอก (ล้อมรอบ) — ขอบเขตลูกโซ่ การปิดมีสามขอบเขตโซ่ และสามารถเข้าถึงสิ่งต่อไปนี้:

  • ขอบเขตของมันเอง (เช่น ตัวแปรที่กำหนดระหว่างวงเล็บปีกกา)
  • ตัวแปรของฟังก์ชันภายนอก
  • ตัวแปรทั่วโลก

(ดูรุ่นใหญ่)

เรื่องราวที่มีตัวประมวลผลล่วงหน้านั้นคล้ายคลึงกัน ลองใช้ Sass เป็นตัวอย่างเพราะอาจเป็นตัวประมวลผลล่วงหน้าที่ได้รับความนิยมมากที่สุดในปัจจุบัน

ด้วย Sass เรามีตัวแปรสองประเภท: โลคัลและโกลบอล

ตัวแปรส่วนกลางสามารถประกาศได้นอกตัวเลือกหรือโครงสร้างใดๆ (เช่น เป็นมิกซ์อิน) มิฉะนั้น ตัวแปรจะเป็นแบบโลคัล

บล็อกโค้ดที่ซ้อนกันสามารถเข้าถึงตัวแปรที่ล้อมรอบได้ (เช่นใน JavaScript)

(ดูรุ่นใหญ่)

ซึ่งหมายความว่าใน Sass ขอบเขตของตัวแปรจะขึ้นอยู่กับโครงสร้างของโค้ด

อย่างไรก็ตาม คุณสมบัติที่กำหนดเองของ CSS นั้นสืบทอดมาโดยค่าเริ่มต้น และเหมือนกับคุณสมบัติ CSS อื่นๆ พวกมันเรียงต่อกัน

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

ลองใช้ความรู้ทางไวยากรณ์ของเราและปรับตัวอย่าง Sass ให้เป็น HTML และ CSS เราจะสร้างการสาธิตโดยใช้คุณสมบัติที่กำหนดเองของ CSS ดั้งเดิม ขั้นแรก HTML:

 global <div class="enclosing"> enclosing <div class="closure"> closure </div> </div>

และนี่คือ CSS:

 :root { --globalVar: 10px; } .enclosing { --enclosingVar: 20px; } .enclosing .closure { --closureVar: 30px; font-size: calc(var(--closureVar) + var(--enclosingVar) + var(--globalVar)); /* 60px for now */ } 

ดู Pen css-custom-properties-time-to-start-using 1 โดย Serg Hospodarets (@malyw) บน CodePen

ดู Pen css-custom-properties-time-to-start-using 1 โดย Serg Hospodarets (@malyw) บน CodePen

การเปลี่ยนแปลงคุณสมบัติที่กำหนดเองจะมีผลกับอินสแตนซ์ทั้งหมดทันที

จนถึงตอนนี้ เรายังไม่เห็นความแตกต่างจากตัวแปร Sass เลย อย่างไรก็ตาม มากำหนดตัวแปรใหม่หลังจากใช้งาน:

ในกรณีของ Sass สิ่งนี้ไม่มีผล:

 .closure { $closureVar: 30px; // local variable font-size: $closureVar +$enclosingVar+ $globalVar; // 60px, $closureVar: 30px is used $closureVar: 50px; // local variable } 

ดู Pen css-custom-properties-time-to-start-using 3 โดย Serg Hospodarets (@malyw) บน CodePen

ดู Pen css-custom-properties-time-to-start-using 3 โดย Serg Hospodarets (@malyw) บน CodePen

แต่ใน CSS ค่าที่คำนวณได้จะเปลี่ยนไป เนื่องจากค่า font-size ถูกคำนวณใหม่จากค่า –closureVar ที่เปลี่ยนแปลง:

 .enclosing .closure { --closureVar: 30px; font-size: calc(var(--closureVar) + var(--enclosingVar) + var(--globalVar)); /* 80px for now, --closureVar: 50px is used */ --closureVar: 50px; } 

ดู Pen css-custom-properties-time-to-start-using 2 โดย Serg Hospodarets (@malyw) บน CodePen

ดู Pen css-custom-properties-time-to-start-using 2 โดย Serg Hospodarets (@malyw) บน CodePen

นั่นคือความแตกต่างใหญ่ประการแรก: หากคุณกำหนดค่าคุณสมบัติที่กำหนดเองใหม่ เบราว์เซอร์จะ คำนวณตัวแปรและนิพจน์ calc() ทั้งหมด เมื่อมีการใช้

ตัวประมวลผลล่วงหน้าไม่ทราบโครงสร้างของ DOM

สมมติว่าเราต้องการใช้ font-size เริ่มต้นสำหรับบล็อก ยกเว้นว่ามีคลาสที่ highlighted อยู่

นี่คือ HTML:

 <div class="default"> default </div> <div class="default highlighted"> default highlighted </div>

ลองทำสิ่งนี้โดยใช้คุณสมบัติที่กำหนดเอง CSS:

 .highlighted { --highlighted-size: 30px; } .default { --default-size: 10px; /* Use default-size, except when highlighted-size is provided. */ font-size: var(--highlighted-size, var(--default-size)); }

เนื่องจากองค์ประกอบ HTML ที่สองที่มีคลาส default มีคลาสที่ highlighted คุณสมบัติจากคลาสที่ highlighted จะถูกนำไปใช้กับองค์ประกอบนั้น

ในกรณีนี้หมายความว่า –highlighted-size: 30px; จะถูกนำไปใช้ซึ่งจะทำให้คุณสมบัติ font-size ที่กำหนดใช้ –highlighted-size

ทุกอย่างตรงไปตรงมาและได้ผล:

ดู Pen css-custom-properties-time-to-start-using 4 โดย Serg Hospodarets (@malyw) บน CodePen

ดู Pen css-custom-properties-time-to-start-using 4 โดย Serg Hospodarets (@malyw) บน CodePen

ตอนนี้ มาพยายามทำสิ่งเดียวกันให้สำเร็จโดยใช้ Sass:

 .highlighted { $highlighted-size: 30px; } .default { $default-size: 10px; /* Use default-size, except when highlighted-size is provided. */ @if variable-exists(highlighted-size) { font-size: $highlighted-size; } @else { font-size: $default-size; } }

ผลลัพธ์แสดงว่าขนาดเริ่มต้นถูกนำไปใช้กับทั้งสอง:

ดู Pen css-custom-properties-time-to-start-using 5 โดย Serg Hospodarets (@malyw) บน CodePen

ดู Pen css-custom-properties-time-to-start-using 5 โดย Serg Hospodarets (@malyw) บน CodePen

สิ่งนี้เกิดขึ้นเนื่องจากการคำนวณและการประมวลผล Sass ทั้งหมดเกิดขึ้นในเวลารวบรวม และแน่นอน มันไม่รู้อะไรเกี่ยวกับโครงสร้างของ DOM โดยอาศัยโครงสร้างของโค้ดทั้งหมด

อย่างที่คุณเห็น คุณสมบัติที่กำหนดเองมีข้อดีของการกำหนดขอบเขตตัวแปร และเพิ่มการเรียงซ้อนคุณสมบัติ CSS ตามปกติ โดยคำนึงถึงโครงสร้างของ DOM และปฏิบัติตามกฎเดียวกันกับคุณสมบัติ CSS อื่นๆ

ประเด็นที่สองคือคุณสมบัติที่กำหนดเองของ CSS รับ รู้โครงสร้างของ DOM และเป็นไดนามิก

คำหลักแบบกว้าง CSS และคุณสมบัติ all

คุณสมบัติที่กำหนดเอง CSS อยู่ภายใต้กฎเดียวกันกับคุณสมบัติที่กำหนดเอง CSS ปกติ ซึ่งหมายความว่าคุณสามารถกำหนดคีย์เวิร์ด CSS ทั่วไปให้กับคีย์เวิร์ดเหล่านี้ได้:

  • inherit
    คีย์เวิร์ด CSS นี้ใช้ค่าของพาเรนต์ขององค์ประกอบ
  • initial
    สิ่งนี้ใช้ค่าเริ่มต้นตามที่กำหนดไว้ในข้อกำหนด CSS (ค่าว่างหรือไม่มีเลยในบางกรณีของคุณสมบัติกำหนดเอง CSS)
  • unset
    ค่านี้จะใช้ค่าที่สืบทอดมาหากโดยปกติคุณสมบัติได้รับการสืบทอด (เช่นในกรณีของคุณสมบัติแบบกำหนดเอง) หรือค่าเริ่มต้นหากคุณสมบัตินั้นโดยปกติไม่ได้รับการสืบทอด
  • revert
    สิ่งนี้จะรีเซ็ตคุณสมบัติเป็นค่าเริ่มต้นที่กำหนดโดยสไตล์ชีตของตัวแทนผู้ใช้ (ค่าว่างในกรณีของคุณสมบัติกำหนดเอง CSS)

นี่คือตัวอย่าง:

 .common-values{ --border: inherit; --bgcolor: initial; --padding: unset; --animation: revert; }

ลองพิจารณาอีกกรณีหนึ่ง สมมติว่าคุณต้องการสร้างส่วนประกอบและต้องการให้แน่ใจว่าไม่มีการใช้สไตล์หรือคุณสมบัติที่กำหนดเองอื่นกับมันโดยไม่ได้ตั้งใจ (ปกติแล้วโซลูชัน CSS แบบแยกส่วนมักจะใช้สำหรับสไตล์ในกรณีดังกล่าว)

แต่ตอนนี้ มีอีกวิธีหนึ่งคือ ใช้คุณสมบัติ CSS all ชวเลขนี้จะรีเซ็ตคุณสมบัติ CSS ทั้งหมด

ร่วมกับคำหลัก CSS เราสามารถทำสิ่งต่อไปนี้:

 .my-wonderful-clean-component{ all: initial; }

สิ่งนี้จะรีเซ็ตสไตล์ทั้งหมดสำหรับองค์ประกอบของเรา

ขออภัย คำหลัก all ไม่ได้รีเซ็ตคุณสมบัติที่กำหนดเอง มีการอภิปรายอย่างต่อเนื่องเกี่ยวกับการเพิ่ม -​- นำหน้า ซึ่งจะรีเซ็ตคุณสมบัติที่กำหนดเอง CSS ทั้งหมด

ดังนั้น ในอนาคต การรีเซ็ตแบบเต็มอาจทำได้ดังนี้:

 .my-wonderful-clean-component{ --: initial; /* reset all CSS custom properties */ all: initial; /* reset all other CSS styles */ }

คุณสมบัติที่กำหนดเอง CSS ใช้กรณี

คุณสมบัติที่กำหนดเองมีประโยชน์หลายอย่าง ฉันจะแสดงสิ่งที่น่าสนใจที่สุดของพวกเขา

จำลองกฎ CSS ที่ไม่มีอยู่จริง

ชื่อของตัวแปร CSS เหล่านี้คือ "คุณสมบัติที่กำหนดเอง" เหตุใดจึงไม่ใช้ตัวแปรเหล่านี้เพื่อจำลองคุณสมบัติที่ไม่มีอยู่จริง

มีหลายอย่าง: translateX/Y/Z , background-repeat-x/y (ยังไม่รองรับการข้ามเบราว์เซอร์) box-shadow-color

มาลองทำอันสุดท้ายกัน ในตัวอย่างของเรา เรามาเปลี่ยนสีกล่องเงาเมื่อโฮเวอร์ เราแค่ต้องการทำตามกฎ DRY (อย่าทำซ้ำตัวเอง) ดังนั้นแทนที่จะทำซ้ำค่าทั้งหมดของ box-shadow ในส่วน :hover เราจะเปลี่ยนสีของมัน คุณสมบัติที่กำหนดเองเพื่อช่วยเหลือ:

 .test { --box-shadow-color: yellow; box-shadow: 0 0 30px var(--box-shadow-color); } .test:hover { --box-shadow-color: orange; /* Instead of: box-shadow: 0 0 30px orange; */ } 

ดูคุณสมบัติ CSS "box-shadow-color" CSS ที่เลียนแบบปากกาโดยใช้คุณสมบัติกำหนดเอง CSS โดย Serg Hospodarets (@malyw) บน CodePen

ดูคุณสมบัติ CSS "box-shadow-color" ที่เลียนแบบปากกาโดยใช้คุณสมบัติกำหนดเอง CSS โดย Serg Hospodarets (@malyw) บน CodePen

ธีมสี

กรณีการใช้งานทั่วไปของคุณสมบัติแบบกำหนดเองอย่างหนึ่งคือสำหรับธีมสีในแอปพลิเคชัน คุณสมบัติที่กำหนดเองถูกสร้างขึ้นเพื่อแก้ปัญหาประเภทนี้ ดังนั้น ให้กำหนดธีมสีอย่างง่ายสำหรับส่วนประกอบ (สามารถทำตามขั้นตอนเดียวกันสำหรับแอปพลิเคชัน)

นี่คือรหัสสำหรับองค์ประกอบปุ่มของเรา:

 .btn { background-image: linear-gradient(to bottom, #3498db, #2980b9); text-shadow: 1px 1px 3px #777; box-shadow: 0px 1px 3px #777; border-radius: 28px; color: #ffffff; padding: 10px 20px 10px 20px; }

สมมติว่าเราต้องการกลับธีมสี

ขั้นตอนแรกคือการขยายตัวแปรสีทั้งหมดไปยังคุณสมบัติที่กำหนดเองของ CSS และเขียนองค์ประกอบของเราใหม่ ดังนั้นผลลัพธ์จะเหมือนกัน:

 .btn { --shadow-color: #777; --gradient-from-color: #3498db; --gradient-to-color: #2980b9; --color: #ffffff; background-image: linear-gradient( to bottom, var(--gradient-from-color), var(--gradient-to-color) ); text-shadow: 1px 1px 3px var(--shadow-color); box-shadow: 0px 1px 3px var(--shadow-color); border-radius: 28px; color: var(--color); padding: 10px 20px 10px 20px; }

มีทุกอย่างที่เราต้องการ ด้วยสิ่งนี้ เราสามารถแทนที่ตัวแปรสีให้เป็นค่าที่กลับด้านและนำไปใช้เมื่อจำเป็น ตัวอย่างเช่น เราอาจเพิ่มคลาส HTML inverted (เป็น องค์ประกอบ body ) และเปลี่ยนสีเมื่อนำไปใช้:

 body.inverted .btn{ --shadow-color: #888888; --gradient-from-color: #CB6724; --gradient-to-color: #D67F46; --color: #000000; }

ด้านล่างนี้เป็นการสาธิตที่คุณสามารถคลิกปุ่มเพื่อเพิ่มและลบคลาสสากล:

ดูปากกา css-custom-properties-time-to-start-using 9 โดย Serg Hospodarets (@malyw) บน CodePen

ดูปากกา css-custom-properties-time-to-start-using 9 โดย Serg Hospodarets (@malyw) บน CodePen

ลักษณะการทำงานนี้ไม่สามารถทำได้ในตัวประมวลผลล่วงหน้า CSS โดยไม่มีโอเวอร์เฮดของโค้ดที่ซ้ำกัน ด้วยตัวประมวลผลล่วงหน้า คุณจะต้องแทนที่ค่าและกฎจริงเสมอ ซึ่งส่งผลให้มี CSS เพิ่มเติมเสมอ

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

การใช้คุณสมบัติที่กำหนดเองด้วย JavaScript

ก่อนหน้านี้ ในการส่งข้อมูลจาก CSS ไปยัง JavaScript เรามักต้องใช้อุบาย เขียนค่า CSS ผ่าน JSON ธรรมดาในเอาต์พุต CSS แล้วอ่านจาก JavaScript

ตอนนี้ เราสามารถโต้ตอบกับตัวแปร CSS จาก JavaScript ได้อย่างง่ายดาย การอ่านและเขียนถึงตัวแปรเหล่านี้โดยใช้ .getPropertyValue() และ .setProperty() ที่เป็นที่รู้จัก ซึ่งใช้สำหรับคุณสมบัติ CSS ปกติ:

 /** * Gives a CSS custom property value applied at the element * element {Element} * varName {String} without '--' * * For example: * readCssVar(document.querySelector('.box'), 'color'); */ function readCssVar(element, varName){ const elementStyles = getComputedStyle(element); return elementStyles.getPropertyValue(`--${varName}`).trim(); } /** * Writes a CSS custom property value at the element * element {Element} * varName {String} without '--' * * For example: * readCssVar(document.querySelector('.box'), 'color', 'white'); */ function writeCssVar(element, varName, value){ return element.style.setProperty(`--${varName}`, value); }

สมมติว่าเรามีรายการค่าการสืบค้นสื่อ:

 .breakpoints-data { --phone: 480px; --tablet: 800px; }

เนื่องจากเราต้องการใช้ซ้ำใน JavaScript เท่านั้น ตัวอย่างเช่นใน Window.matchMedia() เราสามารถรับจาก CSS ได้อย่างง่ายดาย:

 const breakpointsData = document.querySelector('.breakpoints-data'); // GET const phoneBreakpoint = getComputedStyle(breakpointsData) .getPropertyValue('--phone');

เพื่อแสดงวิธีกำหนดคุณสมบัติที่กำหนดเองจาก JavaScript ฉันได้สร้างการสาธิตคิวบ์ 3D CSS แบบโต้ตอบที่ตอบสนองต่อการกระทำของผู้ใช้

ไม่ยากเลย เราแค่ต้องเพิ่มพื้นหลังที่เรียบง่าย แล้ววางลูกบาศก์ห้าหน้าด้วยค่าที่เกี่ยวข้องสำหรับคุณสมบัติการ transform : translateZ() , translateY() , rotateX() และ rotateY()

เพื่อให้มีมุมมองที่ถูกต้อง ฉันได้เพิ่มสิ่งต่อไปนี้ลงในตัวตัดทอนหน้า:

 #world{ --translateZ:0; --rotateX:65; --rotateY:0; transform-style:preserve-3d; transform: translateZ(calc(var(--translateZ) * 1px)) rotateX(calc(var(--rotateX) * 1deg)) rotateY(calc(var(--rotateY) * 1deg)); }

สิ่งเดียวที่ขาดหายไปคือการโต้ตอบ การสาธิตควรเปลี่ยนมุมมอง X และ Y ( –rotateX และ –rotateY ) เมื่อเมาส์เคลื่อนที่และควรซูมเข้าและออกเมื่อเลื่อนเมาส์ ( –translateZ )

นี่คือ JavaScript ที่ทำเคล็ดลับ:

 // Events onMouseMove(e) { this.worldXAngle = (.5 - (e.clientY / window.innerHeight)) * 180; this.worldYAngle = -(.5 - (e.clientX / window.innerWidth)) * 180; this.updateView(); }; onMouseWheel(e) { /*…*/ this.worldZ += delta * 5; this.updateView(); }; // JavaScript -> CSS updateView() { this.worldEl.style.setProperty('--translateZ', this.worldZ); this.worldEl.style.setProperty('--rotateX', this.worldXAngle); this.worldEl.style.setProperty('--rotateY', this.worldYAngle); };

ตอนนี้ เมื่อผู้ใช้เลื่อนเมาส์ การสาธิตจะเปลี่ยนมุมมอง คุณสามารถตรวจสอบได้โดยเลื่อนเมาส์และใช้ล้อเลื่อนของเมาส์เพื่อซูมเข้าและออก:

ดู Pen css-custom-properties-time-to-start-using 10 โดย Serg Hospodarets (@malyw) บน CodePen

ดู Pen css-custom-properties-time-to-start-using 10 โดย Serg Hospodarets (@malyw) บน CodePen

โดยพื้นฐานแล้ว เราเพิ่งเปลี่ยนค่าคุณสมบัติที่กำหนดเองของ CSS อย่างอื่น (การหมุนและการซูมเข้าและออก) ทำได้โดย CSS

เคล็ดลับ: วิธีที่ง่ายที่สุดวิธีหนึ่งในการดีบักค่าคุณสมบัติที่กำหนดเองของ CSS คือการแสดงเนื้อหาในเนื้อหาที่สร้างโดย CSS (ซึ่งใช้ได้ในกรณีทั่วไป เช่น กับสตริง) เพื่อให้เบราว์เซอร์แสดงค่าที่ใช้ในปัจจุบันโดยอัตโนมัติ:

 body:after { content: '--screen-category : 'var(--screen-category); }

คุณสามารถตรวจสอบได้ในการสาธิต CSS ธรรมดา (ไม่มี HTML หรือ JavaScript) (ปรับขนาดหน้าต่างเพื่อดูเบราว์เซอร์สะท้อนถึงค่าคุณสมบัติที่กำหนดเอง CSS ที่เปลี่ยนแปลงโดยอัตโนมัติ)

รองรับเบราว์เซอร์

คุณสมบัติที่กำหนดเอง CSS ได้รับการสนับสนุนในเบราว์เซอร์หลักทั้งหมด:

(ดูรุ่นใหญ่)

ซึ่งหมายความว่าคุณสามารถเริ่มใช้งานได้โดยกำเนิด

หากคุณต้องการสนับสนุนเบราว์เซอร์รุ่นเก่า คุณสามารถเรียนรู้ไวยากรณ์และตัวอย่างการใช้งาน และพิจารณาวิธีที่เป็นไปได้ในการสลับหรือใช้ตัวแปร CSS และตัวประมวลผลล่วงหน้าพร้อมกัน

แน่นอน เราต้องสามารถตรวจพบการสนับสนุนทั้งใน CSS และ JavaScript เพื่อจัดเตรียมทางเลือกหรือการปรับปรุง

นี้ค่อนข้างง่าย สำหรับ CSS คุณสามารถใช้เงื่อนไข @supports กับแบบสอบถามคุณลักษณะจำลอง:

 @supports ( (--a: 0)) { /* supported */ } @supports ( not (--a: 0)) { /* not supported */ }

ใน JavaScript คุณสามารถใช้คุณสมบัติที่กำหนดเองจำลองเดียวกันกับ CSS.supports() วิธีการคงที่:

 const isSupported = window.CSS && window.CSS.supports && window.CSS.supports('--a', 0); if (isSupported) { /* supported */ } else { /* not supported */ }

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

ตัวอย่างเช่น คุณสามารถสร้างไฟล์ CSS หลักสองไฟล์: ไฟล์หนึ่งมีคุณสมบัติที่กำหนดเองของ CSS และไฟล์ที่สองที่ไม่มีไฟล์นั้น ซึ่งคุณสมบัติต่างๆ จะอยู่ในแนวเดียวกัน (เราจะพูดถึงวิธีการดำเนินการนี้ในเร็วๆ นี้)

โหลดอันที่สองโดยปริยาย จากนั้น ให้ตรวจสอบใน JavaScript และเปลี่ยนเป็นเวอร์ชันที่ปรับปรุงแล้ว หากรองรับคุณสมบัติที่กำหนดเอง:

 <!-- HTML --> <link href="without-css-custom-properties.css" rel="stylesheet" type="text/css" media="all" />
 // JavaScript if(isSupported){ removeCss('without-css-custom-properties.css'); loadCss('css-custom-properties.css'); // + conditionally apply some application enhancements // using the custom properties }

นี่เป็นเพียงตัวอย่าง ดังที่คุณเห็นด้านล่าง มีตัวเลือกที่ดีกว่า

วิธีเริ่มใช้งาน

จากการสำรวจเมื่อเร็ว ๆ นี้ Sass ยังคงเป็นตัวเลือกตัวประมวลผลล่วงหน้าสำหรับชุมชนการพัฒนา

ลองพิจารณาวิธีเริ่มใช้คุณสมบัติที่กำหนดเองของ CSS หรือเตรียมรับคุณสมบัติเหล่านี้โดยใช้ Sass

เรามีทางเลือกไม่กี่ทาง

1. ตรวจสอบรหัสสำหรับการสนับสนุนด้วยตนเอง

ข้อดีอย่างหนึ่งของวิธีการตรวจสอบโค้ดด้วยตนเองนี้ว่ารองรับคุณสมบัติที่กำหนดเองหรือไม่ คือใช้งานได้และเราสามารถทำได้ทันที (อย่าลืมว่าเราได้เปลี่ยนมาใช้ Sass):

 $color: red; :root { --color: red; } .box { @supports ( (--a: 0)) { color: var(--color); } @supports ( not (--a: 0)) { color: $color; } }

วิธีการนี้มีข้อเสียหลายประการ อย่างน้อยก็คือโค้ดมีความซับซ้อน และการคัดลอกและวางก็ค่อนข้างยากที่จะรักษา

2. ใช้ปลั๊กอินที่ประมวลผล CSS ผลลัพธ์โดยอัตโนมัติ

ระบบนิเวศ PostCSS มีปลั๊กอินมากมายในปัจจุบัน สองสามตัวประมวลผลคุณสมบัติที่กำหนดเอง (ค่าอินไลน์) ในผลลัพธ์ CSS ที่เป็นผลลัพธ์และทำให้มันใช้งานได้ สมมติว่าคุณระบุตัวแปรส่วนกลางเท่านั้น (เช่น คุณประกาศหรือเปลี่ยนคุณสมบัติที่กำหนดเอง CSS ภายใน :root ตัวเลือก) ดังนั้นค่าของพวกมัน สามารถอินไลน์ได้ง่าย

ตัวอย่างคือ postcss-custom-properties

ปลั๊กอินนี้มีข้อดีหลายประการ: ทำให้ไวยากรณ์ใช้งานได้ มันเข้ากันได้กับโครงสร้างพื้นฐานของ PostCSS ทั้งหมด; และไม่ต้องการการกำหนดค่ามากนัก

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

3. css-vars Mixin

ฉันเริ่มใช้คุณสมบัติที่กำหนดเองของ CSS ในโครงการส่วนใหญ่ของฉันและได้ลองใช้กลยุทธ์ต่างๆ มากมาย:

  • เปลี่ยนจาก Sass เป็น PostCSS ด้วย cssnext
  • เปลี่ยนจากตัวแปร Sass เป็นคุณสมบัติที่กำหนดเองของ CSS ล้วนๆ
  • ใช้ตัวแปร CSS ใน Sass เพื่อตรวจสอบว่าได้รับการสนับสนุนหรือไม่

จากประสบการณ์นั้น ฉันเริ่มมองหาวิธีแก้ปัญหาที่ตรงตามเกณฑ์ของฉัน:

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

ด้วยเหตุนี้ ฉันจึงสร้าง css-vars ซึ่งเป็นมิกซ์อิน Sass ที่คุณสามารถหาได้ใน Github เมื่อใช้มัน คุณสามารถเรียงลำดับการเริ่มต้นโดยใช้รูปแบบ CSS แบบกำหนดเองได้

ใช้ css-vars Mixin

ในการประกาศตัวแปร ให้ใช้มิกซ์อินดังนี้:

 $white-color: #fff; $base-font-size: 10px; @include css-vars(( --main-color: #000, --main-bg: $white-color, --main-font-size: 1.5*$base-font-size, --padding-top: calc(2vh + 20px) ));

ในการใช้ตัวแปรเหล่านี้ ให้ใช้ฟังก์ชัน var() :

 body { color: var(--main-color); background: var(--main-bg, #f00); font-size: var(--main-font-size); padding: var(--padding-top) 0 10px; }

วิธีนี้ช่วยให้คุณควบคุมเอาต์พุต CSS ทั้งหมดได้จากที่เดียว (จาก Sass) และเริ่มทำความคุ้นเคยกับไวยากรณ์ นอกจากนี้ คุณยังสามารถนำตัวแปร Sass และตรรกะกลับมาใช้ใหม่ได้ด้วยมิกซ์อิน

เมื่อเบราว์เซอร์ทั้งหมดที่คุณต้องการสนับสนุนทำงานกับตัวแปร CSS สิ่งที่คุณต้องทำคือเพิ่มสิ่งนี้:

 $css-vars-use-native: true;

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

หากคุณต้องการเปิดข้อมูลการดีบักที่เป็นประโยชน์ ให้เพิ่มสิ่งต่อไปนี้:

 $css-vars-debug-log: true;

สิ่งนี้จะทำให้คุณ:

  • บันทึกเมื่อไม่ได้กำหนดตัวแปร แต่ถูกใช้
  • บันทึกเมื่อมีการกำหนดตัวแปรใหม่
  • ข้อมูลเมื่อไม่ได้กำหนดตัวแปรแต่มีการส่งต่อค่าดีฟอลต์ที่ใช้แทน

บทสรุป

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

คุณได้เรียนรู้วิธีตรวจสอบว่าได้รับการสนับสนุนหรือไม่ แตกต่างจากตัวแปรตัวประมวลผลล่วงหน้าของ CSS อย่างไร และวิธีเริ่มใช้ตัวแปร CSS ดั้งเดิมจนกว่าจะได้รับการสนับสนุนในเบราว์เซอร์ต่างๆ

นี่เป็นเวลาที่เหมาะสมในการเริ่มใช้คุณสมบัติที่กำหนดเองของ CSS และเพื่อเตรียมพร้อมสำหรับการสนับสนุนดั้งเดิมในเบราว์เซอร์