การสร้างคอมโพเนนต์ปุ่ม

ภาพรวมพื้นฐานของวิธีสร้างคอมโพเนนต์ <button> ที่ปรับเปลี่ยนสี ปรับเปลี่ยนตามอุปกรณ์ และเข้าถึงง่าย

ในโพสต์นี้ผมอยากแชร์ความคิดเห็นเกี่ยวกับวิธีสร้างองค์ประกอบ <button> ที่ปรับเปลี่ยนสี ปรับเปลี่ยนตามอุปกรณ์ และเข้าถึงง่าย ลองใช้เดโมและดูแหล่งที่มา

ระบบจะโต้ตอบกับปุ่มผ่านแป้นพิมพ์และเมาส์ในธีมสว่างและมืด

หากชอบวิดีโอ นี่คือโพสต์นี้เวอร์ชัน YouTube

ภาพรวม

การสนับสนุนเบราว์เซอร์

  • 1
  • 12
  • 1
  • อย่างน้อย 4

แหล่งที่มา

องค์ประกอบ <button> สร้างขึ้นเพื่อการโต้ตอบของผู้ใช้ เหตุการณ์ click จะทริกเกอร์จากแป้นพิมพ์ เมาส์ การแตะ เสียง และอื่นๆ โดยใช้กฎอัจฉริยะเกี่ยวกับการกำหนดเวลา และยังมีสไตล์เริ่มต้นบางรูปแบบในแต่ละเบราว์เซอร์เพื่อให้คุณใช้งานได้โดยตรงโดยไม่ต้องปรับแต่งใดๆ ใช้ color-scheme เพื่อเลือกใช้ปุ่มไฟและปุ่มมืดที่เบราว์เซอร์มีให้

นอกจากนี้ยังมีปุ่มประเภทต่างๆ แต่ละประเภทที่แสดงในการฝัง Codepen ก่อนหน้านี้ <button> ที่ไม่มีประเภทจะปรับให้เข้ากับการอยู่ใน <form> และเปลี่ยนเป็นประเภทการส่ง

<!-- buttons -->
<button></button>
<button type="submit"></button>
<button type="button"></button>
<button type="reset"></button>

<!-- button state -->
<button disabled></button>

<!-- input buttons -->
<input type="button" />
<input type="file">

ในภารกิจ GUI ของเดือนนี้ ปุ่มแต่ละปุ่มจะมีรูปแบบที่ช่วยให้เห็นความแตกต่างของความตั้งใจ ปุ่มรีเซ็ตจะมีสีคำเตือนเนื่องจากปุ่มจะเสีย และปุ่มส่งจะได้รับข้อความเน้นเสียงสีน้ำเงินเพื่อให้โปรโมตมากกว่าปุ่มปกติเล็กน้อย

ตัวอย่างชุดปุ่มสุดท้ายประเภทต่างๆ ทั้งหมด แสดงในรูปแบบและไม่ใช่ฟอร์ม พร้อมด้วยปุ่มไอคอนและปุ่มที่ปรับแต่งได้อย่างดี
ตัวอย่างชุดปุ่มสุดท้ายประเภทต่างๆ ทั้งหมดซึ่งแสดงในรูปแบบและไม่ใช่แบบฟอร์ม พร้อมปุ่มไอคอนและปุ่มที่กำหนดเองที่เพิ่มเข้ามาอย่างสวยงาม

ปุ่มต่างๆ ยังมีคลาสเทียม สำหรับ CSS ใช้สำหรับการจัดรูปแบบ คลาสเหล่านี้จะมีฮุก CSS สำหรับการปรับแต่งความรู้สึกของปุ่ม :hover สำหรับเมื่อเมาส์อยู่เหนือปุ่ม :active สำหรับกรณีที่เมาส์หรือแป้นพิมพ์ และ:focus หรือ:focus-visibleสำหรับช่วยจัดรูปแบบของเทคโนโลยีความช่วยเหลือพิเศษ

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
ตัวอย่างชุดปุ่มสุดท้ายทุกประเภทในธีมมืด
ตัวอย่างชุดปุ่มทุกประเภทสุดท้ายในธีมมืด

Markup

นอกจากประเภทปุ่มที่ระบุไว้ในข้อกำหนด HTML แล้ว ผมได้เพิ่มปุ่มที่มีไอคอนและปุ่มที่มีคลาส btn-custom แบบกำหนดเองด้วย

<button>Default</button>
<input type="button" value="<input>"/>
<button>
  <svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
    <path d="..." />
  </svg>
  Icon
</button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom">Custom</button>
<input type="file">

จากนั้นสำหรับการทดสอบ ปุ่มแต่ละปุ่มจะวางอยู่ในแบบฟอร์ม วิธีนี้จะช่วยให้ผมอัปเดตรูปแบบอย่างเหมาะสมสำหรับปุ่มเริ่มต้น ซึ่งทำหน้าที่เป็นปุ่มส่ง และยังเปลี่ยนกลยุทธ์ไอคอนจาก SVG แทรกในบรรทัดเป็น SVG ที่มาสก์ เพื่อให้มั่นใจว่าทั้ง 2 อย่างจะทำงานได้ดีเท่ากัน

<form>
  <button>Default</button>
  <input type="button" value="<input>"/>
  <button>Icon <span data-icon="cloud"></span></button>
  <button type="submit">Submit</button>
  <button type="button">Type Button</button>
  <button type="reset">Reset</button>
  <button disabled>Disabled</button>
  <button class="btn-custom btn-large" type="button">Large Custom</button>
  <input type="file">
</form>

ในตอนนี้ เมตริกซ์ของชุดค่าผสมยังมีความท้าทายอยู่มาก ระหว่างประเภทปุ่ม คลาสเทียม และการอยู่ในหรือนอกแบบฟอร์ม มีปุ่มกว่า 20 ปุ่มรวมกัน ซึ่งเป็นสิ่งที่ดี CSS สามารถช่วยให้เรา อธิบายแต่ละลักษณะได้อย่างชัดเจน

การช่วยเหลือพิเศษ

องค์ประกอบของปุ่มจะเข้าถึงได้อย่างเป็นธรรมชาติ แต่ก็มีการเพิ่มประสิทธิภาพทั่วไป 2-3 อย่าง

วางเมาส์เหนือและโฟกัสพร้อมกัน

ผมชอบจัดกลุ่ม :hover และ :focus เข้ากับตัวเลือกเทียมของฟังก์ชัน :is() ซึ่งช่วยให้อินเทอร์เฟซของฉันดู สไตล์แป้นพิมพ์และเทคโนโลยีความช่วยเหลือพิเศษ

button:is(:hover, :focus) {
  …
}
ลองสาธิต

วงแหวนโฟกัสแบบอินเทอร์แอกทีฟ

ผมชอบทำให้วงแหวนโฟกัสเคลื่อนไหวสำหรับผู้ใช้แป้นพิมพ์และเทคโนโลยีความช่วยเหลือพิเศษ ผมทำวิธีนี้โดยทำให้โครงร่างเคลื่อนไหวห่างจากปุ่ม 5 พิกเซล แต่เฉพาะเมื่อปุ่มไม่ทำงานเท่านั้น ซึ่งจะสร้างเอฟเฟกต์ที่ทำให้วงแหวนโฟกัสลดขนาดกลับไปที่ขนาดปุ่มเมื่อกด

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

การดูแลให้คอนทราสต์ของสีที่ส่ง

มีการผสมสีอย่างน้อย 4 แบบในสไตล์สว่างและมืด ที่ต้องพิจารณาคอนทราสต์ของสี ได้แก่ ปุ่ม ปุ่มส่ง ปุ่มรีเซ็ต และปุ่มปิดใช้ VisBug จะใช้ที่นี่เพื่อตรวจสอบ และแสดงคะแนนทั้งหมดพร้อมกัน

กำลังซ่อนไอคอนจากคนที่มองไม่เห็น

เมื่อสร้างปุ่มไอคอน ไอคอนควรช่วยสนับสนุนภาพข้อความของปุ่ม ซึ่งหมายความไอคอนนั้นจะไม่มีประโยชน์ต่อผู้ที่สูญเสียการมองเห็น โชคดีที่เบราว์เซอร์มีวิธีซ่อนรายการต่างๆ จากเทคโนโลยีโปรแกรมอ่านหน้าจอ เพื่อไม่ให้ผู้ที่สูญเสียการมองเห็นรบกวนด้วยรูปภาพปุ่มตกแต่ง

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
เครื่องมือสำหรับนักพัฒนาเว็บใน Chrome ที่แสดงโครงสร้างการช่วยเหลือพิเศษของปุ่ม ต้นไม้จะไม่สนใจภาพปุ่มเนื่องจากมีการตั้งค่า aria-hidden เป็น &quot;จริง&quot;
เครื่องมือสำหรับนักพัฒนาเว็บใน Chrome ที่แสดงโครงสร้างการช่วยเหลือพิเศษของปุ่ม ต้นไม้จะไม่สนใจรูปภาพปุ่มเนื่องจากมีการตั้งค่า aria-hidden เป็น "จริง"

รูปแบบ

ในส่วนถัดไปนี้ ฉันก่อนอื่น ผมจะสร้างระบบพร็อพเพอร์ตี้ที่กำหนดเองเพื่อจัดการ รูปแบบการปรับของปุ่ม ด้วยคุณสมบัติที่กำหนดเองเหล่านี้ ผมจะเริ่ม เลือกองค์ประกอบและปรับแต่งลักษณะที่ปรากฏได้

กลยุทธ์พร็อพเพอร์ตี้ที่กำหนดเองแบบปรับเปลี่ยนได้

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

button {
  --_bg-light: white;
  --_bg-dark: black;
  --_bg: var(--_bg-light);

  background-color: var(--_bg);
}

@media (prefers-color-scheme: dark) {
  button {
    --_bg: var(--_bg-dark);
  }
}

ฉันชอบคือธีมสว่างและธีมมืดมีความชัดเจนและชัดเจน ระบบจะโหลดโดยอ้อมและนามธรรมลงในพร็อพเพอร์ตี้ที่กำหนดเอง --_bg ซึ่งปัจจุบันเป็นพร็อพเพอร์ตี้ "เชิงรับ" เพียงรายการเดียว โดยมี --_bg-light และ --_bg-dark แบบคงที่ ทั้งยังเห็นได้ชัดเจนว่าธีมสว่างเป็นธีมเริ่มต้นและจะใช้ธีมมืดตามเงื่อนไขเท่านั้น

การเตรียมพร้อมสำหรับความสอดคล้องในการออกแบบ

ตัวเลือกที่ใช้ร่วมกัน

ตัวเลือกดังต่อไปนี้ใช้เพื่อกำหนดเป้าหมายปุ่มประเภทต่างๆ ทั้งหมด และในตอนแรกก็ค่อนข้างเยอะเกินไป มีการใช้ :where() การปรับแต่งปุ่มไม่จำเป็นต้องเฉพาะเจาะจง ปุ่มต่างๆ มักจะมีการปรับเปลี่ยนตามสถานการณ์อื่นๆ และตัวเลือก :where() ก็ช่วยให้งานนั้นทำได้ง่าย ภายใน :where() ระบบจะเลือกปุ่มแต่ละประเภท ซึ่งรวมถึง::file-selector-button ซึ่งจะใช้ไม่ได้ภายใน :is() หรือ :where()

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  …
}

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

สีเฉพาะจุดของปุ่ม

ปุ่มส่งและไอคอนเป็นที่ที่เหมาะสำหรับการแสดงสีสันสวยงาม

--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);

สีข้อความบนปุ่ม

สีข้อความของปุ่มไม่เป็นสีขาวหรือสีดำ แต่เป็น --_accent เวอร์ชันที่มีสีเข้มหรือสว่างขึ้น ซึ่งใช้ hsl() และ ใช้โทนสี 210:

--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);

สีพื้นของปุ่ม

พื้นหลังของปุ่มมีรูปแบบ hsl() เดียวกัน ยกเว้นปุ่มธีมสว่าง ซึ่งจะตั้งค่าเป็นสีขาวเพื่อให้พื้นผิวปรากฏใกล้กับผู้ใช้ หรือแสดงด้านหน้าของแพลตฟอร์มอื่นๆ ดังนี้

--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);

ปุ่มพื้นหลังดี

สีพื้นหลังนี้ใช้สำหรับทำให้พื้นผิวปรากฏด้านหลังพื้นผิวอื่นๆ ซึ่งจะเป็นประโยชน์สำหรับพื้นหลังของอินพุตไฟล์ ดังนี้

--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);

ระยะห่างจากขอบของปุ่ม

การเว้นระยะห่างรอบๆ ข้อความในปุ่มจะใช้หน่วย ch ซึ่งเป็นความยาวที่สัมพันธ์กับขนาดแบบอักษร ซึ่งสำคัญมากเมื่อปุ่มขนาดใหญ่สามารถทำให้ font-size และปุ่มปรับขนาดตามสัดส่วนได้

--_padding-inline: 1.75ch;
--_padding-block: .75ch;

เส้นขอบของปุ่ม

รัศมีเส้นขอบของปุ่มจะซ่อนอยู่ในพร็อพเพอร์ตี้ที่กำหนดเองเพื่อให้อินพุตไฟล์ตรงกับปุ่มอื่นๆ สีเส้นขอบจะเป็นไปตามระบบสีแบบปรับอัตโนมัติที่สร้างขึ้นมา ดังนี้

--_border-radius: .5ch;

--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);

เอฟเฟกต์ไฮไลต์เมื่อวางเมาส์เหนือปุ่ม

พร็อพเพอร์ตี้เหล่านี้จะสร้างพร็อพเพอร์ตี้ขนาดสำหรับการเปลี่ยนเมื่อมีการโต้ตอบ และสีไฮไลต์จะเป็นไปตามระบบสีแบบปรับอัตโนมัติ เราจะพูดถึงวิธีการโต้ตอบเหล่านี้ภายหลังในโพสต์นี้ แต่ท้ายที่สุดแล้วเราจะใช้การโต้ตอบเหล่านี้เพื่อให้เกิดผล box-shadow ดังนี้

--_highlight-size: 0;

--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);

เงาข้อความบนปุ่ม

ปุ่มแต่ละปุ่มจะมีรูปแบบเงาของข้อความเล็กๆ วิธีนี้จะช่วยให้ข้อความวางอยู่เหนือปุ่ม ทำให้อ่านง่าย และเพิ่มความสวยงามของงานนำเสนอ

--_ink-shadow-light: 0 1px 0 var(--_border-light);
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
--_ink-shadow: var(--_ink-shadow-light);

ไอคอนปุ่ม

ไอคอนมีขนาด 2 อักขระตามความยาวหน่วย ch ที่เกี่ยวข้องอีกครั้ง ซึ่งจะช่วยให้ไอคอนปรับขนาดตามสัดส่วนของข้อความบนปุ่ม สีไอคอนจะยึดตาม --_accent-color เป็นสีที่ปรับได้และสีภายในธีม

--_icon-size: 2ch;
--_icon-color: var(--_accent);

เงาปุ่ม

เพื่อให้เงาปรับตัวกับแสงและมืดอย่างเหมาะสม จะต้องมีการเปลี่ยนสีและความทึบแสงด้วย เงาของธีมสว่างจะเหมาะที่สุดเมื่อมีแบบเนียนๆ และปรับสีให้เข้ากับสีพื้นผิวที่วางซ้อน เงาของธีมมืดจะต้องมีสีเข้มและสีอิ่มตัว เพื่อให้ซ้อนกับสีพื้นผิวที่เข้มขึ้นได้

--_shadow-color-light: 220 3% 15%;
--_shadow-color-dark: 220 40% 2%;
--_shadow-color: var(--_shadow-color-light);

--_shadow-strength-light: 1%;
--_shadow-strength-dark: 25%;
--_shadow-strength: var(--_shadow-strength-light);

การใช้สีที่ปรับได้และความเข้มแข็งจะช่วยให้ฉันรวบรวมเงา 2 ระดับได้:

--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));

--_shadow-2: 
  0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
  0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%));

นอกจากนี้ เพื่อให้ปุ่มมีลักษณะ 3 มิติเล็กน้อย เงากล่องของ 1px จะสร้างภาพลวงตาขึ้น

--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);

การเปลี่ยนปุ่ม

ตามรูปแบบสีที่ปรับอัตโนมัติ ฉันสร้างพร็อพเพอร์ตี้แบบคงที่ 2 รายการเพื่อเก็บตัวเลือกระบบการออกแบบไว้

--_transition-motion-reduce: ;
--_transition-motion-ok:
  box-shadow 145ms ease,
  outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);

พร็อพเพอร์ตี้ทั้งหมดรวมอยู่ในตัวเลือก

พร็อพเพอร์ตี้ที่กำหนดเองทั้งหมดในตัวเลือก

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  --_accent-light: hsl(210 100% 40%);
  --_accent-dark: hsl(210 50% 70%);
  --_accent: var(--_accent-light);

--_text-light: hsl(210 10% 30%); --_text-dark: hsl(210 5% 95%); --_text: var(--_text-light);

--_bg-light: hsl(0 0% 100%); --_bg-dark: hsl(210 9% 31%); --_bg: var(--_bg-light);

--_input-well-light: hsl(210 16% 87%); --_input-well-dark: hsl(204 10% 10%); --_input-well: var(--_input-well-light);

--_padding-inline: 1.75ch; --_padding-block: .75ch;

--_border-radius: .5ch; --_border-light: hsl(210 14% 89%); --_border-dark: var(--_bg-dark); --_border: var(--_border-light);

--_highlight-size: 0; --_highlight-light: hsl(210 10% 71% / 25%); --_highlight-dark: hsl(210 10% 5% / 25%); --_highlight: var(--_highlight-light);

--_ink-shadow-light: 0 1px 0 hsl(210 14% 89%); --_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%); --_ink-shadow: var(--_ink-shadow-light);

--_icon-size: 2ch; --_icon-color-light: var(--_accent-light); --_icon-color-dark: var(--_accent-dark); --_icon-color: var(--accent, var(--_icon-color-light));

--_shadow-color-light: 220 3% 15%; --_shadow-color-dark: 220 40% 2%; --_shadow-color: var(--_shadow-color-light); --_shadow-strength-light: 1%; --_shadow-strength-dark: 25%; --_shadow-strength: var(--_shadow-strength-light); --_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%)); --_shadow-2: 0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)), 0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%)) ;

--_shadow-depth-light: hsl(210 14% 89%); --_shadow-depth-dark: var(--_bg-dark); --_shadow-depth: var(--_shadow-depth-light);

--_transition-motion-reduce: ; --_transition-motion-ok: box-shadow 145ms ease, outline-offset 145ms ease ; --_transition: var(--_transition-motion-reduce); }

ปุ่มเริ่มต้นจะแสดงคู่กันในธีมสว่างและมืด

การปรับธีมมืด

ค่าของรูปแบบอุปกรณ์ประกอบฉากคงที่ -light และ -dark จะชัดเจนเมื่อตั้งค่าอุปกรณ์ในธีมมืด

@media (prefers-color-scheme: dark) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_bg: var(--_bg-dark);
    --_text: var(--_text-dark);
    --_border: var(--_border-dark);
    --_accent: var(--_accent-dark);
    --_highlight: var(--_highlight-dark);
    --_input-well: var(--_input-well-dark);
    --_ink-shadow: var(--_ink-shadow-dark);
    --_shadow-depth: var(--_shadow-depth-dark);
    --_shadow-color: var(--_shadow-color-dark);
    --_shadow-strength: var(--_shadow-strength-dark);
  }
}

วิธีนี้นอกจากจะอ่านได้ดีแล้ว ผู้บริโภคที่ใช้ปุ่มที่กำหนดเองเหล่านี้สามารถใช้อุปกรณ์ประกอบฉากต่างๆ ได้ด้วยมั่นใจว่าปุ่มจะปรับตามค่ากำหนดของผู้ใช้อย่างเหมาะสม

การปรับการเคลื่อนไหวลดลง

หากการเคลื่อนไหวของผู้ใช้ที่เข้าชมรายนี้เหมาะสม ให้กำหนด --_transition ให้กับ var(--_transition-motion-ok):

@media (prefers-reduced-motion: no-preference) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_transition: var(--_transition-motion-ok);
  }
}

สไตล์ที่ใช้ร่วมกัน 2-3 รูปแบบ

ปุ่มและอินพุตต้องตั้งค่าแบบอักษรเป็น inherit เพื่อให้ตรงกับแบบอักษรที่เหลือของหน้าเว็บ มิเช่นนั้นเบราว์เซอร์จะจัดรูปแบบให้ ข้อกำหนดนี้มีผลกับ letter-spacing ด้วย การตั้งค่า line-height เป็น 1.5 จะกำหนดขนาดตู้จดหมายเพื่อให้ข้อความด้านบนและด้านล่างมีพื้นที่บางส่วน

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  /* …CSS variables */

  font: inherit;
  letter-spacing: inherit;
  line-height: 1.5;
  border-radius: var(--_border-radius);
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

ปุ่มจัดรูปแบบ

การปรับตัวเลือก

ตัวเลือก input[type="file"] ไม่ใช่ส่วนปุ่มของอินพุต แต่องค์ประกอบเทียม ::file-selector-button คือ ฉันจึงนำ input[type="file"] ออกจากรายการ

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

การปรับเคอร์เซอร์และการแตะ

ก่อนอื่น ผมจัดรูปแบบเคอร์เซอร์ให้เป็นรูปแบบ pointer ซึ่งช่วยให้ปุ่มแสดงแก่ผู้ใช้เมาส์ได้ว่าเป็นการโต้ตอบ จากนั้นผมก็เพิ่ม touch-action: manipulation เพื่อให้คลิกไม่ต้องรอและสังเกตการดับเบิลคลิกที่เป็นไปได้ ซึ่งทำให้ปุ่มโหลดเร็วขึ้น

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  cursor: pointer;
  touch-action: manipulation;
}

สีและเส้นขอบ

ต่อไป ผมจะปรับแต่งขนาดแบบอักษร พื้นหลัง ข้อความ และสีขอบ โดยใช้คุณสมบัติที่กำหนดเองแบบปรับอัตโนมัติซึ่งกำหนดไว้ก่อนหน้านี้

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  font-size: var(--_size, 1rem);
  font-weight: 700;
  background: var(--_bg);
  color: var(--_text);
  border: 2px solid var(--_border);
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

ให้แสงเงา

การใช้ปุ่มต่างๆ ใช้เทคนิคที่ยอดเยี่ยม ปุ่ม text-shadow จะปรับให้เข้ากับแสงและมืด ทำให้ข้อความบนปุ่มมีรูปลักษณ์ที่นุ่มนวลและสวยงาม สำหรับ box-shadow จะมีการกำหนดเงา 3 สี ค่าแรก --_shadow-2 เป็นเงากล่องปกติ เงาที่ 2 เป็นเอฟเฟกต์ที่ดึงดูดสายตาซึ่งทำให้ปุ่มดูสูงขึ้นไปเล็กน้อย เงาส่วนสุดท้ายมีไว้สำหรับการไฮไลต์แบบวางเหนือรายการ ซึ่งในตอนแรกมีขนาด 0 แต่จะมีขนาดในภายหลังและมีการเปลี่ยนให้ดูเหมือน จากปุ่ม

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  box-shadow: 
    var(--_shadow-2),
    var(--_shadow-depth),
    0 0 0 var(--_highlight-size) var(--_highlight)
  ;
  text-shadow: var(--_ink-shadow);
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

เลย์เอาต์

ผมกำหนดเลย์เอาต์แบบ flexbox สำหรับปุ่ม โดยเฉพาะเลย์เอาต์ inline-flex ที่เข้ากับเนื้อหา จากนั้นจัดข้อความให้อยู่กึ่งกลาง และจัดข้อความให้เด็กอยู่ในกึ่งกลางในแนวตั้งและแนวนอน ซึ่งจะช่วยให้ไอคอนและองค์ประกอบปุ่มอื่นๆ จัดเรียงได้อย่างเหมาะสม

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  display: inline-flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

การเว้นพื้นที่

สำหรับการเว้นระยะห่างของปุ่ม เราใช้ gap เพื่อไม่ให้พี่น้องแตะและพร็อพเพอร์ตี้เชิงตรรกะสำหรับระยะห่างจากขอบ เพื่อให้ระยะห่างของปุ่มใช้ได้กับเลย์เอาต์ข้อความทั้งหมด

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  gap: 1ch;
  padding-block: var(--_padding-block);
  padding-inline: var(--_padding-inline);
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

UX การแตะและเมาส์

ส่วนถัดไปส่วนใหญ่จะเป็นเรื่องสำหรับผู้ใช้ระบบสัมผัสในอุปกรณ์เคลื่อนที่ พร็อพเพอร์ตี้แรก user-select มีไว้สำหรับผู้ใช้ทั้งหมด เพื่อป้องกันข้อความที่ไฮไลต์ข้อความบนปุ่ม ซึ่งโดยมากจะสังเกตเห็นได้ในอุปกรณ์ระบบสัมผัสเมื่อมีการแตะปุ่มค้างไว้ และระบบปฏิบัติการจะไฮไลต์ข้อความบนปุ่ม

โดยทั่วไปฉันพบว่านี่ไม่ใช่ประสบการณ์ของผู้ใช้ที่มีปุ่มในแอปในตัว ดังนั้นฉันจึงปิดใช้โดยตั้งค่า user-select เป็น "ไม่มี" แตะสีไฮไลต์ (-webkit-tap-highlight-color) และเมนูตามบริบทของระบบปฏิบัติการ (-webkit-touch-callout) เป็นฟีเจอร์อื่นของปุ่มที่เน้นเว็บ ซึ่งไม่สอดคล้องกับความคาดหวังของผู้ใช้ปุ่มทั่วไป ฉันจึงนำฟีเจอร์ดังกล่าวออกด้วย

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

การเปลี่ยนฉาก

ระบบจะกำหนดตัวแปร --_transition แบบปรับอัตโนมัติให้กับพร็อพเพอร์ตี้ transition ดังนี้

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  …

  transition: var(--_transition);
}

เมื่อวางเมาส์เหนือขณะที่ผู้ใช้ไม่ได้กดอยู่ ให้ปรับขนาดไฮไลต์เงาเพื่อให้มีการโฟกัสที่ชัดเจนและปรากฏขึ้นจากภายในปุ่ม

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
):where(:not(:active):hover) {
  --_highlight-size: .5rem;
}

เมื่อโฟกัส ให้เพิ่มค่าออฟเซ็ตของกรอบโฟกัสจากปุ่ม และทำให้มีรูปลักษณ์ที่โฟกัสชัดเจนขึ้นจากภายในปุ่ม ดังนี้

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

ไอคอน

สำหรับการจัดการไอคอน ตัวเลือกได้เพิ่มตัวเลือก :where() สำหรับบุตรหลานหรือองค์ประกอบ SVG โดยตรงที่มีแอตทริบิวต์ที่กำหนดเอง data-icon ขนาดไอคอนจะกำหนดด้วยพร็อพเพอร์ตี้ที่กำหนดเองโดยใช้พร็อพเพอร์ตี้เชิงตรรกะแบบอินไลน์และบล็อก มีการตั้งค่าสีเส้นโครงร่างและ drop-shadow เพื่อให้ตรงกับtext-shadow มีการตั้งค่า flex-shrink เป็น 0 เพื่อไม่ให้ไอคอนถูกบีบ สุดท้ายนี้ ฉันเลือกไอคอนแบบเส้นและกําหนดรูปแบบเหล่านั้นที่นี่โดยใช้การขึ้นบรรทัดใหม่ fill: none และ round และการผนวกเส้น ดังนี้

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
) > :where(svg, [data-icon]) {
  block-size: var(--_icon-size);
  inline-size: var(--_icon-size);
  stroke: var(--_icon-color);
  filter: drop-shadow(var(--_ink-shadow));

  flex-shrink: 0;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

การปรับแต่งปุ่มส่ง

ผมต้องการให้ปุ่มส่งมีรูปลักษณ์ที่โปรโมตเล็กน้อย ซึ่งทำได้ โดยทำให้สีข้อความของปุ่มเป็นสีเฉพาะจุด ดังนี้

:where(
  [type="submit"], 
  form button:not([type],[disabled])
) {
  --_text: var(--_accent);
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

ปรับแต่งปุ่มรีเซ็ต

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

:where([type="reset"]) {
  --_border-light: hsl(0 100% 83%);
  --_highlight-light: hsl(0 100% 89% / 20%);
  --_text-light: hsl(0 80% 50%);
  --_text-dark: hsl(0 100% 89%);
}

ผมคิดว่าคงจะดีถ้าหากสีเค้าโครงจุดโฟกัสจะตรงกับโทนสีแดง สีข้อความจะปรับสีแดงเข้มเป็นสีแดงอ่อน ผมทำให้สีโครงร่างจับคู่กับคีย์เวิร์ด currentColor ดังนี้

:where([type="reset"]):focus-visible {
  outline-color: currentColor;
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

ปรับแต่งปุ่มที่ปิดใช้

เป็นเรื่องปกติที่ปุ่มที่ปิดใช้จะมีคอนทราสต์ของสีต่ำในระหว่างที่พยายามลบล้างปุ่มที่ปิดใช้เพื่อให้ปุ่มนั้นๆ มีการใช้งานน้อยลง ผมได้ทดสอบชุดสีแต่ละชุดและดูให้แน่ใจว่าผ่านแล้ว โดยเลื่อนค่าความสว่างของ HSL จนกว่าคะแนนจะผ่านในเครื่องมือสำหรับนักพัฒนาเว็บหรือ VisBug

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
)[disabled] {
  --_bg: none;
  --_text-light: hsl(210 7% 40%);
  --_text-dark: hsl(210 11% 71%);

  cursor: not-allowed;
  box-shadow: var(--_shadow-1);
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

การปรับแต่งปุ่มอินพุตไฟล์

ปุ่มอินพุตไฟล์คือคอนเทนเนอร์สำหรับช่วงเวลาและปุ่ม CSS สามารถจัดรูปแบบคอนเทนเนอร์อินพุตเล็กน้อย รวมถึงปุ่มที่ซ้อนกัน แต่ไม่ใช่ระยะเวลา คอนเทนเนอร์จะได้รับ max-inline-size จึงจะไม่ขยายใหญ่เกินกว่าที่จำเป็น ขณะที่ inline-size: 100% จะอนุญาตให้ย่อตัวเองและให้พอดีกับคอนเทนเนอร์ที่เล็กกว่าที่เป็นอยู่ สีพื้นหลังจะเป็นสีแบบปรับอัตโนมัติซึ่งเข้มกว่าพื้นผิวอื่นๆ ดังนั้นจึงอยู่ด้านหลังปุ่มตัวเลือกไฟล์

:where(input[type="file"]) {
  inline-size: 100%;
  max-inline-size: max-content;
  background-color: var(--_input-well);
}

ปุ่มตัวเลือกไฟล์และปุ่มประเภทการป้อนข้อมูลมีการกำหนดไว้โดยเฉพาะ appearance: none เพื่อนำรูปแบบที่เบราว์เซอร์มีให้ซึ่ง ไม่ได้เขียนทับโดยรูปแบบปุ่มอื่นๆ

:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
  appearance: none;
}

และสุดท้าย จะเพิ่มระยะขอบใน inline-end ของปุ่มเพื่อดันข้อความสแปนออกห่างจากปุ่ม ทำให้มีพื้นที่ว่างมากขึ้น

:where(input[type="file"])::file-selector-button {
  margin-inline-end: var(--_padding-inline);
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

ข้อยกเว้นธีมมืดพิเศษ

ผมตั้งพื้นหลังให้ปุ่มการทำงานหลักมีสีเข้มขึ้นสำหรับข้อความที่มีคอนทราสต์สูง

@media (prefers-color-scheme: dark) {
  :where(
    [type="submit"],
    [type="reset"],
    [disabled],
    form button:not([type="button"])
  ) {
    --_bg: var(--_input-well);
  }
}

ภาพหน้าจอแสดงปุ่มหลังจากใช้รูปแบบก่อนหน้า

การสร้างตัวแปร

เพื่อความสนุกและเพราะใช้งานได้จริง ผมจึงเลือกที่จะแสดงวิธีสร้าง รูปแบบสัก 2-3 แบบ ตัวแปรหนึ่งมีสีสันสดใสมาก คล้ายกับปุ่มหลักที่แสดงบ่อยๆ ตัวแปรอื่นมีขนาดใหญ่ รูปแบบสุดท้ายมีไอคอนที่ไล่ระดับสี

ปุ่มสีสันสดใส

ในการสร้างปุ่มสไตล์นี้ ผมจึงเขียนทับวัตถุประกอบฐานด้วยสีฟ้าโดยตรง แม้ว่าจะรวดเร็วและง่ายดาย แต่ก็นำอุปกรณ์ประกอบฉากแบบปรับอัตโนมัติออกได้และมีลักษณะเหมือนกันทั้งในธีมสว่างและธีมมืด

.btn-custom {
  --_bg: linear-gradient(hsl(228 94% 67%), hsl(228 81% 59%));
  --_border: hsl(228 89% 63%);
  --_text: hsl(228 89% 100%);
  --_ink-shadow: 0 1px 0 hsl(228 57% 50%);
  --_highlight: hsl(228 94% 67% / 20%);
}

ปุ่มที่กำหนดเองจะแสดงในแบบสว่างและมืด ซึ่งเป็นสีน้ำเงินที่สดใสมากเหมือนปุ่มการทำงานหลักทั่วไปมักจะเป็น

ปุ่มขนาดใหญ่

ปุ่มรูปแบบนี้ทำได้โดยการแก้ไขพร็อพเพอร์ตี้ที่กำหนดเอง --_size ระยะห่างจากขอบและองค์ประกอบพื้นที่อื่นๆ จะสัมพันธ์กับขนาดนี้ โดยจะปรับขนาดตามสัดส่วนของขนาดใหม่

.btn-large {
  --_size: 1.5rem;
}

ปุ่มขนาดใหญ่จะแสดงข้างปุ่มที่กำหนดเอง โดยใหญ่กว่าประมาณ 150 เท่า

ปุ่มไอคอน

เอฟเฟกต์ไอคอนนี้ไม่มีส่วนเกี่ยวข้องกับรูปแบบปุ่มของเรา แต่จะแสดงวิธีทำให้สำเร็จด้วยคุณสมบัติ CSS เพียงไม่กี่รายการ และประสิทธิภาพของปุ่มนั้นในการจัดการไอคอนที่ไม่ได้อยู่ใน SVG ในหน้าได้ดีเพียงใด

[data-icon="cloud"] {
  --icon-cloud: url("https://api.iconify.design/mdi:apple-icloud.svg") center / contain no-repeat;

  -webkit-mask: var(--icon-cloud);
  mask: var(--icon-cloud);
  background: linear-gradient(to bottom, var(--_accent-dark), var(--_accent-light));
}

ปุ่มที่มีไอคอนจะแสดงในธีมสว่างและมืด

บทสรุป

ตอนนี้คุณก็รู้แล้วว่าตัวเองทำยังไง คุณจะทำอะไรบ้าง‽ 🙂

มาลองเปลี่ยนแนวทางของเราและเรียนรู้วิธีทั้งหมดเพื่อสร้างเว็บกันเถอะ

สร้างเดโม ลิงก์ทวีตฉัน แล้วฉันจะเพิ่มลงในส่วนรีมิกซ์ของชุมชนด้านล่าง

รีมิกซ์ของชุมชน

ยังไม่มีอะไรให้ดูที่นี่

แหล่งข้อมูล