انتخاب‌گر رسانه تعاملی (انتخاب سفارشی‌سازی)

عنصر بومی <select> در گذشته به‌سختی سبک‌بندی می‌شد و فقط می‌توانست گزینه‌های نوشتار ساده را دربرگیرد. ویژگی appearance: base-select روشی اعلانی و فقط CSS برای انتخاب حالت قابل‌سفارشی‌سازی برای عنصر <select> ارائه می‌دهد. این ویژگی به توسعه‌دهندگان امکان می‌دهد محتوای HTML غنی (مانند تصاویر، SVG، و چیدمان‌های پیچیده) را در عناصر <option> بگنجانند و درعین‌حال، دسترسی‌پذیری صفحه‌کلید بومی و ادغام فرم را حفظ کنند. از این الگو برای جایگزین کردن مؤلفه‌های انتخاب سنگین و سفارشی‌سازی‌شده با عناصر استاندارد و بومی استفاده کنید.

نحوه پیاده‌سازی

برای پیاده‌سازی انتخابگر رسانه تعاملی بااستفاده از Customizable Select API:

  1. موافقت با سبک‌های پایه: appearance: base-select را بااستفاده از شبه‌عنصر ::picker(select) هم به عنصر <select> و هم به انتخابگر داخلی آن اعمال کنید. این کار تجزیه‌کننده HTML مرورگر را برای محتوای داخل <select> تغییر می‌دهد.
  2. تعریف محتوای دکمه: از عناصر استاندارد <button> و <selectedcontent> در داخل <select> استفاده کنید تا آنچه را که هنگام بسته شدن انتخابگر نشان داده می‌شود تعریف کنید. عنصر <selectedcontent> به‌طور خودکار محتوای گزینه انتخاب‌شده را منعکس می‌کند. اگر می‌خواهید محتوای غنی انتخاب‌شده فعلی را در دکمه نمایش دهید، این مورد لازم است.
  3. استفاده از محتوای غنی در گزینه‌ها: اکنون می‌توانید تصاویر، SVG، و سایر برچسب‌های HTML را در برچسب‌های <option> قرار دهید. پیش‌از این میانای برنامه‌سازی کاربردی، مرورگر برچسب‌ها را از برچسب‌های <option> حذف می‌کرد و فقط نوشتار ساده را ارائه می‌داد.
  4. سبک‌بندی Popover: با هدف قرار دادن شبه‌عنصر ::picker(select)، فهرست گزینه‌های کرکره‌ای را سبک‌بندی کنید. این عنصر در لایه بالایی ارائه می‌شود، یعنی نیازی نیست با z-index کلنجار بروید. گزینه‌ها بااستفاده از Anchor Positioning API به‌صورت بومی جای‌گذاری می‌شوند.

کد نمونه: انتخابگر نقش غنی

<label for="role-picker">Select your role</label>
<select class="custom-select" name="role" id="role-picker">
  <button>
    <selectedcontent></selectedcontent> <!-- Mirrors the selected option's content automatically so you do not need JS to update the button -->
  </button>

  <!-- Define concise aria-label values on options whose mirrored rich content would otherwise read awkwardly as a concatenated string -->
  <option value="frontend" aria-label="Frontend Developer">
    <svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
      <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
    </svg>
    <div class="option-text">
      <span class="option-title">Frontend Developer</span>
      <span class="option-desc">React, Vue, CSS</span>
    </div>
  </option>

  <option value="backend" aria-label="Backend Developer">
    <svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
      <rect x="2" y="12" width="20" height="14" rx="2" ry="2"></rect>
    </svg>
    <div class="option-text">
      <span class="option-title">Backend Developer</span>
      <span class="option-desc">Node.js, Python</span>
    </div>
  </option>
</select>
select.custom-select,
select.custom-select::picker(select) {
  appearance: base-select; /* MUST opt-in both the select and its picker to enable the customizable state, otherwise browser standard rendering applies */
}

select.custom-select {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 12px;
  background-color: #1e293b;
  border: 1px solid #334155;
  border-radius: 8px;
  color: #f1f5f9;
  cursor: pointer;
}

select.custom-select::picker(select) {
  background-color: #0f172a;
  border: 1px solid #334155;
  border-radius: 8px;
  padding: 8px;
  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
  width: anchor-size(width); /* Uses Anchor Positioning API to keep the dropdown precisely aligned to the button trigger width */
}

select.custom-select option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px;
  border-radius: 4px;
  cursor: pointer;
}

select.custom-select option:hover {
  background-color: #1e293b;
}

/* Remove standard OS checkmark for base-select */
select.custom-select option::before {
  display: none;
}

/* MANDATORY: Provide multiple visual indicators (e.g., prominent background color and bold title font) to communicate the checked state cleanly */
select.custom-select option:checked {
  background-color: #3b82f6;
  color: #ffffff;
}
select.custom-select option:checked .option-title {
  font-weight: 700;
}

پیاده‌سازی استراتژیک و روال‌های مطلوب

  • باید از appearance: base-select استفاده کنید وقتی به چیدمان‌های پیچیده گزینه‌ها (نمادها، توضیحات، تصاویر) نیاز دارید که قبلاً فقط با چارچوب‌های سنگین واسط کاربر جاوا اسکریپت امکان‌پذیر بود.
  • اگر متوجه تأخیر در عملکرد شدید، از عناصر موقت استفاده نکنید؛ مرورگر تمرکز صفحه‌کلید بومی را به‌صورت بومی مدیریت می‌کند.
  • باید پرداز زدن لایه بالایی را درنظر بگیرید. انتخابگر در لایه بالایی ارائه می‌شود، یعنی z-index نسبی محتوای صفحه را لغو می‌کند.
  • باید جزئیات ثانویه (مانند توضیحات) را در وضعیت دکمه پنهان کنید اگر فضای زیادی اشغال می‌کنند، بااستفاده از سبک‌دهی .custom-select selectedcontent .option-desc { display: none; }.
  • رفتار چیدمان را آزمایش کنید. تنظیم appearance: base-select رفتار پیش‌فرض مرورگر را برای اندازه‌گیری انتخاب براساس طولانی‌ترین عرض گزینه حذف می‌کند. ممکن است لازم باشد عرض ثابتی تنظیم کنید یا از محدودیت‌های flex/grid برای جلوگیری از تغییرات طرح‌بندی استفاده کنید.
  • مطمئن شوید <select> دارای مشخصه name و <label> مرتبط باشد. این کار تضمین می‌کند که حتی با واسط کاربر سفارشی، مؤلفه برای صفحه‌خوان‌ها دسترس‌پذیر باقی بماند و با ارسال‌های فرم استاندارد به‌درستی کار کند.
  • از مشخصه‌های استاندارد value در گزینه‌ها استفاده کنید تا مطمئن شوید ارسال فرم دقیقاً مثل قبل کار می‌کند.

راهبردهای جایگزین

جایگزین‌ها و پشتیبانی مرورگر برای <select> قابل‌سفارشی‌سازی

برای مرورگرهایی که هنوز از appearance: base-select پشتیبانی نمی‌کنند، عنصر <select> به‌طور مناسب به منو کرکره‌ای سیستم‌عامل استاندارد تنزل می‌یابد.

  • نادیده گرفتن محتوای غیرنوشتاری: مرورگرهای قدیمی‌تر تگ‌های HTML (مثل <svg> یا <div>) را در تگ‌های <option> حذف می‌کنند و فقط گره‌های نوشتاری را ارائه می‌دهند. مطمئن شوید محتوای نوشتاری <option> به‌تنهایی خوانا و معنادار باشد.
  • مدیریت ساختار HTML: تجزیه‌کننده‌های استاندارد ممکن است برچسب‌های <button> و <selectedcontent> را در <select> نادیده بگیرند یا آن‌ها را نامعتبر تلقی کنند. اگر نوشتار استاندارد را به‌عنوان جایگزین خوانا درنظر بگیرید، برای ارتقای پیش‌رو به شبیه‌سازهای مرورگر جاوا اسکریپت سنگین نیازی نیست.
document.addEventListener("DOMContentLoaded", () => {
  // Check if browser supports base-select value
  if (!CSS.supports("appearance", "base-select")) {
    // Custom select overrides are not supported natively.
  }
});