CSS Selector Tester: ทดสอบและไฮไลต์ selector ด้วย live match count ในเบราว์เซอร์
ทดสอบ CSS selector กับ HTML ที่ paste เข้ามา ไฮไลต์ element ที่ match จับ selector ที่ผิด syntax และฝึกทักษะ selector ด้วย live match count ทั้งหมดในเบราว์เซอร์
Table of Contents
CSS Selector Tester: ทดสอบและไฮไลต์ selector ด้วย live match count ในเบราว์เซอร์
การเขียน CSS selector นั้นง่าย แต่การรู้ว่ามัน match กับอะไรบ้างต่างหากที่ยาก CSS Selector Tester แก้ปัญหานี้ได้ตรงจุด: paste HTML สักชิ้น พิมพ์ selector แล้วคุณจะเห็นทุก element ที่ match ถูกไฮไลต์ไว้ในที่ของมันทันที พร้อม live match count และข้อความ error ที่อ่านเข้าใจง่ายเมื่อ selector ผิด syntax ทุกอย่างทำงานในเบราว์เซอร์ของคุณ ไม่มีการอัปโหลด ไม่ต้องสมัครบัญชี และไม่ต้องรอ
Selector คือเส้นเลือดใหญ่ของงาน front-end มันขับเคลื่อน stylesheet ของคุณ คำสั่ง querySelector ตัวจับ element ใน end-to-end test และกฎการ scrape ข้อมูล เมื่อ selector ตัวหนึ่ง match ไม่เจออะไรเลยแบบเงียบ ๆ หรือ match กับสี่สิบ element ทั้งที่คุณคาดว่าจะเจอแค่ตัวเดียว บั๊กแบบนี้มักไม่มีวันประกาศตัวเอง คุณแค่สังเกตว่า style ไม่ถูกใส่ test หา element ไม่เจอ หรือ script ดึง node ผิดตัว
บทความนี้จะพาไปดูเครื่องมือ แล้วเจาะลึกเทคนิค selector ที่ควรฝึกใช้จริง: combinator, attribute operator, คณิตศาสตร์ของ :nth-child, การต่อ :not(), ความเข้าใจเรื่อง specificity และตัวอย่างการ debug จริงที่ selector พลาดเป้าไปเงียบ ๆ
ทำไมต้องใช้ CSS Selector Tester?
- เห็นผลลัพธ์ทันทีในรูปแบบภาพ element ที่ match จะถูกไฮไลต์ไว้ใน markup ที่แสดงผลโดยตรง คุณเห็นขอบเขตของ selector ในแวบเดียว ไม่ต้องเดาจาก array ของ node ใน console
- Live match count ตัวนับอัปเดตตามที่คุณพิมพ์ ทำให้เห็นทันทีว่าการแก้ selector หนึ่งครั้งช่วยลดผลลัพธ์จากหลายสิบ element เหลือให้ตรงกับสามตัวที่ต้องการจริง ๆ
- Selector ที่ผิดก็ fail อย่างชัดเจน พิมพ์ผิดหรือ syntax ผิดจะขึ้นเป็น error message ที่อ่านได้ ไม่ใช่ผลลัพธ์ว่าง ๆ ซึ่งต่างจากการไล่หากันยี่สิบนาทีใน stylesheet
- ทดสอบกับ markup จริง ไม่ใช่ตัวอย่างสำเร็จรูป paste ชิ้นส่วนจริงจากแอป, template ของ CMS หรือ vendor widget แล้วทดสอบกับโครงสร้างที่คุณใช้งานจริง
- Sample HTML loader ไม่มี markup ติดมือ? กดโหลด sample ที่มีให้แล้วเริ่มทดลองได้ทันที เหมาะกับการใช้เป็น sandbox สำหรับฝึก selector
- ประมวลผล 100% client-side HTML ของคุณไม่หลุดออกจากแท็บเบราว์เซอร์ markup ภายในองค์กร URL ภายใน และดีไซน์ที่ยังไม่เปิดตัวจึงยังอยู่บนเครื่องคุณ
ฟีเจอร์หลัก
| ฟีเจอร์ | ทำอะไร | ทำไมจึงสำคัญ |
|---|---|---|
| HTML paste area | รับ markup ที่ paste เข้ามา | ทดสอบกับโครงสร้าง DOM จริงของคุณ |
| Selector input | ประเมิน CSS selector มาตรฐานระหว่างพิมพ์ | ได้ feedback ทันทีขณะปรับ selector |
| Highlight overlay | ไฮไลต์ทุก element ที่ match | เห็นชัดว่า selector คว้าอะไรไปบ้าง |
| Live match counter | รายงานจำนวน match แบบเรียลไทม์ | จับการ match มากไปหรือน้อยไปได้ทันที |
| Error reporting | จับ selector ที่ invalid พร้อมข้อความอ่านง่าย | รู้ตัวเร็ว ไม่ต้อง debug แบบมืดตื้อ |
| Sample HTML loader | มี markup สำเร็จรูปให้ทดลอง | เริ่มฝึกได้เลยโดยไม่ต้องเตรียมอะไร |
บางฟีเจอร์ควรเน้นเป็นพิเศษ คู่ของไฮไลต์และตัวนับเปลี่ยนการเขียน selector จากการเดาให้กลายเป็นการวัดผล: คุณเสนอ selector เครื่องมือตัดสิน และคุณรู้ภายในการกดคีย์เดียวว่าโมเดลในหัวของคุณตรงกับ markup หรือไม่ และเพราะการประเมินทำงานฝั่ง client ทั้งหมด คุณจึง paste dashboard ภายใน, email template หรือ component ก่อนวางจำหน่ายได้อย่างปลอดภัย
วิธีใช้งาน CSS Selector Tester
- Paste HTML ของคุณ คัดลอกชิ้นส่วนจากโปรเจกต์ เช่น component template, section ของหน้าเว็บที่ render แล้ว หรือ email layout แล้ววางลงในพื้นที่ HTML
- หรือโหลด sample แทน ถ้าแค่อยากสำรวจ กดปุ่ม sample loader เพื่อรับ markup ตัวอย่างที่มีทั้ง element ซ้อนกัน, class และ attribute หลากหลาย
- พิมพ์ selector เริ่มจากกว้าง ๆ (div, .card, ul li) แล้วดูตัวนับ จากนั้นค่อย ๆ เพิ่ม class, attribute หรือ pseudo-class จนไฮไลต์ครอบคลุมเฉพาะเป้าหมายของคุณ
- อ่านไฮไลต์และตัวเลข element ที่ match จะสว่างขึ้นใน tree และตัวนับยืนยันว่า match กี่ node ถ้าเป็นศูนย์มักแปลว่า selector เข้มกว่า markup ถ้าเยอะมากแปลว่ามันหลวมกว่าที่คิด
- วนซ้ำและเปรียบเทียบ ปรับ selector เปลี่ยน combinator เติม :not() หรือสลับ attribute operator แล้วเทียบจำนวน match ระหว่างเวอร์ชันจนทั้งตัวเลขและไฮไลต์ถูกต้องพร้อมกัน
วงจรทั้งหมดใช้เวลาไม่กี่วินาที และเพราะเห็นทุก iteration คุณจะสร้าง intuition เรื่อง selector ที่แม่นยำได้เร็วกว่าการแก้ stylesheet แล้วรีเฟรชหน้าเว็บหลายเท่า
เทคนิค selector ขั้นสูงที่ควรลองทดสอบ
Descendant กับ child combinator
Space combinator match ที่ความลึกไหนก็ได้: div.card p เลือกทุก paragraph ที่อยู่ใน card ไม่ว่าจะซ้อนลึกแค่ไหน ส่วน child combinator div.card > p เลือกเฉพาะลูกโดยตรง ความต่างนี้เป็นต้นเหตุของบั๊กเงียบ ๆ บ่อยมาก: พอใส่ <div> ครอบระหว่าง card กับข้อความ เวอร์ชัน child ก็ match ไม่เจอทันทีขณะที่เวอร์ชัน descendant ยังทำงานปกติ ใช้ child combinator เมื่อโครงสร้างคือสัญญาที่คุณอยากบังคับใช้ และใช้ descendant เมื่ออยากทนต่อการเพิ่ม wrapper ทดสอบทั้งสองแบบในเครื่องมือแล้วคุณจะรู้ทันทีว่า markup ปัจจุบันรองรับแบบไหน
Attribute selector: ^=, $= และ *=
Attribute operator เปลี่ยน convention ใน markup ให้เป็นตัวกรองความละเอียดสูง a[href^="https"] match ลิงก์ที่ขึ้นต้นด้วย https เหมาะกับการตรวจว่า anchor ไหนปลอดภัย img[src$=".svg"] match รูปเวกเตอร์จากนามสกุล ใช้ได้ทั้งงาน lazy-loading และการจัด style [class*="btn-"] match ทุก element ที่ class attribute มี substring ว่า btn- ซึ่งใช้ได้ดีกับ codebase สาย utility class แต่ก็หยาบเพราะไป match btn-outline-secondary ด้วย การ match แบบ prefix (^=) มักปลอดภัยกว่าเมื่อชื่อ class มีรูปแบบชัดเจน
คณิตศาสตร์ของ pseudo-class และการต่อ :not()
:nth-child รับ expression ทางคณิตศาสตร์เต็มรูปแบบ ไม่ใช่แค่ odd กับ even :nth-child(3n+1) match ลำดับที่ 1, 4, 7 ไปเรื่อย ๆ ซึ่งเป็นแกนคณิตของการทำ zebra striping ใน grid สามคอลัมน์ :nth-child(n+3) ข้ามสองอันแรก เป็นวิธีมาตรฐานในการเอาเส้นขอบออกจาก list item ยกเว้นสองอันแรก และเมื่อผสมกับ :not() ก็จะได้การตัดออกแบบผ่าตัด: li:not(:last-child) จัด style ทุกอันยกเว้นอันสุดท้าย ส่วน input:not([disabled]):not([type="hidden"]) เลือกเฉพาะ input ที่ใช้งานได้จริง การต่อ :not() หลาย ๆ อันอ่านเหมือนประโยคและเลี่ยงต้นทุน specificity ของการไล่ class ยาว ๆ
ความเข้าใจเรื่อง specificity
Specificity คือเกมการนับ: inline style ชนะ ID, ID ชนะ class และ class ชนะชื่อ element selector อย่าง #sidebar .nav li a มีทั้ง ID, class และชื่อ element สองตัว แทบไม่มีอะไร override มันได้ถ้าไม่ใช้ ID อีกทอด ซึ่งเป็นที่มาของสงครามยาวใน stylesheet ทางเลือกที่แบนกว่าอย่าง .nav-link override ง่ายกว่าและย้ายโปรเจกต์ง่ายกว่า เมื่อ style ดื้อไม่ยอมใส่ ตัวการมักเป็น selector ที่มี specificity สูงกว่าซ่อนอยู่ที่ไหนสักแห่งในไฟล์ การเอา selector ทั้งสองมาเช็กใน tester แล้วเทียบชุด match คือวิธีเร็วที่สุดในการมองเห็นการชนกัน
ทำไม selector ถึง match ไม่เจออะไรเลย
มีสี่ผู้ต้องสงสัยที่ครองคดีผลลัพธ์ว่างส่วนใหญ่ หนึ่ง combinator เข้มกว่า markup — ใช้ > ทั้งที่การซ้อนเป็นแบบทางอ้อม สอง class เป็น dynamic: มันถูก JavaScript เติมให้ตอน runtime ดังนั้น snapshot ของ HTML ฝั่ง server จึงไม่มีมัน สามค่า attribute ต่างกันในจุดที่มองไม่เห็น: type="text " ที่มี space ท้าย, ค่าที่เป็นตัวพิมพ์ใหญ่ หรือ data- prefix ที่คุณลืม สี่ element อยู่ใน shadow root หรือถูก inject หลังจาก snapshot เมื่อตัวนับขึ้นศูนย์ ให้ไล่เช็กตามลิสต์นี้ไปทีละข้อโดยคลายข้อจำกัดทีละอย่าง
ตัวอย่างการ debug แบบลงมือจริง
เพื่อนร่วมทีมต้องการดึงหัวข้อของแพ็กเกจราคาจาก section pricing เขาจึงเขียน #pricing .card > h3 แล้วมัน match ไม่เจออะไรเลย สาม query ใน tester แก้ปัญหาได้ภายในนาทีเดียว:
- #pricing ได้ 1 match แปลว่า section นี้มีอยู่จริงใน markup ที่ paste มา
- #pricing .card ได้ 4 matches แปลว่า card ก็มีครบ
- #pricing .card > h3 ได้ 0 และ child combinator คือสิ่งเดียวที่ต่างจากข้อสอง
- #pricing .card h3 ได้ 4 ยืนยันสมมติฐาน: template ใช้ <div class="card-inner"> ครอบเนื้อหาของแต่ละ card หัวข้อจึงเป็นหลาน ไม่ใช่ลูกโดยตรง
ทางแก้คือใช้เวอร์ชัน descendant หรือ .card h3 ที่ตั้งใจชัดกว่า ใจความสำคัญไม่ใช่ว่า child combinator ไม่ดี แต่คือ match count ที่เป็นศูนย์บวกกับการไล่ bisection ทีละเงื่อนไข เปลี่ยนบั๊กปริศนาให้กลายเป็นการวินิจฉัยสองนาที
กรณีใช้งานจริง
เขียน assertion สำหรับ test
Playwright, Cypress และ Testing Library ล้วนพึ่งพา CSS selector เป็น locator และ test ที่ flaky มักมีต้นเหตุจาก locator ที่ match element มากกว่าที่ผู้เขียนเชื่อ paste markup ที่ render แล้วของ component ลงใน tester รัน locator selector แล้วเช็กว่าตัวนับขึ้นเลขหนึ่งพอดีก่อน commit test นั้นจริง วิธีนี้กันอาการคลาสสิกที่ selector ไป match element ที่หน้าตาเหมือนกันใน section อื่นของหน้า
Debug หน้าเว็บจาก third-party
Vendor widget, embedded form และ markup ที่ CMS สร้าง มักไม่มีเอกสารบอกโครงสร้าง DOM มาด้วย บันทึกชิ้นส่วนที่ render แล้ว paste เข้ามา แล้วสำรวจด้วย selector แบบกว้างก่อน ([class*="widget"], form input) เพื่อวาดแผนที่ก่อนเขียนอะไรที่ต้องพึ่งโครงสร้างนั้น คุณจะได้ภาพโครงสร้างที่เชื่อถือได้โดยไม่ต้องไปรื้อหน้า production จริงใน devtools
เก็บกวาด stylesheet เก่า
Legacy CSS สะสม rule ที่เขียนมาเพื่อ markup ที่ไม่มีแล้ว paste template ปัจจุบันลงใน tester แล้วเช็ก selector ที่น่าสงสัย เช่น สาย #wrapper .col-3 .inner p จากปี 2019 กับความจริง ถ้าได้ศูนย์ นั่นคือหลักฐานแข็งว่า rule เป็นของตาย ถ้าได้หนึ่งเดียว อาจกำลังเผชิญ rule ที่ over-specific ซึ่งแทนด้วย class เดียวได้
สอนและเรียน CSS
Selector เรียนรู้ได้ดีที่สุดเมื่อได้เห็นผลลัพธ์ sample HTML loader บวกกับไฮไลต์แบบเรียลไทม์ทำให้เครื่องมือนี้เป็นห้องเรียนจิ๋ว ลองให้ผู้เรียนพิมพ์ li:nth-child(2n) แล้วดู item สลับกันสว่างขึ้น เปลี่ยน 2n เป็น 3n+1 แล้วให้ทายไฮไลต์ถัดไปก่อนกดพิมพ์ feedback loop แบบทันทีนี้สร้าง intuition ที่ถูกต้องได้ภายในไม่กี่นาที
แนวทางปฏิบัติที่ดี
- เลือกใช้ class มากกว่าสาย structural ยาว ๆ .card-title รอดจาก refactor ส่วน #main .content .card > div > h3 ไม่รอด ทุกชั้นที่เพิ่มคือ breaking change ในอนาคต
- ทดสอบกับ markup จริง ไม่ใช่ความจำ โมเดล DOM ในหัวคุณล้าสมัยอยู่เสมอ ชิ้นส่วนที่ paste มาต่างหากที่เป็นความจริง
- รักษา specificity ให้แบน selector ระดับ class เดียว override ง่าย ใช้ซ้ำง่าย และปลอดภัยจากสงคราม specificity
- ไล่จากกว้างไปเฉพาะเจาะจง เริ่มจาก type หรือ class เดียว ยืนยันว่าจำนวน match สมเหตุสมผล แล้วเติมเงื่อนไขทีละอย่าง คุณจะรู้เสมอว่าการเติมครั้งไหนทำให้ match พัง
- จับตาดูตัวเลข ไม่ใช่แค่ไฮไลต์ selector ที่ดูถูกต้องอาจ match element มากเป็นสองเท่าของที่ตั้งใจ ตัวเลขจับสิ่งที่ตากวาดผ่าน
- ทดสอบซ้ำหลัง markup เปลี่ยน template เปลี่ยนตลอด wrapper เพิ่มตลอด selector ที่สมบูรณ์แบบสปรินต์ก่อนอาจผุพังเงียบ ๆ การ paste เช็กสิบวินาทีจับการเลื่อนไหลนี้ได้
เริ่มใช้ CSS Selector Tester วันนี้
ถ้าคุณเคยนั่งเพ่ง devtools สงสัยว่าทำไม rule ถึงไม่ยอมใส่ ลอง paste markup ลงใน CSS Selector Tester พิมพ์ selector แล้วอ่านตัวเลขดู มันฟรี ทันที และทำงานในเบราว์เซอร์ของคุณทั้งหมด และมันจะทำให้คุณเร็วขึ้นจับต้องได้ในงานที่พบบ่อยที่สุดอย่างหนึ่งของสาย front-end
เครื่องมือที่เกี่ยวข้องที่คุณอาจชอบ:
- CSS Unit Converter — แปลงหน่วยระหว่าง px, rem, em, pt และอื่น ๆ โดยไม่ต้องออกจากเบราว์เซอร์
- CSS Custom Properties Generator — สร้างชุด design token ที่สม่ำเสมอและส่งออกเป็น CSS variables
- Tailwind to CSS Converter — แปลง Tailwind utility classes เป็น CSS ธรรมดาที่อ่านได้ เก็บถาวรได้ หรือส่งต่อให้ทีมได้
ขอให้ทุก query คืน element มาตรงตามที่คุณคาดหวังทุกครั้ง
คำถามที่พบบ่อย
ถ: HTML ของฉันถูกอัปโหลดไปที่ server หรือไม่?
ตอบ: ไม่ การ parse การ match และการไฮไลต์ทำงานในแท็บเบราว์เซอร์ของคุณทั้งหมด ไม่มีการส่งข้อมูล ไม่มีการเก็บ และไม่มีการ log คุณจึง paste markup ภายในองค์กรหรืองานก่อนเปิดตัวได้อย่างปลอดภัย
ถ: รองรับ selector แบบไหนบ้าง?
ตอบ: เครื่องมือประเมิน CSS selector มาตรฐาน: type, class และ ID selector, attribute selector ทุก comparison operator, combinator ทั้ง descendant, child และ sibling รวมถึง pseudo-class ที่รองรับแพร่หลายอย่าง :nth-child, :first-child, :last-child และ :not() ส่วน syntax ที่ผิดจะถูกรายงานเป็น error ชัดเจน
ถ: ใช้เขียน selector สำหรับ React, Vue หรือ testing framework ได้ไหม?
ตอบ: ได้ class และ attribute selector ที่คุณตรวจสอบที่นี่คือชุดเดียวกับที่ querySelector และ locator ของ testing framework ใช้ เพียงจำไว้ว่า node ที่ถูก inject แบบ dynamic จะปรากฏก็ต่อเมื่อมันอยู่ใน markup ที่ paste เข้ามา จึงควร render state ที่ต้องการ target ก่อนคัดลอก
ถ: ทำไม selector ที่ดูถูกต้องถึง match ไม่เจออะไรเลย?
ตอบ: สาเหตุที่พบบ่อยคือ child combinator ทั้งที่การซ้อนเป็นแบบทางอ้อม, class ที่ JavaScript เติมให้หลังจาก snapshot, ความต่างที่มองไม่เห็นในค่า attribute หรือ element ที่อยู่ใน shadow root เริ่มจาก selector แบบกว้างแล้วเติมเงื่อนไขทีละอย่างพร้อมดู match count ไปด้วย
ถ: มีขีดจำกัดขนาด HTML หรือไม่?
ตอบ: ไม่มีขีดจำกัดการอัปโหลดเพราะไม่มีอะไรถูกอัปโหลด ข้อจำกัดจริงคือหน่วยความจำของแท็บเบราว์เซอร์ ชิ้นส่วนหน้าเว็บตามโลกความจริงและเอกสารเต็ม ๆ ส่วนใหญ่รันได้สบาย แต่ไฟล์ดัมป์ขนาดหลายเมกะไบต์อาจทำให้ live highlighting ช้าลง