ภาพรวมพื้นฐานเกี่ยวกับวิธีสร้างคอมโพเนนต์การตั้งค่าของแถบเลื่อนและช่องทำเครื่องหมาย
ในโพสต์นี้ ฉันต้องการแชร์แนวคิดเกี่ยวกับการสร้างคอมโพเนนต์การตั้งค่าสำหรับเว็บที่ปรับเปลี่ยนตามอุปกรณ์ รองรับอินพุตอุปกรณ์หลายรายการ และทำงานในเบราว์เซอร์ต่างๆ ได้ ลองใช้เดโม
หากคุณชอบดูวิดีโอหรือต้องการดูตัวอย่าง UI/UX ของสิ่งที่เรากำลังสร้าง โปรดดูคำแนะนำสั้นๆ บน YouTube
ภาพรวม
เราได้แบ่งแง่มุมต่างๆ ขององค์ประกอบนี้ออกเป็นส่วนๆ ดังนี้
- เลย์เอาต์
- สี
- อินพุตช่วงที่กำหนดเอง
- อินพุตช่องทำเครื่องหมายที่กำหนดเอง
- ข้อควรพิจารณาเกี่ยวกับการช่วยเหลือพิเศษ
- JavaScript
เลย์เอาต์
นี่คือการสาธิต GUI Challenge ครั้งแรกที่เป็น CSS Grid ทั้งหมด ตารางกริดแต่ละรายการที่ไฮไลต์ด้วยเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome สำหรับตารางกริดมีดังนี้

Just for gap
เลย์เอาต์ที่พบบ่อยที่สุดมีดังนี้
foo {
display: grid;
gap: var(--something);
}
ฉันเรียกเลย์เอาต์นี้ว่า "just for gap" เพราะใช้ตารางกริดเพื่อเพิ่มช่องว่างระหว่างบล็อกเท่านั้น
เลย์เอาต์ 5 แบบใช้กลยุทธ์นี้ โดยเลย์เอาต์ทั้งหมดจะแสดงดังนี้

องค์ประกอบ fieldset ซึ่งมีกลุ่มอินพุตแต่ละกลุ่ม (.fieldset-item) ใช้ gap: 1px เพื่อสร้างเส้นขอบบางๆ ระหว่างองค์ประกอบ ไม่ต้องแก้ปัญหาเรื่องชายแดนที่ซับซ้อน
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
การตัดบรรทัดตารางกริดแบบเป็นธรรมชาติ
เลย์เอาต์ที่ซับซ้อนที่สุดคือเลย์เอาต์มาโคร ซึ่งเป็นระบบเลย์เอาต์เชิงตรรกะระหว่าง <main> ถึง <form>
การจัดเนื้อหาที่ตัดขึ้นบรรทัดใหม่ให้อยู่กึ่งกลาง
ทั้ง Flexbox และ Grid มีความสามารถในการalign-itemsหรือalign-content และเมื่อจัดการกับองค์ประกอบที่ตัดขึ้นบรรทัดใหม่ การจัดแนวเลย์เอาต์ content จะกระจายพื้นที่ว่างระหว่างองค์ประกอบย่อยเป็นกลุ่ม
main {
display: grid;
gap: var(--space-xl);
place-content: center;
}
องค์ประกอบหลักใช้place-content: center ชวเลขการจัดแนวเพื่อให้องค์ประกอบย่อยอยู่ตรงกลางในแนวตั้งและแนวนอนทั้งในเลย์เอาต์แบบ 1 และ 2 คอลัมน์
ดูวิดีโอด้านบนเพื่อดูว่า "เนื้อหา" ยังคงอยู่ตรงกลางแม้ว่าจะมีการตัดบรรทัดก็ตาม
ทำซ้ำ minmax ของการปรับพอดีอัตโนมัติ
<form> ใช้เลย์เอาต์ตารางกริดแบบปรับเปลี่ยนได้สำหรับแต่ละส่วน
เลย์เอาต์นี้จะเปลี่ยนจาก 1 คอลัมน์เป็น 2 คอลัมน์ตามพื้นที่ว่างที่มีอยู่
form {
display: grid;
gap: var(--space-xl) var(--space-xxl);
grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
align-items: flex-start;
max-width: 89vw;
}
ตารางกริดนี้มีค่าสำหรับ row-gap (--space-xl) แตกต่างจาก column-gap (--space-xxl) เพื่อเพิ่มความเฉพาะตัวให้กับเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์ เมื่อคอลัมน์ซ้อนกัน เราต้องการช่องว่างขนาดใหญ่ แต่ไม่ใหญ่เท่ากับตอนที่อยู่บนหน้าจอกว้าง
พร็อพเพอร์ตี้ grid-template-columns ใช้ฟังก์ชัน CSS 3 ฟังก์ชัน ได้แก่ repeat(), minmax() และ min() Una Kravets มีบล็อกโพสต์เกี่ยวกับเลย์เอาต์ที่ยอดเยี่ยมในเรื่องนี้ โดยเรียกว่า RAM
เลย์เอาต์ของเรามีส่วนเพิ่มเติมพิเศษ 3 ส่วนเมื่อเทียบกับของ Una
- เราส่งฟังก์ชัน
min()เพิ่มเติม - เราจะระบุ
align-items: flex-start - มีสไตล์
max-width: 89vw
Evan Minto ได้อธิบายฟังก์ชัน min() เพิ่มเติมไว้อย่างดีในบล็อกของเขาในโพสต์ Intrinsically Responsive CSS Grid with minmax() and min()
เราขอแนะนำให้อ่านโพสต์ดังกล่าว การแก้ไขการจัดแนว flex-start คือการนำเอฟเฟกต์การยืดเริ่มต้นออก เพื่อให้องค์ประกอบย่อยของเลย์เอาต์นี้ไม่จำเป็นต้องมีความสูงเท่ากัน แต่สามารถมีความสูงตามธรรมชาติและตามจริงได้ วิดีโอ YouTube มีรายละเอียดสั้นๆ เกี่ยวกับการเพิ่มการจัดแนวนี้
max-width: 89vw เป็นเรื่องที่ควรค่าแก่การอธิบายสั้นๆ ในโพสต์นี้
เราจะแสดงเลย์เอาต์ที่มีและไม่มีการใช้สไตล์ให้ดู
บอกว่าคุณกำลังคิดอะไรอยู่ เมื่อระบุ max-width จะเป็นการให้บริบท การกำหนดขนาดที่ชัดเจน หรือการกำหนดขนาดที่แน่นอนสำหรับอัลกอริทึมเลย์เอาต์ auto-fit เพื่อให้ทราบจำนวนการทำซ้ำที่สามารถใส่ลงในพื้นที่ได้ แม้ว่าพื้นที่ดังกล่าวจะดูเหมือน "เต็มความกว้าง" แต่ตามข้อกำหนดของตารางกริด CSS คุณต้องระบุขนาดที่แน่นอนหรือขนาดสูงสุด ฉันได้ระบุขนาดสูงสุดแล้ว
แล้วทำไมต้องเป็น 89vw เพราะ "มันใช้ได้" กับเลย์เอาต์ของฉัน
เราและทีม Chrome กำลังตรวจสอบว่าเหตุใดค่าที่สมเหตุสมผลกว่า เช่น 100vw จึงไม่เพียงพอ และปัญหานี้เป็นข้อบกพร่องจริงหรือไม่
การเว้นวรรค
ความกลมกลืนส่วนใหญ่ของเลย์เอาต์นี้มาจากระยะห่างที่จำกัด ซึ่งก็คือ 7 ระยะห่าง
:root {
--space-xxs: .25rem;
--space-xs: .5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
--space-xxl: 6rem;
}
การใช้งานเหล่านี้เข้ากันได้ดีกับ Grid, CSS @nest และไวยากรณ์ระดับ 5 ของ @media ตัวอย่างเช่น ชุดสไตล์เลย์เอาต์ <main> ที่สมบูรณ์
main {
display: grid;
gap: var(--space-xl);
place-content: center;
padding: var(--space-sm);
@media (width >= 540px) {
& {
padding: var(--space-lg);
}
}
@media (width >= 800px) {
& {
padding: var(--space-xl);
}
}
}
ตารางกริดที่มีเนื้อหาอยู่ตรงกลาง โดยมีการเว้นระยะห่างจากขอบปานกลางโดยค่าเริ่มต้น (เช่น บนอุปกรณ์เคลื่อนที่) แต่เมื่อมีพื้นที่วิวพอร์ตมากขึ้น ก็จะกระจายออกโดยเพิ่มระยะห่างจากขอบ CSS ปี 2021 ดูดีมาก
จำเลย์เอาต์ก่อนหน้านี้ที่ "ใช้เพื่อเว้นช่องว่างเท่านั้น" ได้ไหม ต่อไปนี้เป็นเวอร์ชันที่สมบูรณ์ยิ่งขึ้นของลักษณะที่ปรากฏในคอมโพเนนต์นี้
header {
display: grid;
gap: var(--space-xxs);
}
section {
display: grid;
gap: var(--space-md);
}
สี
การใช้สีอย่างควบคุมได้ช่วยให้การออกแบบนี้โดดเด่นในด้านการแสดงออกแต่ก็ยังคงความเรียบง่าย ฉันทำแบบนี้
:root {
--surface1: lch(10 0 0);
--surface2: lch(15 0 0);
--surface3: lch(20 0 0);
--surface4: lch(25 0 0);
--text1: lch(95 0 0);
--text2: lch(75 0 0);
}
ฉันตั้งชื่อสีพื้นผิวและสีข้อความเป็นตัวเลขแทนชื่ออย่าง surface-dark และ surface-darker เพราะในการค้นหาสื่อ ฉันจะสลับสี และสีอ่อนและสีเข้มจะไม่มีความหมาย
ฉันจะสลับค่าในคิวรีสื่อค่ากำหนดดังนี้
:root {
...
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--surface2: lch(100 0 0);
--surface3: lch(98 0 0);
--surface4: lch(85 0 0);
--text1: lch(20 0 0);
--text2: lch(40 0 0);
}
}
}
สิ่งสำคัญคือต้องดูภาพรวมและกลยุทธ์โดยรวมอย่างรวดเร็วก่อนที่เราจะเจาะลึกรายละเอียดไวยากรณ์สี แต่ก่อนจะไปไกลกว่านี้ เราขอย้อนกลับไปสักนิด
LCH?
โดยไม่ต้องลงลึกถึงทฤษฎีสีมากนัก LCH เป็นไวยากรณ์ที่เน้นมนุษย์เป็นหลัก ซึ่งตอบสนองต่อวิธีที่เรารับรู้สี ไม่ใช่วิธีที่เราวัดสีด้วยคณิตศาสตร์ (เช่น 255) ซึ่งทำให้มีข้อได้เปรียบที่ชัดเจน เนื่องจากมนุษย์สามารถเขียนได้ง่ายกว่าและมนุษย์คนอื่นๆ จะเข้าใจการปรับเปลี่ยนเหล่านี้
สำหรับวันนี้ ในการสาธิตนี้ เราจะเน้นที่ไวยากรณ์และค่าที่ฉันกำลังสลับเพื่อสร้างโหมดสว่างและมืด มาดูพื้นผิว 1 รายการและสีข้อความ 1 สีกัน
:root {
--surface1: lch(10 0 0);
--text1: lch(95 0 0);
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--text1: lch(40 0 0);
}
}
}
--surface1: lch(10 0 0) แปลงเป็นความสว่าง 10%, โครมา 0 และสี 0: สีเทาเข้มมากที่ไม่มีสี จากนั้นในคิวรีสื่อสำหรับโหมดสว่าง ความสว่าง
จะเปลี่ยนเป็น 90% โดยมี --surface1: lch(90 0 0); และนั่นคือสาระสำคัญของกลยุทธ์นี้ เริ่มด้วยการเปลี่ยนความสว่างระหว่าง 2 ธีม โดยคงอัตราส่วนคอนทราสต์ที่การออกแบบต้องการหรือสิ่งที่สามารถรักษาการช่วยเหลือพิเศษไว้ได้
ข้อดีของ lch() ในที่นี้คือความสว่างเป็นสิ่งที่มนุษย์รับรู้ได้ และเราจะรู้สึก
ดีกับการเปลี่ยนแปลง % ของความสว่าง ซึ่งจะแตกต่างจากเดิม % อย่างสม่ำเสมอ
และรับรู้ได้ hsl() เช่น ไม่น่าเชื่อถือเท่า
ยังมีข้อมูลเพิ่มเติมให้เรียนรู้เกี่ยวกับขอบเขตสีและ lch() หากคุณสนใจ มาแล้ว!
ตอนนี้ CSS ไม่สามารถเข้าถึงสีเหล่านี้ได้เลย ขอย้ำอีกครั้งว่าเราไม่สามารถเข้าถึง 1 ใน 3 ของสีในจอภาพสมัยใหม่ส่วนใหญ่ได้ และสีเหล่านี้ไม่ใช่แค่สีธรรมดา แต่เป็นสีที่สดใสที่สุดที่หน้าจอสามารถแสดงได้ เว็บไซต์ของเรามีสีซีดเนื่องจากฮาร์ดแวร์ของจอภาพพัฒนาเร็วกว่าข้อกำหนด CSS และการใช้งานเบราว์เซอร์
Lea Verou
การควบคุมแบบฟอร์มที่ปรับเปลี่ยนได้ด้วยรูปแบบสี
เบราว์เซอร์หลายตัวมีตัวควบคุมธีมมืด ซึ่งปัจจุบันคือ Safari และ Chromium แต่คุณต้องระบุใน CSS หรือ HTML ว่าการออกแบบของคุณใช้ธีมมืด
ตัวอย่างด้านบนแสดงผลลัพธ์ของพร็อพเพอร์ตี้จากแผงสไตล์ของเครื่องมือสำหรับนักพัฒนาเว็บ การสาธิตใช้แท็ก HTML ซึ่งในความเห็นของฉันมักจะเป็นตำแหน่งที่ดีกว่า
<meta name="color-scheme" content="dark light">
ดูข้อมูลทั้งหมดได้ในcolor-schemeบทความนี้โดย Thomas Steiner ยังมีอะไรให้คุณได้มากกว่า
การป้อนข้อมูลในช่องทำเครื่องหมายสีเข้ม
CSS accent-color
เมื่อเร็วๆ นี้มีกิจกรรมเกี่ยวกับ accent-color ในองค์ประกอบของแบบฟอร์ม ซึ่งเป็นรูปแบบ CSS เดียวที่สามารถเปลี่ยนสีที่ใช้ในองค์ประกอบอินพุตของเบราว์เซอร์ได้ อ่านข้อมูลเพิ่มเติมได้ที่นี่ใน GitHub ฉันได้รวมไว้ในสไตล์ของฉัน
สำหรับคอมโพเนนต์นี้แล้ว เนื่องจากเบราว์เซอร์รองรับ ช่องทำเครื่องหมายของฉันจึงจะเข้ากับธีมมากขึ้นด้วยป๊อปสีชมพูและสีม่วง
input[type="checkbox"] {
accent-color: var(--brand);
}

ป๊อปสีที่มีการไล่ระดับสีแบบคงที่และโฟกัสภายใน
สีจะโดดเด่นที่สุดเมื่อใช้ในปริมาณที่พอเหมาะ และวิธีหนึ่งที่ฉันชอบใช้เพื่อให้ได้ผลลัพธ์ดังกล่าวคือการโต้ตอบกับ UI ที่มีสีสัน
มีฟีดแบ็กและการโต้ตอบของ UI หลายชั้นในวิดีโอด้านบน ซึ่งช่วยสร้างบุคลิกให้กับการโต้ตอบโดยทำดังนี้
- ไฮไลต์บริบท
- แสดงความคิดเห็นเกี่ยวกับ UI ของ "ความเต็ม" ของค่าในช่วง
- การแสดงความคิดเห็นเกี่ยวกับ UI ว่าช่องยอมรับอินพุต
CSS จะใช้คลาสจำลอง :focus-within เพื่อแสดงความคิดเห็นเมื่อมีการโต้ตอบกับองค์ประกอบหนึ่งๆ เพื่อเปลี่ยนลักษณะที่ปรากฏขององค์ประกอบต่างๆ มาดูรายละเอียดของ .fieldset-item กัน ซึ่งน่าสนใจมาก
.fieldset-item {
...
&:focus-within {
background: var(--surface2);
& svg {
fill: white;
}
& picture {
clip-path: circle(50%);
background: var(--brand-bg-gradient) fixed;
}
}
}
เมื่อองค์ประกอบย่อยรายการใดรายการหนึ่งขององค์ประกอบนี้มี focus-within:
- พื้นหลัง
.fieldset-itemจะได้รับการกำหนดสีพื้นผิวที่มีคอนทราสต์สูงกว่า svgที่ฝังอยู่จะเติมสีขาวเพื่อให้มีคอนทราสต์สูงขึ้น<picture>clip-pathที่ซ้อนกันจะขยายเป็นวงกลมเต็มวงและพื้นหลังจะเต็มไปด้วยการไล่ระดับสีแบบคงที่ที่สว่าง
ช่วงที่กำหนดเอง
จากองค์ประกอบอินพุต HTML ต่อไปนี้ เราจะแสดงวิธีปรับแต่งลักษณะที่ปรากฏ
<input type="range">
องค์ประกอบนี้มี 3 ส่วนที่เราต้องปรับแต่ง ได้แก่
รูปแบบองค์ประกอบช่วง
input[type="range"] {
/* style setting variables */
--track-height: .5ex;
--track-fill: 0%;
--thumb-size: 3ex;
--thumb-offset: -1.25ex;
--thumb-highlight-size: 0px;
appearance: none; /* clear styles, make way for mine */
display: block;
inline-size: 100%; /* fill container */
margin: 1ex 0; /* ensure thumb isn't colliding with sibling content */
background: transparent; /* bg is in the track */
outline-offset: 5px; /* focus styles have space */
}
CSS 2-3 บรรทัดแรกเป็นส่วนที่กำหนดเองของรูปแบบ และเราหวังว่าการติดป้ายกำกับอย่างชัดเจนจะช่วยได้ รูปแบบที่เหลือส่วนใหญ่เป็นรูปแบบการรีเซ็ต เพื่อให้มีรากฐานที่สอดคล้องกันสำหรับการสร้างส่วนที่ยุ่งยากของคอมโพเนนต์
ติดตามสไตล์
input[type="range"]::-webkit-slider-runnable-track {
appearance: none; /* clear styles, make way for mine */
block-size: var(--track-height);
border-radius: 5ex;
background:
/* hard stop gradient:
- half transparent (where colorful fill we be)
- half dark track fill
- 1st background image is on top
*/
linear-gradient(
to right,
transparent var(--track-fill),
var(--surface1) 0%
),
/* colorful fill effect, behind track surface fill */
var(--brand-bg-gradient) fixed;
}
เคล็ดลับของวิธีนี้คือการ "เปิดเผย" สีเติมที่สดใส ซึ่งทำได้โดยใช้การไล่ระดับสีแบบ Hard Stop ที่ด้านบน การไล่ระดับสีจะโปร่งใสจนถึงเปอร์เซ็นต์การเติม และหลังจากนั้นจะใช้สีพื้นผิวแทร็กที่ไม่ได้เติม ด้านหลังพื้นผิวที่ไม่มีสีนั้นคือสีแบบเต็มความกว้างที่รอให้ความโปร่งใสเผยออกมา
รูปแบบการเติมพื้นแทร็ก
การออกแบบของฉันต้องใช้ JavaScript เพื่อรักษารูปแบบการเติม มีกลยุทธ์ที่ใช้ CSS เท่านั้น แต่ต้องใช้องค์ประกอบ Thumb ที่มีความสูงเท่ากับแทร็ก และฉันไม่สามารถค้นหาความสอดคล้องกันภายในขีดจำกัดเหล่านั้นได้
/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')
/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
const max = slider.getAttribute('max') || 10;
const percent = slider.value / max * 100;
return `${parseInt(percent)}%`;
};
/* on page load, set the fill amount */
sliders.forEach(slider => {
slider.style.setProperty('--track-fill', rangeToPercent(slider));
/* when a slider changes, update the fill prop */
slider.addEventListener('input', e => {
e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
})
})
เราคิดว่าการอัปเกรดนี้จะช่วยให้ภาพดูดีขึ้น แถบเลื่อนทำงานได้ดีโดยไม่ต้องใช้ JavaScript, ไม่จำเป็นต้องใช้พร็อพเพอร์ตี้ --track-fill และจะไม่มีสไตล์การเติมหากไม่มีพร็อพเพอร์ตี้ดังกล่าว หาก JavaScript พร้อมใช้งาน ให้ป้อนข้อมูลคุณสมบัติที่กำหนดเองพร้อมกับสังเกตการเปลี่ยนแปลงของผู้ใช้ โดยซิงค์คุณสมบัติที่กำหนดเองกับค่า
โพสต์ที่ยอดเยี่ยมใน CSS-Tricks โดย Ana Tudor แสดงให้เห็นถึงโซลูชัน CSS เท่านั้นสำหรับการเติมแทร็ก ฉันยังพบว่าองค์ประกอบ range นี้สร้างแรงบันดาลใจได้ดีมาก
รูปแบบ Thumb
input[type="range"]::-webkit-slider-thumb {
appearance: none; /* clear styles, make way for mine */
cursor: ew-resize; /* cursor style to support drag direction */
border: 3px solid var(--surface3);
block-size: var(--thumb-size);
inline-size: var(--thumb-size);
margin-top: var(--thumb-offset);
border-radius: 50%;
background: var(--brand-bg-gradient) fixed;
}
สไตล์ส่วนใหญ่เหล่านี้มีไว้เพื่อสร้างวงกลมที่สวยงาม
คุณจะเห็นการไล่ระดับสีพื้นหลังคงที่ซึ่งรวมสีแบบไดนามิกของปุ่มเลื่อน แทร็ก และองค์ประกอบ SVG ที่เกี่ยวข้องเข้าด้วยกัน
ฉันแยกสไตล์สำหรับการโต้ตอบเพื่อช่วยแยกเทคนิค box-shadow ที่ใช้สำหรับไฮไลต์เมื่อวางเมาส์เหนือองค์ประกอบ
@custom-media --motionOK (prefers-reduced-motion: no-preference);
::-webkit-slider-thumb {
…
/* shadow spread is initally 0 */
box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
/* if motion is OK, transition the box-shadow change */
@media (--motionOK) {
& {
transition: box-shadow .1s ease;
}
}
/* on hover/active state of parent, increase size prop */
@nest input[type="range"]:is(:hover,:active) & {
--thumb-highlight-size: 10px;
}
}
เป้าหมายคือการสร้างไฮไลต์ภาพเคลื่อนไหวที่จัดการได้ง่ายสำหรับความคิดเห็นของผู้ใช้ การใช้เงาของกล่องช่วยให้ฉันหลีกเลี่ยงการทริกเกอร์เลย์เอาต์ด้วยเอฟเฟกต์ได้ ฉันทำเช่นนี้โดยสร้างเงาที่ไม่เบลอและตรงกับรูปทรงกลมขององค์ประกอบ Thumb จากนั้นฉันจะเปลี่ยนและเปลี่ยนขนาดการกระจายเมื่อวางเมาส์เหนือ
ถ้าเอฟเฟกต์ไฮไลต์ทำได้ง่ายๆ ในช่องทำเครื่องหมายก็คงดี…
ตัวเลือกข้ามเบราว์เซอร์
ฉันพบว่าฉันต้องใช้ตัวเลือก -webkit- และ -moz- เหล่านี้เพื่อให้ได้ความสอดคล้องกันในเบราว์เซอร์ต่างๆ:
input[type="range"] {
&::-webkit-slider-runnable-track {}
&::-moz-range-track {}
&::-webkit-slider-thumb {}
&::-moz-range-thumb {}
}
ช่องทำเครื่องหมายที่กำหนดเอง
จากองค์ประกอบอินพุต HTML ต่อไปนี้ เราจะแสดงวิธีปรับแต่งลักษณะที่ปรากฏ
<input type="checkbox">
องค์ประกอบนี้มี 3 ส่วนที่เราต้องปรับแต่ง ได้แก่
องค์ประกอบช่องทำเครื่องหมาย
input[type="checkbox"] {
inline-size: var(--space-sm); /* increase width */
block-size: var(--space-sm); /* increase height */
outline-offset: 5px; /* focus style enhancement */
accent-color: var(--brand); /* tint the input */
position: relative; /* prepare for an absolute pseudo element */
transform-style: preserve-3d; /* create a 3d z-space stacking context */
margin: 0;
cursor: pointer;
}
สไตล์ transform-style และ position จะเตรียมพร้อมสำหรับองค์ประกอบเทียมที่เราจะแนะนำในภายหลังเพื่อจัดสไตล์ไฮไลต์ นอกเหนือจากนั้น ส่วนใหญ่จะเป็นเรื่องสไตล์เล็กๆ น้อยๆ ที่เป็นความคิดเห็นของฉันเอง ฉันชอบให้เคอร์เซอร์เป็นตัวชี้ ชอบการออฟเซ็ตเส้นขอบ ช่องทำเครื่องหมายเริ่มต้นมีขนาดเล็กเกินไป และหากรองรับ accent-color ให้นำช่องทำเครื่องหมายเหล่านี้มาไว้ในรูปแบบสีของแบรนด์
ป้ายกำกับช่องทำเครื่องหมาย
การระบุป้ายกำกับสำหรับช่องทำเครื่องหมายมีความสำคัญด้วยเหตุผล 2 ประการ ส่วนแรกคือการแสดงให้เห็นว่าค่าของช่องทำเครื่องหมายใช้ทำอะไร เพื่อตอบคำถามว่า "เปิดหรือปิดสำหรับอะไร" ประการที่ 2 คือเพื่อ UX ผู้ใช้เว็บคุ้นเคยกับการโต้ตอบกับช่องทำเครื่องหมายผ่านป้ายกำกับที่เกี่ยวข้อง
<input type="checkbox" id="text-notifications" name="text-notifications" >
<label for="text-notifications"> <h3>Text Messages</h3> <small>Get notified about all text messages sent to your device</small> </label>
ในป้ายกำกับ ให้ใส่แอตทริบิวต์ for ที่ชี้ไปยังช่องทำเครื่องหมายตามรหัส: <label for="text-notifications"> ในช่องทำเครื่องหมาย ให้ใส่ทั้งชื่อและรหัสซ้ำเพื่อให้แน่ใจว่าเครื่องมือและเทคโนโลยีต่างๆ เช่น เมาส์หรือโปรแกรมอ่านหน้าจอ จะค้นหาช่องทำเครื่องหมายนั้นได้
<input type="checkbox" id="text-notifications" name="text-notifications">
:hover, :active และอื่นๆ จะมาพร้อมกับการเชื่อมต่อโดยไม่มีค่าใช้จ่าย ซึ่งจะเพิ่มวิธีที่ผู้ใช้โต้ตอบกับแบบฟอร์มของคุณได้
ไฮไลต์ช่องทำเครื่องหมาย
ฉันต้องการให้อินเทอร์เฟซสอดคล้องกัน และองค์ประกอบแถบเลื่อนมีไฮไลต์ภาพขนาดย่อที่สวยงามซึ่งฉันต้องการใช้กับช่องทำเครื่องหมาย ภาพขนาดย่อสามารถใช้ box-shadow และพร็อพเพอร์ตี้ spread เพื่อปรับขนาดเงาขึ้นและลงได้ อย่างไรก็ตาม เอฟเฟกต์นั้นใช้ไม่ได้ที่นี่เนื่องจากช่องทำเครื่องหมายของเราเป็นสี่เหลี่ยมจัตุรัสและควรเป็นเช่นนั้น
ฉันสร้างเอฟเฟกต์ภาพแบบเดียวกันได้ด้วยองค์ประกอบจำลองและ CSS ที่ซับซ้อนจำนวนมาก
@custom-media --motionOK (prefers-reduced-motion: no-preference);
input[type="checkbox"]::before {
--thumb-scale: .01; /* initial scale of highlight */
--thumb-highlight-size: var(--space-xl);
content: "";
inline-size: var(--thumb-highlight-size);
block-size: var(--thumb-highlight-size);
clip-path: circle(50%); /* circle shape */
position: absolute; /* this is why position relative on parent */
top: 50%; /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
left: 50%;
background: var(--thumb-highlight-color);
transform-origin: center center; /* goal is a centered scaling circle */
transform: /* order here matters!! */
translateX(-50%) /* counter balances left: 50% */
translateY(-50%) /* counter balances top: 50% */
translateZ(-1px) /* PUTS IT BEHIND THE CHECKBOX */
scale(var(--thumb-scale)) /* value we toggle for animation */
;
will-change: transform;
@media (--motionOK) { /* transition only if motion is OK */
& {
transition: transform .2s ease;
}
}
}
/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
--thumb-scale: 1;
}
การสร้างองค์ประกอบเทียมวงกลมเป็นงานที่ตรงไปตรงมา แต่การวางไว้ด้านหลังองค์ประกอบที่แนบมานั้นทำได้ยากกว่า นี่คือภาพก่อนและหลังที่ฉันแก้ไข
แม้จะเป็นการโต้ตอบเล็กๆ น้อยๆ แต่ก็สำคัญสำหรับฉันในการรักษาความสอดคล้องของภาพ เทคนิคการปรับขนาดภาพเคลื่อนไหวเป็นเทคนิคเดียวกับที่เราใช้ในที่อื่นๆ เราตั้งค่าคุณสมบัติที่กำหนดเองเป็นค่าใหม่และให้ CSS เปลี่ยนแปลงค่าตามค่ากำหนดการเคลื่อนไหว ฟีเจอร์หลักในที่นี้คือ translateZ(-1px) องค์ประกอบหลักสร้างพื้นที่ 3 มิติ และองค์ประกอบย่อยเทียมนี้ก็เข้าไปอยู่ในพื้นที่นั้นโดยวางตัวเองไว้ด้านหลังเล็กน้อยในพื้นที่แกน Z
การช่วยเหลือพิเศษ
วิดีโอ YouTube แสดงการสาธิตการโต้ตอบของเมาส์ แป้นพิมพ์ และโปรแกรมอ่านหน้าจอสำหรับคอมโพเนนต์การตั้งค่านี้ได้อย่างดีเยี่ยม เราจะอธิบายรายละเอียดบางส่วนที่นี่
ตัวเลือกองค์ประกอบ HTML
<form>
<header>
<fieldset>
<picture>
<label>
<input>
ซึ่งแต่ละรายการจะมีคำแนะนำและเคล็ดลับสำหรับเครื่องมือการท่องเว็บของผู้ใช้ องค์ประกอบบางอย่างให้คำแนะนำในการโต้ตอบ บางองค์ประกอบเชื่อมต่อการโต้ตอบ และบางองค์ประกอบช่วยกำหนดรูปร่างของแผนผังการช่วยเหลือพิเศษที่โปรแกรมอ่านหน้าจอใช้ไปยังส่วนต่างๆ
แอตทริบิวต์ HTML
เราสามารถซ่อนองค์ประกอบที่โปรแกรมอ่านหน้าจอไม่จำเป็นต้องใช้ได้ ซึ่งในกรณีนี้คือไอคอนข้างแถบเลื่อน
<picture aria-hidden="true">
วิดีโอด้านบนแสดงขั้นตอนการใช้โปรแกรมอ่านหน้าจอใน Mac OS สังเกตว่าโฟกัสอินพุตย้ายจากแถบเลื่อนหนึ่งไปยังแถบเลื่อนถัดไปโดยตรงอย่างไร เนื่องจากเราได้ซ่อนไอคอนที่อาจเป็นจุดหยุดพักระหว่างทางไปยังแถบเลื่อนถัดไป หากไม่มีแอตทริบิวต์นี้ ผู้ใช้จะต้องหยุด ฟัง และข้ามรูปภาพที่อาจมองไม่เห็น
SVG เป็นชุดคณิตศาสตร์ ลองเพิ่มองค์ประกอบ <title> สำหรับชื่อที่แสดงเมื่อวางเมาส์เหนือองค์ประกอบและแสดงความคิดเห็นที่มนุษย์อ่านได้เกี่ยวกับสิ่งที่คณิตศาสตร์สร้างขึ้น
<svg viewBox="0 0 24 24">
<title>A note icon</title>
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>
นอกจากนี้ เรายังใช้ HTML ที่ทำเครื่องหมายไว้อย่างชัดเจนมากพอ เพื่อให้แบบฟอร์มทำงานได้ดีกับเมาส์ คีย์บอร์ด ตัวควบคุมวิดีโอเกม และโปรแกรมอ่านหน้าจอ
JavaScript
เราได้พูดถึงวิธีจัดการสีเติมของแทร็กจาก JavaScript ไปแล้ว ลองมาดู JavaScript ที่เกี่ยวข้องกับ <form> กัน
const form = document.querySelector('form');
form.addEventListener('input', event => {
const formData = Object.fromEntries(new FormData(form));
console.table(formData);
})
ทุกครั้งที่มีการโต้ตอบและเปลี่ยนแปลงแบบฟอร์ม คอนโซลจะบันทึกแบบฟอร์มเป็นออบเจ็กต์ลงในตารางเพื่อให้ตรวจสอบได้ง่ายก่อนส่งไปยังเซิร์ฟเวอร์

บทสรุป
ตอนนี้คุณก็รู้แล้วว่าเราทำยังไง แล้วคุณล่ะจะทำยังไง ซึ่งทำให้สถาปัตยกรรมคอมโพเนนต์ มีความสนุกสนาน ใครจะเป็นคนสร้างเวอร์ชันแรกที่มีช่องในเฟรมเวิร์กที่ตนเองชื่นชอบ 🙂
มาลองใช้วิธีการที่หลากหลายและเรียนรู้วิธีทั้งหมดในการสร้างบนเว็บกัน สร้างเดโม ทวีตลิงก์มาหาฉัน แล้วฉันจะเพิ่มลงในส่วนรีมิกซ์ของชุมชนด้านล่าง
รีมิกซ์ของชุมชน
- @tomayac สำหรับสไตล์ของพื้นที่วางเมาส์เหนือป้ายกำกับช่องทำเครื่องหมาย เวอร์ชันนี้ไม่มีช่องว่างระหว่างองค์ประกอบเมื่อวางเมาส์เหนือองค์ประกอบ: เดโมและแหล่งที่มา