พร็อพเพอร์ตี้ CSS appearance: base-select ปลดล็อกความสามารถในการจัดรูปแบบองค์ประกอบ <select> และเครื่องมือเลือก (ผ่าน ::picker(select)) เช่นเดียวกับองค์ประกอบ HTML ทั่วไป
เมื่อใช้ร่วมกับเทคนิคเลย์เอาต์ CSS สมัยใหม่ เช่น Grid หรือ Flexbox คุณจะหลุดพ้นจากรายการแนวตั้งแบบซ้อนกันแบบเดิมๆ และสร้างประสบการณ์การใช้งานภาพที่สมบูรณ์ได้โดยไม่ต้องใช้ JS ที่กำหนดเอง
เช่น คุณสามารถใช้ display: grid เพื่อจัดสไตล์ตัวเลือกเป็นตารางกริด 2 มิติของการ์ด
ซึ่งเหมาะสำหรับตัวเลือกสี ตัวเลือกอีโมจิ หรือสินค้าย่อยที่เมนูภาพที่สมบูรณ์มีประสิทธิภาพมากกว่ารายการ
วิธีการนำไปใช้งาน
1. เปิดใช้งานการจัดรูปแบบพื้นฐาน
ใช้ appearance: base-select กับทั้งองค์ประกอบ <select> และองค์ประกอบเทียมของเครื่องมือเลือกภายใน select::picker(select) ดังนี้
select.grid-picker {
&, &::picker(select) {
appearance: base-select;
}
}
2. จัดสไตล์คอนเทนเนอร์เครื่องมือเลือก
กำหนดเป้าหมาย select:open::picker(select) และใช้ display: grid (หรือ display: flex)
กำหนดคอลัมน์และช่องว่างเช่นเดียวกับที่ทำกับคอนเทนเนอร์อื่นๆ
select.grid-picker:open::picker(select) {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
สำคัญ: ต้องระบุ :open หากคุณจัดสไตล์ select::picker(select) จะทำให้เครื่องมือเลือกปรากฏขึ้นแม้ว่าการเลือกจะปิดอยู่ก็ตาม
3. จัดรูปแบบตัวเลือก
กำหนดเป้าหมายองค์ประกอบ <option> เพื่อจัดสไตล์เป็นรายการตารางกริดหรือการ์ด
คุณสามารถเพิ่มรูปภาพ, SVG หรือเลย์เอาต์ที่ซับซ้อนภายในองค์ประกอบเหล่านี้ได้
/* Style options as grid cards */
.grid-picker option {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
/* padding, border-radius, background, etc. */
}
4. จัดรูปแบบตัวเลือกที่เลือก
หากต้องการจัดรูปแบบตัวเลือกที่เลือก ให้ใช้ option:checked เช่น
.grid-picker option:checked {
position: relative;
border: 2px solid var(--primary-color);
background-color: oklab(from var(--primary-color) l a b / 8%);
}
เช่นเดียวกับตัวควบคุม UI อื่นๆ อย่าสื่อสารสถานะด้วยสีเพียงอย่างเดียว และใช้ตัวบ่งชี้ภาพหลายรายการ (เช่น สี ความหนาของเส้นขอบ เครื่องหมายถูก) เพื่อสื่อสารว่าเลือกตัวเลือกใด
5. (ไม่บังคับ) จัดรูปแบบเครื่องหมายถูกของตัวเลือกที่เลือก
โดยค่าเริ่มต้น เบราว์เซอร์จะแสดงผลเครื่องหมายถูกเป็นองค์ประกอบย่อยแรกของ <option> ทุกรายการ
โดยจะทำงานเหมือน ::before ที่มี content: "✓" / "" ซึ่งแสดงผลก่อน ::before ที่ผู้เขียนระบุไว้ (หากมี)
หากไม่ได้เลือกตัวเลือกนี้ ระบบจะซ่อนเครื่องหมายถูกผ่าน visibility: hidden
คุณสามารถจัดสไตล์โดยใช้องค์ประกอบจำลอง ::checkmark หรือซ่อนทั้งหมดหากต้องการสื่อถึงการเลือกผ่านการจัดสไตล์เพียงอย่างเดียวหรือใช้ตัวบ่งชี้ที่กำหนดเอง
เช่น หากต้องการวางไว้ที่มุมขวาบนของตัวเลือก คุณอาจทำดังนี้
select.grid-picker {
> option::checkmark {
/* Hide the checkmark for unselected options */
display: none;
}
> option:checked {
position: relative;
&::checkmark {
position: absolute;
inset-block-start: -.4em;
inset-inline-end: -.5em;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
min-inline-size: 1.6em;
aspect-ratio: 1;
padding-right: 0.12em;
padding-left: 0.05em;
border-radius: 50%;
background: var(--primary-color);
color: white;
font-size: 70%;
font-weight: bold;
}
}
}
เคล็ดลับ: เมื่อวาดคอนเทนเนอร์ (เช่น วงกลม) รอบเครื่องหมายถูก ให้ขยับขึ้นไปด้านบนเล็กน้อย (เหมือนที่เราทำที่นี่ด้วย padding-bottom และ padding-left) เพื่อให้เครื่องหมายถูกอยู่ตรงกลางตามหลักการมองเห็นซึ่งคำนึงถึงรูปร่างของเครื่องหมายถูก
อย่าใช้ padding-inline-start หรือ padding-block-end สำหรับกรณีนี้ เนื่องจากจะเปลี่ยนไปตามโหมดการเขียน ในขณะที่รูปร่างของเครื่องหมายถูกจะไม่เปลี่ยน
6. (ไม่บังคับ) ปรับแต่งการแสดงตัวเลือกที่เลือก
โดยค่าเริ่มต้น <select> จะแสดงตัวเลือกที่เลือกในเวอร์ชันข้อความเท่านั้น
หากต้องการแสดงข้อมูลอย่างละเอียดสำหรับค่าที่เลือก ให้ใช้ <selectedcontent> ภายใน <button> และ/หรือแสดงตัวเลือกที่เลือกแตกต่างออกไป (เช่น ซ่อนรายละเอียดบางอย่าง)
อย่าใช้ <selectedcontent> โดยไม่มี <button> ล้อมรอบ เนื่องจาก <selectedcontent> จะกลายเป็นส่วนหนึ่งของเครื่องมือเลือก เช่นเดียวกับองค์ประกอบเนื้อหาอื่นๆ
แนวทางปฏิบัติแนะนำ
- ทดสอบลักษณะการทำงานของเลย์เอาต์ การตั้งค่า
appearance: base-selectจะนำลักษณะการทำงานของเบราว์เซอร์เริ่มต้นในการปรับขนาดการเลือกตามความกว้างของตัวเลือกที่ยาวที่สุดออก คุณอาจต้องตั้งค่าความกว้างคงที่หรือใช้ข้อจำกัด Flex/Grid เพื่อป้องกันไม่ให้เลย์เอาต์เปลี่ยนแปลง - ตรวจสอบว่า
<select>มีแอตทริบิวต์nameและ<label>ที่เชื่อมโยงกัน ซึ่งจะช่วยให้มั่นใจได้ว่าแม้จะมี UI ที่กำหนดเอง คอมโพเนนต์จะยังคงเข้าถึงได้โดยโปรแกรมอ่านหน้าจอและทำงานได้อย่างถูกต้องกับการส่งแบบฟอร์มมาตรฐาน - ใช้แอตทริบิวต์
valueมาตรฐานในตัวเลือกเพื่อให้แน่ใจว่าการส่งแบบฟอร์มทำงานเหมือนเดิมทุกประการ
การช่วยเหลือพิเศษ
<select> แบบเนทีฟจะจัดการเฉพาะการไปยังส่วนต่างๆ ด้วยลูกศรขึ้น/ลงแบบเชิงเส้น ดังนั้นลูกศรซ้าย/ขวาจึงไม่ทำงานในเครื่องมือเลือกที่เปิดอยู่ และลูกศรขึ้น/ลงยังคงไปยังส่วนต่างๆ ของรายการตามลำดับ โดยไม่คำนึงถึงแถวและคอลัมน์
หากต้องการใช้การไปยังส่วนต่างๆ เชิงพื้นที่ที่สอดคล้องกับตารางกริด คุณสามารถสกัดกั้น keydown และกำหนดเส้นทางโฟกัสไปยังตัวเลือกที่ใกล้ที่สุดในทิศทางที่กด (เช่น ใช้ getBoundingClientRect()) เมื่อใช้แป้นลูกศร
หากต้องการระบุรายการถัดไป/ก่อนหน้าที่เหมาะสม ให้ใช้เมธอด DOM ที่ทำงานบนเรขาคณิตจริง (เช่น getBoundingClientRect()) แทนการแยกวิเคราะห์สตริง CSS เช่น grid-template-columns หรือ grid-column ซึ่งอาจไม่เสถียรและมีแนวโน้มที่จะเกิดข้อผิดพลาดสำหรับตารางกริดที่ซับซ้อน ตารางกริดย่อย, RTL และสถานการณ์เลย์เอาต์อื่นๆ
อย่างไรก็ตาม อย่าออกแบบมากเกินไปโดยไม่จำเป็น ให้ใช้ค่าคงที่ที่คุณทราบว่าเป็นจริงเกี่ยวกับเลย์เอาต์เพื่อลดความซับซ้อนของตรรกะนี้
หมายเหตุ: วิธีนี้จะแก้ปัญหาการไปยังส่วนต่างๆ ด้วยแป้นพิมพ์เท่านั้น <select> และ ::picker() ยังคงมีบทบาทเริ่มต้น (menu หรือ listbox) และไม่สามารถลบล้างบทบาทเหล่านี้ได้ และไม่อนุญาตให้มีองค์ประกอบที่มี role="grid"
การฝัง Wrapper ที่มี role="grid" ไว้ในเครื่องมือเลือกสามารถใช้งานได้จริง แต่ไม่ถูกต้อง และอาจทำให้ผู้ใช้ AT ประหลาดใจ
ในบางกรณี การใช้ <optgroup> เพื่อจัดกลุ่มตัวเลือกอาจสร้าง UX ของโปรแกรมอ่านหน้าจอที่ดีได้โดยไม่ต้องใช้ role="grid"
ไม่เช่นนั้น คุณอาจต้องเปลี่ยนไปใช้โซลูชันที่กำหนดเองโดยใช้ Popover API, การวางตำแหน่ง Anchor และ role="grid" เพื่อให้ได้ UX ที่ต้องการสำหรับผู้ใช้โปรแกรมอ่านหน้าจอ
กลยุทธ์สำรอง
การสนับสนุนเบราว์เซอร์และทางเลือกสำหรับ <select> ที่ปรับแต่งได้
สำหรับเบราว์เซอร์ที่ยังไม่รองรับ appearance: base-select องค์ประกอบ <select> จะลดระดับลงเป็นเมนูแบบเลื่อนลงของระบบปฏิบัติการมาตรฐานอย่างราบรื่น
- ละเว้นเนื้อหาที่ไม่ใช่ข้อความ: เบราว์เซอร์รุ่นเก่าจะตัดแท็ก HTML (เช่น
<svg>หรือ<div>) ภายในแท็ก<option>และแสดงผลเฉพาะโหนดข้อความ ตรวจสอบว่าเนื้อหาข้อความของ<option>อ่านได้และมีความหมายในตัวเอง - การจัดการโครงสร้าง HTML: โปรแกรมแยกวิเคราะห์มาตรฐานอาจละเว้นแท็ก
<button>และ<selectedcontent>ภายใน<select>หรือถือว่าแท็กดังกล่าวไม่ถูกต้อง ไม่จำเป็นต้องใช้ Polyfill ของ JavaScript ที่มีขนาดใหญ่สำหรับการเพิ่มประสิทธิภาพแบบต่อเนื่อง หากคุณมองว่าข้อความมาตรฐานเป็นทางเลือกสำรองที่อ่านได้
document.addEventListener("DOMContentLoaded", () => {
// Check if browser supports base-select value
if (!CSS.supports("appearance", "base-select")) {
// Custom select overrides are not supported natively.
}
});