درحال ساختن مؤلفه «تنظیمات»

نمای کلی پایه‌ای از نحوه ساخت مؤلفه تنظیمات لغزنده‌ها و چارگوش‌های انتخاب.

در این پست می‌خواهم ایده‌هایی را درباره ساختن مؤلفه «تنظیمات» برای وب هم‌رسانی کنم که واکنش‌گرا باشد، از ورودی‌های چند دستگاه پشتیبانی کند، و در مرورگرهای مختلف کار کند. نسخه نمایشی را امتحان کنید.

نمونه

اگر ویدیو را ترجیح می‌دهید یا می‌خواهید پیش‌نمایشی از واسط کاربر/ تجربه کاربری آنچه می‌سازیم داشته باشید، در اینجا راهنمای گام‌به‌گام کوتاه‌تری در YouTube ارائه شده است:

نمای کلی

جنبه‌های این مؤلفه را به بخش‌های زیر تقسیم کرده‌ام:

  1. چیدمان‌ها
  2. رنگ
  3. ورودی محدوده سفارشی
  4. ورودی چارگوش انتخاب سفارشی
  5. ملاحظات دسترس‌پذیری
  6. JavaScript

چیدمان‌ها

این اولین نسخه نمایشی «چالش GUI» است که کاملاً CSS Grid است! در اینجا هر شبکه با Chrome DevTools برای شبکه برجسته شده است:

خطوط رنگارنگ و فاصله‌گذاری‌های هم‌پوشان که به نمایش همه کادرهایی که چیدمان تنظیمات را تشکیل می‌دهند کمک می‌کند

فقط برای فاصله

رایج‌ترین چیدمان:

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

من این چیدمان را «فقط برای فاصله» می‌نامم چون فقط از شبکه برای افزودن فاصله بین بلوک‌ها استفاده می‌کند.

پنج طرح‌بندی از این استراتژی استفاده می‌کنند، همه آن‌ها در اینجا نمایش داده شده‌اند:

طرح‌بندی‌های جدولی عمودی که با خطوط پیرامونی برجسته شده‌اند و فاصله‌های خالی پر شده‌اند

عنصر 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 استفاده می‌کند تا عناصر فرزند به‌صورت عمودی و افقی در هر دو چیدمان یک و دو ستونی در مرکز قرار گیرند.

در ویدیو بالا تماشا کنید که چگونه «محتوا» در مرکز باقی می‌ماند، حتی اگر پیچیدن اتفاق افتاده باشد.

تکرار حداقل/حداکثر تنظیم خودکار

<form> از طرح‌بندی شبکه‌ای تطبیقی برای هر بخش استفاده می‌کند. این چیدمان براساس فضای دردسترس از یک به دو ستون تغییر می‌کند.

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 استفاده می‌کند: repeat()، minmax()، و min(). Una Kravets پست وبلاگ عالی‌ای درباره چیدمان دارد که آن را RAM می‌نامد.

اگر چیدمان ما را با چیدمان اونا مقایسه کنید، ۳ مورد ویژه به آن اضافه شده است:

  • تابع min() اضافی را رد می‌کنیم.
  • align-items: flex-start را مشخص می‌کنیم.
  • سبک max-width: 89vw وجود دارد.

تابع اضافی min() به‌خوبی توسط ایوان مینتو در وبلاگش در پست شبکه CSS ذاتاً واکنش‌گرا با minmax()‎ و min()‎ شرح داده شده است. توصیه می‌کنم آن را بخوانید. تصحیح تراز flex-start برای برداشتن جلوه کشیدگی پیش‌فرض است تا فرزندان این چیدمان نیازی به داشتن ارتفاع یکسان نداشته باشند و بتوانند ارتفاع طبیعی و ذاتی داشته باشند. ویدیو YouTube به‌طور خلاصه این افزودنی تراز را توضیح می‌دهد.

max-width: 89vw ارزش این را دارد که در این پست کمی به آن بپردازیم. اجازه دهید چیدمان را با و بدون اعمال سبک به شما نشان دهم:

چه اتفاقی افتاده؟ وقتی max-width مشخص می‌شود، بافت، اندازه صریح، یا اندازه قطعی را برای الگوریتم چیدمان auto-fit ارائه می‌دهد تا بداند چند تکرار را می‌تواند در فضا جای دهد. While it seems obvious that the space is "full width", per the CSS grid spec, a definite size or max-size must be provided. حداکثر اندازه را ارائه کرده‌ام.

پس چرا 89vw؟ چون برای چیدمان من «کار کرد». من و چند نفر دیگر از افراد Chrome درحال بررسی این موضوع هستیم که چرا مقدار منطقی‌تری، مثل 100vw، کافی نیست و آیا این درواقع یک اشکال است یا نه.

فاصله‌گذاری

بخش عمده‌ای از هماهنگی این چیدمان از پالت محدود فاصله‌گذاری، دقیقاً ۷، ناشی می‌شود.

: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، و نحو سطح ۵ از @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 سال ۲۰۲۱ خیلی خوب به‌نظر می‌رسد!

چیدمان قبلی را به‌یاد دارید، «فقط برای فاصله»؟ نسخه کامل‌تری از نحوه نمایش آن‌ها در این مؤلفه در اینجا آورده شده است:

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 یک نحو انسان‌محور است که به نحوه درک ما از رنگ توجه می‌کند، نه نحوه اندازه‌گیری رنگ با ریاضی (مانند ۲۵۵). این امر مزیت متمایزی به آن می‌دهد زیرا انسان‌ها می‌توانند آن را راحت‌تر بنویسند و انسان‌های دیگر با این تنظیمات هماهنگ خواهند بود.

نماگرفتی از صفحه وب pod.link/csspodcast، با قسمت «رنگ ۲: ادراک» که بالا کشیده شده است
در پادکست CSS درباره رنگ ادراکی (و موارد دیگر!) بیشتر بدانید

برای امروز، در این نسخه نمایشی، بیایید روی نحو و مقادیری که من برای ایجاد حالت روشن و تاریک تغییر می‌دهم تمرکز کنیم. بیایید به ۱ سطح و ۱ رنگ نوشتار نگاه کنیم:

: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% روشنایی، ۰ فام‌داری، و ۰ فام ترجمه می‌شود: خاکستری بی‌رنگ بسیار تیره. سپس، در پرسمان رسانه برای حالت روشن، روشنایی به 90% با --surface1: lch(90 0 0); تغییر می‌کند. و این خلاصه استراتژی است. با تغییر دادن روشنایی بین ۲ طرح زمینه شروع کنید و نسبت‌های کنتراست موردنیاز طراحی یا آنچه را که می‌تواند دسترس‌پذیری را حفظ کند حفظ کنید.

مزیت lch() در اینجا این است که روشنایی انسان‌محور است و می‌توانیم نسبت‌به تغییر % در آن احساس خوبی داشته باشیم، زیرا این تغییر % ازنظر ادراکی و به‌طور مداوم متفاوت خواهد بود. برای مثال، hsl() به‌اندازه قابل‌اعتماد نیست.

اگر علاقه‌مندید، مطالب بیشتری برای یادگیری درباره فضاهای رنگی و lch() وجود دارد. به‌زودی می‌آید!

درحال‌حاضر CSS به‌هیچ‌وجه نمی‌تواند به این رنگ‌ها دسترسی داشته باشد. اجازه دهید تکرار کنم: ما به یک سوم رنگ‌ها در اکثر مانیتورهای مدرن دسترسی نداریم. و این‌ها فقط رنگ‌های معمولی نیستند، بلکه زنده‌ترین رنگ‌هایی هستند که صفحه‌نمایش می‌تواند نشان دهد. وب‌سایت‌های ما رنگ‌پریده هستند چون سخت‌افزار نمایشگر سریع‌تر از مشخصات CSS و پیاده‌سازی‌های مرورگر تکامل یافته است.

Lea Verou

کنترل‌های فرم تطبیقی با طرح رنگ

بسیاری از مرورگرها کنترل‌های زمینه تیره را ارائه می‌دهند، درحال‌حاضر Safari و Chromium، اما باید در CSS یا HTML مشخص کنید که طراحی شما از آن‌ها استفاده می‌کند.

در بالا، تأثیر این ویژگی از پانل «سبک‌ها» در DevTools نشان داده شده است. نسخه نمایشی از برچسب HTML استفاده می‌کند که به‌نظر من معمولاً مکان بهتری است:

<meta name="color-scheme" content="dark light">

در این color-scheme مقاله از توماس اشتاینر، همه چیز را درباره آن بیاموزید. چیزهای زیاد دیگری برای به‌دست آوردن وجود دارد تا ورودی‌های چارگوش انتخاب تیره!

سرویس مقایسه قیمت accent-color

فعالیت‌های اخیر درخصوص accent-color در عناصر فرم، یک سبک CSS واحد است که می‌تواند رنگ ته‌مایه استفاده‌شده در عنصر ورودی مرورگرها را تغییر دهد. در اینجا در GitHub درباره آن بیشتر بخوانید. آن را در سبک‌هایم برای این مؤلفه گنجانده‌ام. ازآنجایی‌که مرورگرها از آن پشتیبانی می‌کنند، چارگوش‌های انتخاب من با پاپ فیلتر رنگ صورتی و بنفش بیشتر با زمینه هماهنگ خواهند بود.

input[type="checkbox"] {
  accent-color: var(--brand);
}

نماگرفتی از Chromium در Linux با چارگوش‌های انتخاب صورتی

پاپ فیلتر رنگ با گرادیان‌های ثابت و فوکوس داخلی

رنگ زمانی بیشتر جلوه می‌کند که به‌ندرت استفاده شود، و یکی از روش‌هایی که دوست دارم برای رسیدن به آن استفاده کنم، ازطریق تعاملات رنگارنگ میانای کاربر است.

در ویدیو بالا، لایه‌های زیادی از بازخورد و تعامل واسط کاربر وجود دارد که با انجام کارهای زیر به تعامل شخصیت می‌بخشد:

  • درحال برجسته کردن بافت.
  • ارائه بازخورد واسط کاربر درباره اینکه مقدار در محدوده «چقدر پر» است.
  • ارائه بازخورد واسط کاربر مبنی بر اینکه فیلد ورودی را می‌پذیرد.

برای ارائه بازخورد هنگام تعامل با یک عنصر، 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">

این عنصر ۳ بخش دارد که باید سفارشی‌سازی کنیم:

  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 بخش‌های سفارشی سبک‌ها هستند و امیدوارم که برچسب‌گذاری واضح آن‌ها مفید باشد. بقیه سبک‌ها عمدتاً سبک‌های بازنشانی هستند تا پایه‌ای منسجم برای ساختن بخش‌های پیچیده مؤلفه فراهم کنند.

سبک‌های قطعه

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

ترفند این کار «نمایان کردن» رنگ پرکننده زنده است. این کار با گرادیان توقف سخت در بالا انجام می‌شود. گرادیان تا درصد پر شدن شفاف است و پس‌از آن از رنگ سطح قطعه پرنشده استفاده می‌کند. پشت آن سطح پرنشده، رنگی با عرض کامل وجود دارد که منتظر شفافیت است تا آشکار شود.

سبک رنگ قطعه

طراحی من برای حفظ سبک پر کردن به جاوا اسکریپت نیاز دارد. راهبردهای CSS-only وجود دارد اما آن‌ها نیاز دارند که عنصر thumb هم‌ارتفاع track باشد و من نتوانستم در این محدودیت‌ها هماهنگی پیدا کنم.

/* 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));
  })
})

فکر می‌کنم این کار باعث ارتقای بصری خوبی می‌شود. لغزنده بدون جاوا اسکریپت به‌خوبی کار می‌کند، ویژگی --track-fill الزامی نیست، اگر وجود نداشته باشد، سبک پر کردن نخواهد داشت. اگر جاوا اسکریپت دردسترس است، ویژگی سفارشی را پر کنید و درعین‌حال هرگونه تغییر کاربر را نیز مشاهده کنید و ویژگی سفارشی را با مقدار همگام‌سازی کنید.

این یک پست عالی است در 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">

این عنصر ۳ بخش دارد که باید سفارشی‌سازی کنیم:

  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 پشتیبانی می‌شود، این چارگوش‌های انتخاب را به طرح رنگ نمانام اضافه کنید.

برچسب‌های چارگوش انتخاب

ارائه برچسب برای چارگوش‌های انتخاب به ۲ دلیل مهم است. اولین مورد این است که نشان دهد مقدار چارگوش انتخاب برای چه چیزی استفاده می‌شود، تا به این سؤال پاسخ دهد که «روشن یا خاموش برای چه چیزی؟» دوم اینکه برای تجربه کاربری، کاربران وب به تعامل با چارگوش‌های انتخاب ازطریق برچسب‌های مرتبط با آن‌ها عادت کرده‌اند.

ورودی
<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) است. والد یک فضای سه‌بعدی ایجاد کرده است و این عنصر شبه‌فرزند با قرار دادن خود کمی عقب‌تر در فضای 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

من قبلاً توضیح داده‌ام که رنگ پرکننده قطعه چگونه از جاوا اسکریپت مدیریت می‌شد، بنابراین بیایید اکنون به جاوا اسکریپت مرتبط با <form> نگاه کنیم:

const form = document.querySelector('form');

form.addEventListener('input', event => {
  const formData = Object.fromEntries(new FormData(form));
  console.table(formData);
})

هر بار که با فرم تعامل برقرار می‌شود و فرم تغییر می‌کند، کنسول فرم را به‌عنوان یک شیء در جدولی ثبت می‌کند تا قبل‌از ارسال به سرور به‌راحتی قابل‌بازبینی باشد.

نماگرفتی از نتایج console.table() که در آن داده‌های فرم در جدول نشان داده شده است

نتیجه‌گیری

حالا که می‌دانید من چطور این کار را کردم، شما چطور این کار را می‌کنید؟! این کار باعث ایجاد معماری مؤلفه جالبی می‌شود! Who's going to make the 1st version with slots in their favorite framework? 🙂

بیایید رویکردهایمان را متنوع کنیم و همه روش‌های ساختن در وب را یاد بگیریم. یک نسخه نمایشی ایجاد کنید، پیوندها را برای من توییت کنید، و من آن را به بخش بازآمیزی‌های انجمن در زیر اضافه خواهم کرد!

ریمیکس‌های انجمن

  • @tomayac با سبک خودشان درباره ناحیه نگه داشتن نشانگر برای برچسب‌های چارگوش انتخاب! این نسخه هیچ فاصله نگه داشتن نشانگر بین عناصر ندارد: نسخه نمایشی و منبع.