:where() :is() :not() :has()

Pimpineej
2 min readMar 15, 2024

วันนี้เราจะมาพูดถึง Functional pseudo-classes กันค่ะ จากการที่ลองเล่นมาแล้วส่วนตัวมันช่วยการเขียน css แบบไม่ใช้ less หรือ sass ได้อยู่ค่ะ ว่าแต่จะช่วยยังไงบ้างนั้นมาดูกัน

ก่อนที่เราจะมี less sass หรือ scss นั้น การเขียนคำสั่งไปที่ child element จะเขียนแบบที่อยู่ในบรรทัดเดียวกัน

.main a {
...
}

แต่ถ้าเราอยากจะเพิ่ม selectors ก็จะต้องเขียนโดยการใส่ , ต่อกันไปเรื่อยๆ

.main a, ul a, footer a, h2 a {
...
}

ทำให้ยากต่อการอ่านและแก้ไข code อยู่ค่ะ และโอกาสในแก้ผิดก็ค่อนข้างสูงอีกด้วย เลยจะต้องใช้ scss หรือ sass เข้ามาช่วย (less ก็เช่นกัน)

/* การเขียน select child element ด้วย scss */
.main, ul, footer, h2 {
a {
...
}
}

แต่ถ้าไม่ได้ใช้ less / scss ล่ะ ..

หรือถ้าเป็นที่เราต้องการเขียนกล่องที่มี style ต่างกันเพียงแค่บางจุด แล้วต้องใช้ if ในการเพิ่ม class เข้าไปทำให้ check case ใน code ส่วน js เพิ่มขึ้น ซึ่งก็ทำได้แหละ แต่มันมีวิธีที่ทำโดยไม่ต้องเพิ่ม class ด้วยนะ นั่นก็คือ Functional pseudo-classes เหล่านี้เองค่ะ

:where()

เป็นการเขียนแบบรวม selector กับ child element เข้าด้วยกัน โดยที่เราไม่ต้องเขียนแยกออกมาเลย เขียนแบบนี้อาจจะยังงงๆ ไปดูตัวอย่างก่อนนะคะ

/* แบบปกติ */
.main a, ul a, footer a, h2 a, .main span, ul span, footer span, h2 span {
...
}
/* ใช้คำสั่ง where */
:where(.main, ul, footer, h2) :where(a, span) {
...
}

จะเห็นได้ว่าการเขียนโดยใช้ :where() ทำให้สั้นลงมาก จาก code แสดงให้เห็นว่าเราเขียนสั่งที่ selector .main, ul, footer, h2 และ child a, span ได้โดยไม่ต้องใช้ตัวช่วยเลย

:is()

เป็น pseudo-classes ที่เหมือนกับ :where() เลยค่ะ แต่ที่ต่างกันจะเป็นเรื่องของ น้ำหนักความสำคัญตอนมี override css ตามตัวอย่างนี้นะคะ

header h1 {
color: red;
}

:is(header, section) :is(h1, h2) {
color: green;
}

:where(header, section) :where(h1, h2) {
color: blue;
}
/* header h1 แสดง text สีเขียว */

กรณีนี้ header h1 จะแสดงเป็นสีเขียว แม้ว่าจะมีคำสั่ง :where() ด้านล่างน้ำหนักก็จะไม่แรงเท่า :is() และถึงเราจะลบคำสั่ง :is() ออก :where() ก็จะไม่ override header h1 ด้านบนเช่นกัน

:is(.content, aside) :is(h3, h2) {
color: blue;
}

aside h2 {
color: green;
}
/* aside h2 แสดง text สีเขียว */

ในทางกลับกันเราเรียง :is() ไว้ด้านบนแล้วเขียนคำสั่งแบบปกติด้านล่างก็จะไม่เกิดการ override เหมือนกัน เรามองว่าคำสั่งนี้ก็คล้ายๆ เราใส่ !important อยู่เหมือนกัน (แต่คิดว่าไม่มีอะไรแรงเท่า important แล้วค่ะ 😅)

สามารถดูเรื่องคะแนนของน้ำหนักได้ที่ https://medium.com/js-now/css-where-is-pseudo-class-functions-33964d0de461

:not()

อีกคำสั่งที่คิดว่าน่าจะได้ใช้กันคือ :not() ที่จะใช้เพื่อเช็คสิ่งที่ไม่ match กับ selector ของเรานั่นเองค่ะ ไปดูตัวอย่างกันเลย

<!-- กรณีใช้ class เดียวกันแต่มี html tag ที่ต่างกัน -->
<div class="content">
<h3>Title</h3>
<p>Lorem Ipsum is simply</p>
</div>

<section class="content">
<h3>Title</h3>
<p>Lorem Ipsum is simply</p>
</section>

<aside class="content">
<h3>Title</h3>
<p>Lorem Ipsum is simply</p>
</aside>
/* เขียนแบบปกติ */
div.content, aside.content {
background: green;
}
/* เขียนโดยใช้คำสั่ง not */
.content:not(section) {
background: green;
}

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

:has()

เป็นคำสั่งที่เราค่อนข้างชอบมากที่สุด เราเคยคิดกับตัวเองก่อนหน้านี้มาว่า
“ ทำไมเราไม่มีคำสั่งที่สามารถเช็คได้ว่า มี child แบบไหนบ้างใน div ”
ใช่ค่ะ :has() เป็น function pseudo-classes ที่มีไว้เพื่อสิ่งนี้

<!-- กรณีใช้ class เดียวกันแต่มี child ที่ต่างกัน -->
<div class="content">
<p>Lorem Ipsum is simply</p>
</div>

<div class="content">
<div>Lorem Ipsum is simply</div>
</div>

กรณีที่เราใช้ class ร่วมกัน แต่ child ด้านในไม่เหมือนกัน เดิมหากต้องการเขียนให้มี style ที่ต่างกันเราจะต้องเขียนให้ js เข้าไปเช็ค element ข้างใน แล้วใส่ class เพิ่มที่ตัวที่มี child ที่เราระบุนั้นๆ แต่ด้วย :has() เราไม่จำเป็นต้องทำแบบนั้นอีกต่อไปค่ะ

.content {
background: green;
}
/* class content จะมีสีพื้นหลังสีเขียว */

.content:has(p) {
background: blue;
}
/* class content ที่มี child เป็น p จะมีสีพื้นหลังสีน้ำเงิน */

ซึ่งเท่านี้เราก็ไม่ต้องมาเขียน check ใน js ให้วุ่นวายอีกแล้วค่ะ

สุดท้ายนี้เรามองว่า Functional pseudo-classes เป็นคำสั่งที่มีมาเพื่อทำให้เขียน style ได้ง่ายขึ้น เป็นอีกมิตินึงของการเขียน css ให้ดูเหมือนการเขียนโปรแกรมมากขึ้น หวังว่าจะชอบกันนะคะ 😌

--

--