ตัวแปร CSS - ทำไมคุณจึงควรให้ความสนใจ

ตัวแปร 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 ได้ ผู้เขียนคอมโพเนนต์เว็บสามารถสร้างการออกแบบเริ่มต้นโดยใช้ค่าสำรอง และแสดง &quot;ฮุก&quot; การจัดธีมในรูปแบบพร็อพเพอร์ตี้ที่กำหนดเอง

<!-- 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