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

ภาพรวมพื้นฐานเกี่ยวกับวิธีสร้างคอมโพเนนต์การตั้งค่าของแถบเลื่อนและช่องทําเครื่องหมาย

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

สาธิต

หากต้องการดูวิดีโอหรือต้องการดูตัวอย่าง UI/UX ของสิ่งที่เรากำลังสร้าง โปรดดูวิดีโอแนะนำแบบสั้นๆ บน YouTube ต่อไปนี้

ภาพรวม

เราได้แยกแง่มุมต่างๆ ของคอมโพเนนต์นี้ออกเป็นส่วนต่อไปนี้

  1. เลย์เอาต์
  2. สี
  3. การป้อนช่วงที่กำหนดเอง
  4. อินพุตช่องทำเครื่องหมายที่กําหนดเอง
  5. ข้อควรพิจารณาเกี่ยวกับการช่วยเหลือพิเศษ
  6. JavaScript

เลย์เอาต์

นี่คือการสาธิต GUI Challenge แรกที่เป็นตารางกริด CSS ทั้งหมด ตารางกริดแต่ละตารางที่ไฮไลต์ด้วย Chrome DevTools สําหรับตารางกริดมีดังนี้

การวางซ้อนเส้นขอบสีสันสดใสและระยะห่างช่องว่างที่ช่วยแสดงช่องทั้งหมดที่ประกอบกันเป็นเลย์เอาต์การตั้งค่า

เพื่อช่องว่าง

เลย์เอาต์ที่พบบ่อยที่สุด

foo {
  display: grid;
  gap: var(--something);
}

เราเรียกเลย์เอาต์นี้ว่า "มีไว้เพื่อเว้นวรรค" เนื่องจากใช้ตารางกริดเพื่อเว้นวรรคระหว่างบล็อกเท่านั้น

เลย์เอาต์ 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 และตารางกริดช่วยให้คุณalign-itemsหรือ align-contentได้ และเมื่อจัดการกับองค์ประกอบที่มีการตัดขึ้นบรรทัดใหม่ การจัดวางcontentจะกระจายพื้นที่ว่างระหว่างองค์ประกอบย่อยเป็นกลุ่ม

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
}

องค์ประกอบหลักใช้การจัดแนวplace-content: centerแบบย่อเพื่อให้องค์ประกอบย่อยอยู่กึ่งกลางในแนวตั้งและแนวนอนทั้งในเลย์เอาต์แบบ 1 และ 2 คอลัมน์

ดูในวิดีโอด้านบนว่า "เนื้อหา" อยู่ตรงกลางอย่างไร แม้ว่าจะมีการตัดขึ้นบรรทัดใหม่แล้วก็ตาม

ปรับขนาดอัตโนมัติตามค่าต่ำสุดและสูงสุดซ้ำ

<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() เพิ่มเติมไว้อย่างดีในบล็อกของเขาในโพสต์ตาราง CSS ที่ตอบสนองโดยเนื้อแท้ด้วย minmax() และ min() เราขอแนะนำให้อ่านโพสต์ดังกล่าว flex-start การแก้ไขการจัดตำแหน่งมีไว้เพื่อนำเอฟเฟกต์การยืดเริ่มต้นออก เพื่อให้องค์ประกอบย่อยของเลย์เอาต์นี้ไม่จำเป็นต้องมีความสูงเท่ากัน แต่มีความสูงตามธรรมชาติ วิดีโอ YouTube มีรายละเอียดคร่าวๆ เกี่ยวกับการเพิ่มการจัดแนวนี้

max-width: 89vw มีรายละเอียดเล็กๆ น้อยๆ ในโพสต์นี้ เราขอแสดงเลย์เอาต์ที่มีและไม่ได้ใช้สไตล์

บอกว่าคุณกำลังคิดอะไรอยู่ เมื่อระบุ max-width จะเป็นการระบุบริบท การกำหนดขนาดที่ชัดเจน หรือการกำหนดขนาดที่แน่นอนเพื่อให้auto-fitอัลกอริทึมการจัดวางทราบจำนวนการซ้ำที่พอดีกับพื้นที่ แม้ว่าพื้นที่จะดูเป็น "แบบเต็มความกว้าง" แต่ตามข้อกำหนดของตารางกริด CSS คุณต้องระบุขนาดที่แน่นอนหรือขนาดสูงสุด เราได้ระบุขนาดสูงสุดแล้ว

แล้วทำไมต้องเป็น 89vw เนื่องจาก "ใช้งานได้" สำหรับเลย์เอาต์ของฉัน เราและทีม Chrome อีก 2 คนกำลังตรวจสอบสาเหตุที่ค่าที่เหมาะสมกว่า เช่น 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;
}

การใช้ฟีเจอร์เหล่านี้ทำงานร่วมกับตารางกริด, 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 เนื่องจากใน Media Query ฉันจะพลิกสีเหล่านั้น และสีอ่อนและสีเข้มจะไม่มีความหมาย

ฉันจะพลิกในคําค้นหาสื่อตามค่ากําหนดดังนี้

: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) ซึ่งมีข้อดีตรงที่มนุษย์เขียนได้ง่ายขึ้นและผู้ใช้คนอื่นๆ จะเข้าใจการปรับเหล่านี้

ภาพหน้าจอของหน้าเว็บ pod.link/csspodcast ที่มีตอน Color 2: Perception แสดงอยู่
ดูข้อมูลเกี่ยวกับสีที่รับรู้ (และอื่นๆ) ใน CSS Podcast

ในวันนี้ เราจะโฟกัสไปที่ไวยากรณ์และค่าที่ฉันจะสลับเพื่อทำให้สว่างและมืด มาดูพื้นผิว 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 ว่าการออกแบบของคุณใช้การควบคุมดังกล่าว

ด้านบนแสดงผลของพร็อพเพอร์ตี้จากแผงสไตล์ของ DevTools ตัวอย่างนี้ใช้แท็ก 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);
}

ภาพหน้าจอจาก Chromium บน Linux ที่แสดงช่องทำเครื่องหมายสีชมพู

ป๊อปสีด้วยการไล่ระดับสีแบบคงที่และโฟกัสภายใน

สีจะโดดเด่นที่สุดเมื่อใช้อย่างจำกัด และวิธีที่เราชอบใช้เพื่อทำให้สีโดดเด่นคือการใช้การโต้ตอบ 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;
    }
  }
}

เมื่อหนึ่งในองค์ประกอบย่อยขององค์ประกอบนี้มีจุดโฟกัสอยู่ภายใน:

  1. พื้นหลัง .fieldset-item ได้รับการกําหนดสีพื้นผิวที่มีความคมชัดสูงกว่า
  2. svg ที่ฝังอยู่จะเติมสีขาวเพื่อให้คอนทราสต์สูงขึ้น
  3. <picture> clip-path ที่ฝังจะขยายเป็นรูปวงกลมเต็มและพื้นหลังจะเต็มไปด้วยการไล่ระดับสีที่สว่างแบบคงที่

ช่วงที่กำหนดเอง

เราจะแสดงวิธีปรับแต่งลักษณะที่ปรากฏขององค์ประกอบอินพุต HTML ต่อไปนี้

<input type="range">

องค์ประกอบนี้มีส่วนที่ต้องปรับแต่ง 3 ส่วน ได้แก่

  1. องค์ประกอบ/คอนเทนเนอร์ช่วง
  2. ติดตาม
  3. Thumb

รูปแบบองค์ประกอบช่วง

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;
}

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

รูปแบบการเติมการติดตาม

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

/* 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 นี้สร้างแรงบันดาลใจมาก

รูปแบบภาพปก

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;
  }
}

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

หากเอฟเฟกต์ไฮไลต์ในช่องทําเครื่องหมายทําได้ง่ายขนาดนี้ก็คงดี

ตัวเลือกข้ามเบราว์เซอร์

ฉันพบว่าต้องใช้ตัวเลือก -webkit- และ -moz- เหล่านี้เพื่อให้สอดคล้องกันในเบราว์เซอร์ต่างๆ

input[type="range"] {
  &::-webkit-slider-runnable-track {}
  &::-moz-range-track {}
  &::-webkit-slider-thumb {}
  &::-moz-range-thumb {}
}

ช่องทำเครื่องหมายที่กำหนดเอง

จากองค์ประกอบอินพุต HTML ต่อไปนี้ ผมจะแสดงวิธีการปรับแต่งรูปลักษณ์ขององค์ประกอบ

<input type="checkbox">

องค์ประกอบนี้มีอยู่ 3 ส่วนที่ต้องปรับแต่ง ดังนี้

  1. องค์ประกอบช่องทําเครื่องหมาย
  2. ป้ายกำกับที่เชื่อมโยง
  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"> ในช่องทำเครื่องหมาย ให้เพิ่มทั้งชื่อและรหัส 2 เท่าเพื่อให้แน่ใจว่าข้อมูลจะปรากฏพร้อมกับเครื่องมือและเทคโนโลยีต่างๆ เช่น เมาส์หรือโปรแกรมอ่านหน้าจอ ดังนี้ <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-Space

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

วิดีโอ 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);
})

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

ภาพหน้าจอของผลลัพธ์ console.table() ซึ่งแสดงข้อมูลแบบฟอร์มในตาราง

บทสรุป

ตอนนี้คุณก็รู้วิธีที่เราทําแล้ว คุณจะทําอย่างไร นี่เป็นสถาปัตยกรรมคอมโพเนนต์ที่น่าสนใจ ใครจะสร้างเวอร์ชันที่ 1 ด้วยช่องในเฟรมเวิร์กโปรด 🙂

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

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

  • @tomayac กับสไตล์เกี่ยวกับพื้นที่โฮเวอร์สำหรับป้ายกำกับช่องทำเครื่องหมาย เวอร์ชันนี้ไม่มีช่องว่างจากการวางเมาส์เหนือระหว่างองค์ประกอบ: demo และ source