Skip to content

CSS Specificity พื้นฐานการเขียน CSS ที่คนส่วนใหญ่ไม่รู้ & เทคนิค Hack

designil
5 mins
CSS Specificity พื้นฐานการเขียน CSS ที่คนส่วนใหญ่ไม่รู้ & เทคนิค Hack
เวลาเราเขียน CSS ในโปรเจคเว็บไซต์ใหญ่ ๆ ที่มี CSS Selector มากมาย ปัญหาที่น่าจะเจอกันบ่อย ๆ คือ CSS เขียนแล้วไม่ยอมทำงาน เพราะโดน Selector ตัวอื่นเขียนทับ ต้องไปใส่ !important เพื่อบังคับให้มันทำงาน การใส่ !important ช่วยแก้ปัญหาได้รวดเร็วก็จริง แต่ยิ่งเราเขียนโค้ดเยอะ ๆ ก็จะพบว่าการใส่ !important จะทำให้มีปัญหาตีกับ Element อื่นตลอดเวลา และทำให้โค้ดดูแลยากในระยะยาวด้วยครับ ยิ่งกับโปรเจคใหญ่ ๆ เรายิ่งไม่ควรใช้ !important เลย บทความแนะนำ: CSS Guideline - เทคนิคการเขียน CSS แบบมืออาชีพ

CSS Specificity คืออะไร? รู้แล้วจะเลิกใช้ !important

CSS Specificity เป็นคอนเซปต์การเลือก CSS Selector ที่มี "ค่าพลัง" เยอะที่สุด มาใช้กับ Element บนหน้าเว็บไซต์ครับ (ขอใช้คำนี้แล้วกันครับ มันดูเป็นการ์ดพลังต่อสู้อะไรแบบนั้นดี ใครพลังเยอะกว่าก็ชนะ 55) ภาษา CSS เหมือนภาษาการเขียนโปรแกรมอื่น ๆ ที่อ่านโค้ดจาก บน - ล่าง ครับ แปลว่า ถ้าเขียน CSS Selector ซ้ำกัน 2 อัน อันล่างจะถูกนำไปใช้งานเพราะใหม่กว่า แต่ความพิเศษของ CSS คือ Selector ที่แตกต่างกันแต่ละ Selector จะมี "ค่าพลัง" ไม่เหมือนกัน และเมื่อไหร่ที่ "ค่าพลัง" ต่างกัน ลำดับการเขียนโค้ดจะไม่มีผลทันที ตัวอย่างง่าย ๆ ของเรื่อง CSS Specificity คือ ถ้าเราเขียน HTML/CSS แบบนี้: HTML: [html] <div class="box" id="redbox"> [/html] CSS: [css] .box { background: white; } /* ให้ .box พื้นหลังสีขาว */ #redbox { background: red; } /* ให้ #redbox พื้นหลังสีแดง */ [/css] เราจะได้กล่องสีแดงมา 1 กล่อง ดังด้านล่างนี้ครับ [codepen_embed height="268" theme_id="1723" slug_hash="Lsjew" default_tab="result"][/codepen_embed] CSS Selector ทั้ง 2 อันของเรามีค่าพลังต่างกัน โดยค่าพลังจะคำนวณจากการใช้ class, ID, !important หรือการซ้อน Element หลาย ๆ ชั้นครับ ยิ่ง Selector นั้นเจาะจงเท่าไหร่ยิ่งมีค่าพลังเยอะเท่านั้น เรามาดูกันว่า CSS Selector ในตัวอย่างมีค่าพลังเท่าไหร่กันบ้าง [css].box { }[/css] มีค่าพลัง 10 [css]#redbox { }[/css] มีค่าพลัง 100 เพราะฉะนั้น CSS Property ใน [css]#redbox { }[/css] (ค่าพลัง 100) จะถูกดึงมาแสดงผลทับของ [css].box { }[/css] (ค่าพลัง 10) เพราะมี ค่าพลังมากกว่า นั่นเอง ลองมาดูอีกตัวอย่างกันนะครับ HTML: [html] <div class="box"> <a href="#">Hello</a> </div> [/html] CSS: [css] a { color: blue; } /* ให้ <a> ตัวหนังสือสีน้ำเงิน */ .box a { color: red; } /* ให้ <a> ที่อยู่ใน .box ตัวหนังสือสีแดง */ [/css] ถึงแม้เราจะกำหนดให้ <a> เป็นสีเงินในบรรทัดแรก ลิงค์ก็จะกลายเป็นสีแดงเพราะไปเจอ [css].box a { }[/css] ที่มีค่าพลังเยอะกว่าครับผม [codepen_embed height="268" theme_id="1723" slug_hash="hILwb" default_tab="result"][/codepen_embed] ในตัวอย่างนี้ [css]a { }[/css] มีค่าพลัง 1 ในขณะที่ [css].box a { }[/css] มีค่าพลัง 11 ครับ ทำให้บราวเซอร์เลือก CSS Selector อันหลังมาแสดงแทนนั่นเอง ต่อไปเรามาดูกันครับว่า "ค่าพลัง" คำนวณยังไง

วิธีคำนวณ "ค่าพลัง" CSS Specificity

เราสามารถคำนวณตามกฏง่าย ๆ แบบนี้เลยครับ โดยทุก Selector เริ่มจาก 0 คะแนน:
  1. ถ้าเขียน CSS ใส่ใน style เลย (เช่น [html]<a style="color: red">[/html]) : +1000 คะแนน
  2. ใส่ 1 ID : +100 คะแนน
  3. ใส่ 1 class : +10 คะแนน
  4. ใส่ 1 Element (แท็ก HTML ทั้งหลาย) :  +1 คะแนน
มาลองคำนวณ "ค่าพลัง" กันดูนะคร้าบ
  • [css]div { }[/css] = 1 คะแนน (ข้อ 4)
  • [css].box { }[/css] = 10 คะแนน (ข้อ 3)
  • [css]#box { }[/css] = 100 คะแนน (ข้อ 2)
ในกรณีที่ CSS Selector เราซ้อนหลายชั้น ก็คิดคะแนนโดย + ทุกชั้นรวมกันไปเลยครับ เช่น
  • [css]div a { }[/css] = 2 คะแนน เพราะ div และ a คิดเป็น Element ละ 1 คะแนน (ข้อ 4)
  • [css].box a { }[/css] = 11 คะแนน เพราะ .box = 10 คะแนน (ข้อ 3) และ a = 1 คะแนน (ข้อ 4)
  • [css]div h1 a span { }[/css] = 4 คะแนน เพราะ Element ละ 1 คะแนน (ข้อ 4)
  • [css].page h1 a { }[/css] = 12 คะแนน เพราะ .page = 10 คะแนน (ข้อ 3) และ h1 กับ a = 1 + 1 คะแนน (ข้อ 4)
CSS Selector ตัวไหนมีคะแนนเยอะกว่าก็จะถูกนำมาใช้งาน ซึ่งในกรณีที่คะแนนเท่ากัน ก็มาดูว่า CSS Selector ตัวไหนอยู่ด้านล่างครับ ตัวด้านล่างจะถูกนำมาใช้งาน ซึ่งถ้าสังเกตในข้อ 1 จะเห็นว่าถ้าเราเขียน Inline CSS (เขียน CSS ลงใน style) จะมีค่าพลังสูงกว่าทุกอย่างครับ (1000 คะแนน) เพราะฉะนั้นเวลาเราอยากบังคับใช้ CSS อะไรสามารถเขียนเป็น Inline CSS ได้ แต่แนะนำให้ใช้เวลาทดสอบเฉย ๆ ครับ เว็บไซต์จริงไม่ควรมี CSS ใน HTML เพราะจะทำให้ไฟล์ HTML หนัก โหลดช้า เป็นผลเสียต่อ SEO ครับ สำหรับ !important ที่ไม่ได้อยู่ในข้อ 1 - 4 ด้านบน ถ้าใส่เข้าไปจะเป็นการบังคับใช้ CSS นั้นทันที ไม่ต้องดู "ค่าพลัง" กันเลยครับ (หรือจะใช้วิธีจำว่าค่าพลัง Infinity เลยก็ได้ครับ)

เทคนิคการเขียนให้ CSS ของเราไม่ตีกับ CSS Specificity  โดย CSSWizardry

ถ้าเราต้องมานั่งคิดคะแนนทุกครั้งที่เขียน Selector คงยุ่งยากน่าดูครับ เพราะฉะนั้นมาดูเทคนิคง่าย ๆ ที่จะทำให้โค้ด CSS ของเราจัดการได้สะดวก ซึ่งแนะนำโดยคุณ Harry เจ้าของเว็บไซต์ CSSWizardry.com ซึ่งเป็น Front-end Developer ที่เก่งมาก ๆ
  • อย่าใช้ #ID ใน Selector - การใช้ ID ซึ่งเพิ่มค่าพลังถึง 100 คะแนน จะทำให้ความแตกต่างระหว่าง Selector มากเกินไป และเขียนทับได้ยากครับ (ถ้าจะทับต้องเขียน ID, Inline CSS, หรือ !important เท่านั้น ซึ่งทำให้โค้ดหนักเข้าไปใหญ่)
  • อย่าเขียน Selector ซ้อนกันโดยไม่จำเป็น - เขียน [css].box-inside { }[/css] จะดีกว่าเขียน [css].box .box-inside { }[/css] ซึ่งเป็นการซ้อนโดยไม่จำเป็น และทำให้ค่าพลังสูงกว่าเดิมโดยไม่จำเป็น ยกเว้นว่าแบบแรกไม่ทำงาน
  • อย่าเขียน Selector ชั้นเดียวแบบเจาะจงเกินไป - เขียน [css].box { }[/css] จะดีกว่าเขียน [css]div.box { }[/css] ซึ่งเป็นการเจาะจงเกินไป ทำให้ค่าพลังสูงกว่าเดิมโดยไม่จำเป็น ยกเว้นว่าแบบแรกไม่ทำงาน
  • ใช้ Class ให้บ่อยเข้าไว้ - Class เป็นการเขียน Selector ที่ค่าพลังไม่สูงเกินไป จะเขียนทับก็ไม่ยาก หรือจะสามารถนำมาใช้ใหม่ก็ทำได้ง่าย
สรุปสั้น ๆ คือ อย่าเขียน CSS Selector ที่เจาะจงเกินความจำเป็นครับ บางคนอ่านแล้วอาจจะสงสัยว่า ถ้าทำตามเทคนิคนี้แล้วจะเขียน Selector ให้ ID ยังไง หรือจะเพิ่มค่าพลังของ CSS Selector บางตัวได้ยังไงโดยไม่ต้องซ้อนหลายชั้น และไม่ต้องใช้ !important เข้ามาช่วย เรามาดูกันครับ

เทคนิค Hack 1 : เขียน CSS Selector สำหรับ ID แบบค่าพลังน้อย

การใช้ ID ไม่ได้แย่นะครับ เพราะใน HTML มันมีประโยชน์ (เช่น ทำ Hash ให้ลิงค์มาที่จุดนั้น ๆ ได้) แต่ใน CSS นั้น การเขียน Selector ของ ID จะไม่ดี เพราะ "ค่าพลัง" มันเยอะเกินไป ทำให้เราเขียนทับได้ยากครับ ปกติเราจะเขียน Selector ของ ID แบบนี้: [css] #box { } [/css] แบบนี้มี ค่าพลัง = 100 คะแนน ซึ่งถ้าเราเปลี่ยนเป็นแบบนี้: [css] [id="box] { } [/css] จะมี ค่าพลัง = 10 คะแนน เท่านั้น เท่ากับการใช้ class selector เลยครับ การเขียนแบบหลังเป็นการใช้ Attribute Selector โดยสามารถเลือก ID ได้เหมือนกับแบบแรกครับ อย่างไรก็ตาม อย่าลืมว่าวิธีนี้เป็น CSS Hack ให้นำมาใช้เมื่อจำเป็นต้องใช้ ID ในเว็บไซต์จริง ๆ ครับ ถ้าหลีกเลี่ยงได้ก็ใช้ class ทั้งหมดจะดีที่สุดครับผม

เทคนิค Hack 2 : เพิ่มค่าพลัง โดยไม่ต้องซ้อนหลายชั้น

บางครั้งเวลาเขียน CSS จะเจอปัญหา Selector ชั้นเดียวค่าพลังน้อยกว่า Selector หลายชั้น ซึ่งถ้าจะแปลง Selector ชั้นเดียวกลายเป็นหลายชั้นเพื่อให้ค่าพลังมากกว่า เราก็อาจจะต้องไปแก้ไข HTML เพิ่ม class, element เข้าไป มาดูกันว่าจะแก้ปัญหานี้ได้ยังไงโดยไม่ต้องแก้ HTML ครับ ในสถานการณ์ต่อไปนี้ HTML: [html] <div class="page"> <div class="button"> <a href="#">Click</a> </div><!-- button --> </div><!-- page --> [/html] CSS: [css] .button { color: red; } /* ค่าพลัง = 10 */ .page a { color: blue; } /* ค่าพลัง = 11 */ [/css] จะเห็นว่า .button ไม่กลายเป็นสีแดง เพราะโดน [css].page a { }[/css] ที่มีค่าพลังมากกว่าเขียนทับ ในกรณีนี้ เราสามารถทำแบบนี้ได้ครับ [css] .button.button { color: red; } /* ค่าพลัง = 20 */ .page a { color: blue; } /* ค่าพลัง = 11 */ [/css] การเพิ่ม .button เข้าไปต่อท้าย จะทำให้ "ค่าพลัง" เพิ่มขึ้นเป็น 10 + 10 และทำให้ไม่โดน [css].page a[/css] เขียนทับครับ และจะทำให้ .button ของเรากลายเป็นสีแดงตามที่เราต้องการ

เครื่องมือคำนวณ "ค่าพลัง" CSS Specificity

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

สรุปเรื่อง CSS Specificity เราควรรู้ขนาดไหน

บางคนอาจจะคิดว่าการต้องมาคำนวณ "ค่าพลัง" ของ Selector มันลำบาก (ผมก็คิดเหมือนกันครับ) เพราะฉะนั้นแนะนำให้ขึ้นไปอ่านหัวข้อ "เทคนิคการเขียนให้ CSS ของเราไม่ตีกับ CSS Specificity" ก็ครอบคลุมในระดับที่โอเคแล้วครับ ถ้าเจอปัญหาจริง ๆ ค่อยกลับมาดูเรื่อง CSS Specificity ว่าเราเขียนผิดตรงไหน สิ่งที่สำคัญมาก ๆ คือ "อย่าใช้ ID ใน CSS ถ้าไม่จำเป็น" หลัง ๆ ผมเขียน CSS โดยใช้ class หมดเลยครับ ซึ่งดีมาก ๆ โดยเฉพาะอย่างยิ่งในเว็บที่ใช้ UI ซ้ำบ่อย ๆ หากใครยังไม่ได้อ่าน CSS Guideline - เทคนิคการเขียน CSS แบบมืออาชีพ แนะนำให้อ่านต่อเลยครับ อ่านจบจะเขียน CSS เก่งขึ้นเยอะแน่นอน แวะไปเยี่ยมเยียน สอบถามคำถามต่าง ๆ ได้ที่ Facebook Page ของ Designil นะครับ หากชอบบทความนี้อย่าลืมแชร์ให้เพื่อน ๆ ได้อ่านกัน ความรู้ดี ๆ มีไว้แชร์ครับ :D
designil

designil

Data engineer & WordPress Developer ทำงานที่บริษัทแคนว่า ซิดนีย์ออสเตรเลีย ปัจจุบันเป็นเจ้าของเว็บไซต์ Designil, DataTH ชอบอ่านบทความใหม่ๆ ตลอดเวลา และชอบสรุปเรื่องราวเกี่ยวกับเทคโนโลยีให้ภาษาที่เข้าใจง่าย ยินดีที่ได้รู้จักทุกคนนะครับ

บทความทั้งหมด