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

ตัวแปร CSS หรือที่เรียกอย่างถูกต้องว่าพร็อพเพอร์ตี้ที่กำหนดเองของ CSS จะพร้อมใช้งานใน Chrome 49 ซึ่งมีประโยชน์ในการลดการซ้ำใน CSS และเพื่อเอฟเฟกต์รันไทม์ที่มีประสิทธิภาพ เช่น การเปลี่ยนธีม และอาจขยาย/โพลีฟีลฟ์ฟีเจอร์ CSS ในอนาคต

CSS รก

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

ในช่วงหลังๆ นี้ นักพัฒนาซอฟต์แวร์จำนวนมากหันมาใช้โปรแกรมประมวลผลข้อมูล CSS เช่น SASS หรือ LESS ซึ่งแก้ปัญหานี้ได้โดยใช้ตัวแปรโปรแกรมประมวลผลข้อมูล แม้ว่าเครื่องมือเหล่านี้จะช่วยเพิ่มประสิทธิภาพของนักพัฒนาซอฟต์แวร์ได้เป็นอย่างมาก แต่ตัวแปรที่ใช้ก็มีข้อเสียที่สำคัญอย่างหนึ่งคือตัวแปรเป็นแบบคงที่และไม่สามารถเปลี่ยนแปลงขณะรันไทม์ได้ การเพิ่มความสามารถในการเปลี่ยนตัวแปรขณะรันไทม์ไม่เพียงเปิดโอกาสให้ทำสิ่งต่างๆ เช่น การกำหนดธีมแอปพลิเคชันแบบไดนามิกเท่านั้น แต่ยังส่งผลสำคัญต่อการออกแบบที่ปรับเปลี่ยนตามอุปกรณ์และมีโอกาสที่จะใช้ polyfill กับฟีเจอร์ 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 ในปัจจุบันไม่ได้ เนื่องจากไม่สามารถกำหนดตัวแปรภายในการค้นหาสื่อ ความสามารถนี้จะช่วยปลดล็อกศักยภาพได้มากมาย

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

: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()วิธีของออบเจ็กต์ CSSStyleDeclaration ที่คำนวณแล้ว

/* 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