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

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

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

สาธิต

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

ภาพรวม

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

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

เลย์เอาต์

นี่เป็นตัวอย่าง GUI Challenge รายการแรกที่เป็น CSS Grid ทั้งหมด ตารางกริดแต่ละตารางที่ไฮไลต์ด้วย 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 ตัวย่อการจัดตำแหน่งเพื่อให้องค์ประกอบย่อยอยู่กึ่งกลางทั้งแนวตั้งและแนวนอนทั้งในเลย์เอาต์คอลัมน์เดียวและ 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;
    }
  }
}

เมื่อองค์ประกอบย่อยรายการใดรายการหนึ่งขององค์ประกอบนี้มี focus-within

  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