ตัวแปร CSS หรือที่เรียกอย่างถูกต้องว่าพร็อพเพอร์ตี้ที่กำหนดเองของ CSS จะพร้อมใช้งานใน Chrome 49 ซึ่งมีประโยชน์ในการลดการซ้ำใน CSS และเพื่อเอฟเฟกต์รันไทม์ที่มีประสิทธิภาพ เช่น การเปลี่ยนธีม และอาจขยาย/โพลีฟีลฟีเจอร์ CSS ในอนาคต
ความไม่เป็นระเบียบของ CSS
แนวทางปฏิบัติทั่วไปในการออกแบบแอปพลิเคชันมักจะไม่ใส่ชุดสีของแบรนด์ที่จะนำมาใช้ซ้ำเพื่อให้ภาพลักษณ์ของแอปสอดคล้องกัน การใช้ค่าสีเหล่านี้ซ้ำแล้วซ้ำอีกใน CSS ไม่เพียงเป็นงานที่น่าเบื่อ แต่ยังมีโอกาสเกิดข้อผิดพลาดอีกด้วย เมื่อถึงช่วงหนึ่งที่ต้องเปลี่ยนสีใดสีหนึ่ง คุณอาจระมัดระวังในเรื่องลมและ "ค้นหาและแทนที่" ทุกสิ่งได้ แต่ในโปรเจ็กต์ที่ใหญ่พอ อาจทำให้มีอันตรายได้ง่าย
ในช่วงหลังๆ นี้ นักพัฒนาซอฟต์แวร์จำนวนมากหันมาใช้โปรแกรมประมวลผลข้อมูล CSS เช่น SASS หรือ LESS ซึ่งแก้ปัญหานี้ได้โดยใช้ตัวแปรโปรแกรมประมวลผลข้อมูล แม้ว่าเครื่องมือเหล่านี้จะช่วยเพิ่มประสิทธิภาพของนักพัฒนาซอฟต์แวร์ได้เป็นอย่างมาก แต่ตัวแปรที่ใช้ก็มีข้อเสียที่สำคัญอย่างหนึ่งคือตัวแปรเป็นแบบคงที่และไม่สามารถเปลี่ยนแปลงขณะรันไทม์ได้ การเพิ่มความสามารถในการเปลี่ยนตัวแปรขณะรันไทม์ไม่เพียงเปิดประตูสู่สิ่งต่างๆ เช่น ธีมแอปพลิเคชันแบบไดนามิก แต่ยังทำให้เกิดผลลัพธ์หลักๆ สำหรับการออกแบบที่ปรับเปลี่ยนตามอุปกรณ์และศักยภาพในการใช้ฟีเจอร์ CSS ในอนาคตด้วย เมื่อมีการเปิดตัว Chrome 49 ความสามารถเหล่านี้พร้อมใช้งานในรูปแบบพร็อพเพอร์ตี้ที่กำหนดเองของ CSS แล้ว
พร็อพเพอร์ตี้ที่กำหนดเองโดยสรุป
พร็อพเพอร์ตี้ที่กำหนดเองได้เพิ่มฟีเจอร์ใหม่ 2 รายการลงในกล่องเครื่องมือ CSS ดังนี้
- ความสามารถในการกำหนดค่าที่กำหนดเองให้กับพร็อพเพอร์ตี้ที่มีชื่อที่ผู้เขียนเลือก
- ฟังก์ชัน
var()
ซึ่งช่วยให้ผู้เขียนใช้ค่าเหล่านี้ในพร็อพเพอร์ตี้อื่นๆ ได้
ต่อไปนี้เป็นตัวอย่างสั้นๆ ที่แสดงให้เห็น
:root {
--main-color: #06c;
}
#foo h1 {
color: var(--main-color);
}
--main-color
เป็นพร็อพเพอร์ตี้แบบกำหนดเองที่ผู้เขียนกำหนดซึ่งมีค่า #06c โปรดทราบว่าพร็อพเพอร์ตี้ที่กำหนดเองทั้งหมดจะขึ้นต้นด้วยขีด 2 ขีด
ฟังก์ชัน var()
จะดึงและแทนที่ตัวเองด้วยค่าพร็อพเพอร์ตี้ที่กำหนดเอง ซึ่งจะส่งผลเป็น color: #06c;
ตราบใดที่มีการระบุคุณสมบัติที่กำหนดเองที่ใดที่หนึ่งในสไตล์ชีตของคุณ พร็อพเพอร์ตี้ดังกล่าวควรพร้อมใช้งานในฟังก์ชัน var
ไวยากรณ์อาจดูแปลกๆ ไปหน่อยในตอนแรก นักพัฒนาแอปหลายคนถามว่า "ทำไมไม่ใช้ $foo
เป็นชื่อตัวแปรไปเลย" วิธีการนี้ได้รับการเลือกมาโดยเฉพาะเพื่อให้มีความยืดหยุ่นมากที่สุดและอาจรองรับมาโคร $foo
ในอนาคต
สำหรับเรื่องราวเบื้องหลัง โปรดอ่านโพสต์นี้
จากหนึ่งในผู้เขียนข้อกำหนดอย่าง Tab Atkins
ไวยากรณ์ของพร็อพเพอร์ตี้ที่กำหนดเอง
ไวยากรณ์สําหรับพร็อพเพอร์ตี้ที่กําหนดเองไม่ซับซ้อน
--header-color: #06c;
โปรดทราบว่าพร็อพเพอร์ตี้ที่กำหนดเองจะพิจารณาตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ ดังนั้น --header-color
และ --Header-Color
จึงเป็นพร็อพเพอร์ตี้ที่กำหนดเองที่ต่างกัน แม้ว่าจะดูเรียบง่ายในด้านมูลค่าใบหน้า แต่ไวยากรณ์ที่ใช้ได้สำหรับพร็อพเพอร์ตี้ที่กำหนดเองนั้นค่อนข้างอนุญาต ตัวอย่างเช่น พร็อพเพอร์ตี้ที่กำหนดเองที่ถูกต้องมีดังต่อไปนี้
--foo: if(x > 5) this.width = 10;
แม้ว่าอาจไม่มีประโยชน์ในการเป็นตัวแปร แต่เนื่องจากพร็อพเพอร์ตี้ทั่วไปอาจไม่ถูกต้อง แต่อาจอ่านและดำเนินการกับ JavaScript ได้ขณะรันไทม์ ซึ่งหมายความว่าพร็อพเพอร์ตี้ที่กำหนดเองมีศักยภาพที่จะปลดล็อกเทคนิคที่น่าสนใจทุกประเภทที่ปัจจุบันใช้กับเครื่องมือประมวลผล CSS ไม่ได้ ดังนั้น ถ้าคุณคิดว่า "หาว ฉันมี SASS แล้วใครจะสนใจ..." ก็มาดูอีกทีนะ สิ่งเหล่านี้ไม่ใช่ตัวแปรที่คุณคุ้นเคย
การแสดงผลตามลำดับขั้น
พร็อพเพอร์ตี้ที่กำหนดเองจะเป็นไปตามกฎการซ้อนทับมาตรฐาน คุณจึงกำหนดพร็อพเพอร์ตี้เดียวกันในระดับความเฉพาะเจาะจงที่แตกต่างกันได้
:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id="alert">
While I got red set directly on me!
<p>I’m red too, because of inheritance!</p>
</div>
ซึ่งหมายความว่าคุณสามารถใช้คุณสมบัติที่กำหนดเองภายในคำค้นหาสื่อเพื่อช่วยในการออกแบบที่ปรับเปลี่ยนตามอุปกรณ์ กรณีการใช้งานอย่างหนึ่งอาจเป็นการขยายระยะขอบรอบองค์ประกอบการแบ่งส่วนหลักเมื่อขนาดหน้าจอเพิ่มขึ้น
:root {
--gutter: 4px;
}
section {
margin: var(--gutter);
}
@media (min-width: 600px) {
:root {
--gutter: 16px;
}
}
สิ่งสำคัญที่ควรทราบคือ ข้อมูลโค้ดข้างต้นไม่สามารถใช้กับตัวประมวลผล CSS ล่วงหน้าแบบ CSS ในปัจจุบันซึ่งกำหนดตัวแปรภายในคำค้นหาสื่อไม่ได้ ความสามารถนี้จะช่วยปลดล็อกศักยภาพได้มากมาย
นอกจากนี้ คุณยังอาจมีพร็อพเพอร์ตี้ที่กำหนดเองซึ่งดึงค่ามาจากพร็อพเพอร์ตี้ที่กำหนดเองอื่นๆ ได้ด้วย ซึ่งจะเป็นประโยชน์อย่างมากสำหรับการกำหนดธีม ดังนี้
:root {
--primary-color: red;
--logo-text: var(--primary-color);
}
ฟังก์ชัน var()
หากต้องการดึงข้อมูลและใช้ค่าของพร็อพเพอร์ตี้ที่กำหนดเอง คุณจะต้องใช้ฟังก์ชัน var()
ไวยากรณ์ของฟังก์ชัน var()
มีลักษณะดังนี้
var(<custom-property-name> [, <declaration-value> ]? )
โดยที่ <custom-property-name>
คือชื่อพร็อพเพอร์ตี้ที่กำหนดเองของผู้เขียน เช่น --foo
และ <declaration-value>
คือค่าสำรองที่จะใช้เมื่อพร็อพเพอร์ตี้ที่กำหนดเองซึ่งอ้างอิงไม่ถูกต้อง ค่าสำรองอาจเป็นรายการที่คั่นด้วยคอมมา ซึ่งจะรวมกันเป็นค่าเดียว เช่น var(--font-stack,
"Roboto", "Helvetica");
กำหนดโฆษณาสำรอง "Roboto", "Helvetica"
อย่าลืมว่าค่าชวเลข เช่น ค่าที่ใช้สำหรับขอบและระยะห่างจากขอบ ไม่ได้คั่นด้วยคอมมา ดังนั้นทางเลือกสำรองที่เหมาะสมสำหรับระยะห่างจากขอบจะมีลักษณะดังนี้
p {
padding: var(--pad, 10px 15px 20px);
}
ผู้เขียนคอมโพเนนต์สามารถใช้ค่าสำรองเหล่านี้เขียนรูปแบบการป้องกันสำหรับองค์ประกอบของตนได้
/* In the component’s style: */
.component .header {
color: var(--header-color, blue);
}
.component .text {
color: var(--text-color, black);
}
/* In the larger application’s style: */
.component {
--text-color: #080;
/* header-color isn’t set,
and so remains blue,
the fallback value */
}
เทคนิคนี้มีประโยชน์อย่างยิ่งสำหรับการกำหนดธีมให้กับ Web Component ที่ใช้ Shadow DOM เนื่องจากพร็อพเพอร์ตี้ที่กำหนดเองสามารถข้ามขอบเขตของ Shadow ได้ ผู้เขียนคอมโพเนนต์เว็บสามารถสร้างการออกแบบเริ่มต้นโดยใช้ค่าสำรอง และแสดง "ฮุก" การจัดธีมในรูปแบบพร็อพเพอร์ตี้ที่กำหนดเอง
<!-- In the web component's definition: -->
<x-foo>
#shadow
<style>
p {
background-color: var(--text-background, blue);
}
</style>
<p>
This text has a yellow background because the document styled me! Otherwise it
would be blue.
</p>
</x-foo>
/* In the larger application's style: */
x-foo {
--text-background: yellow;
}
เมื่อใช้ var()
มีบางสิ่งที่ควรระวังอยู่ ตัวแปรต้องไม่ใช่ชื่อพร็อพเพอร์ตี้ ตัวอย่างเช่น
.foo {
--side: margin-top;
var(--side): 20px;
}
อย่างไรก็ตาม การตั้งค่านี้ไม่เทียบเท่ากับการตั้งค่า margin-top: 20px;
แต่การประกาศที่ 2 จะไม่ถูกต้องและระบบจะแสดงข้อผิดพลาด
ในทำนองเดียวกัน คุณไม่สามารถสร้างค่าที่ตัวแปรส่วนหนึ่งให้โดย (โดยไม่มีเหตุอันควร) ดังนี้
.foo {
--gap: 20;
margin-top: var(--gap)px;
}
ย้ำอีกครั้ง การตั้งค่านี้ไม่เทียบเท่ากับการตั้งค่าmargin-top: 20px;
หากต้องการสร้างค่า คุณต้องมีอย่างอื่น ซึ่งก็คือฟังก์ชัน calc()
การสร้างค่าด้วย calc()
หากคุณยังไม่เคยใช้มาก่อน ฟังก์ชัน calc()
จะเป็นเครื่องมือเล็กๆ ที่จะช่วยให้คุณคำนวณเพื่อกำหนดค่า CSS ได้ เบราว์เซอร์สมัยใหม่ทั้งหมดรองรับ และสามารถรวมเข้ากับพร็อพเพอร์ตี้ที่กำหนดเองเพื่อสร้างค่าใหม่ได้ เช่น
.foo {
--gap: 20;
margin-top: calc(var(--gap) * 1px); /* niiiiice */
}
การใช้พร็อพเพอร์ตี้ที่กําหนดเองใน JavaScript
หากต้องการรับค่าของพร็อพเพอร์ตี้ที่กำหนดเองขณะรันไทม์ ให้ใช้เมธอด getPropertyValue()
ของออบเจ็กต์ CSSStyle Declaration ที่คำนวณแล้ว
/* CSS */
:root {
--primary-color: red;
}
p {
color: var(--primary-color);
}
<!-- HTML -->
<p>I’m a red paragraph!</p>
/* JS */
var styles = getComputedStyle(document.documentElement);
var value = String(styles.getPropertyValue('--primary-color')).trim();
// value = 'red'
ในทำนองเดียวกัน หากต้องการกำหนดค่าพร็อพเพอร์ตี้ที่กำหนดเองขณะรันไทม์ ให้ใช้เมธอด setProperty()
ของออบเจ็กต์ CSSStyleDeclaration
/* CSS */
:root {
--primary-color: red;
}
p {
color: var(--primary-color);
}
<!-- HTML -->
<p>Now I’m a green paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'green');
นอกจากนี้ คุณยังตั้งค่าของพร็อพเพอร์ตี้ที่กำหนดเองให้อ้างอิงพร็อพเพอร์ตี้ที่กำหนดเองอีกรายการหนึ่งขณะรันไทม์ได้โดยใช้ฟังก์ชัน var()
ในการเรียกใช้ setProperty()
/* CSS */
:root {
--primary-color: red;
--secondary-color: blue;
}
<!-- HTML -->
<p>Sweet! I’m a blue paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'var(--secondary-color)');
เนื่องจากพร็อพเพอร์ตี้ที่กำหนดเองอาจอ้างถึงพร็อพเพอร์ตี้ที่กำหนดเองอื่นๆ ในสไตล์ชีตได้ คุณจึงอาจจินตนาการได้ว่าสิ่งนี้จะนำไปสู่เอฟเฟกต์รันไทม์ที่น่าสนใจทุกประเภทได้อย่างไร
การสนับสนุนเบราว์เซอร์
ขณะนี้ Chrome 49, Firefox 42, Safari 9.1 และ iOS Safari 9.3 รองรับคุณสมบัติที่กำหนดเอง
สาธิต
ลองใช้ตัวอย่างเพื่อดูเทคนิคที่น่าสนใจทั้งหมดที่คุณใช้ประโยชน์ได้ตอนนี้ด้วยพร็อพเพอร์ตี้ที่กำหนดเอง
อ่านเพิ่มเติม
หากอยากทราบข้อมูลเพิ่มเติมเกี่ยวกับพร็อพเพอร์ตี้ที่กำหนดเอง Philip Walton จากทีม Google Analytics ได้เขียนเกริ่นนำเกี่ยวกับเหตุผลที่เขาสนใจพร็อพเพอร์ตี้ที่กำหนดเอง และคุณสามารถติดตามดูความคืบหน้าในเบราว์เซอร์อื่นๆ ได้ที่ chromestatus.com