منوهای کرکره‌ای آگاه از ناحیه نمایش

پانل کنش آشکارشده یا گروه دکمه‌های پاپ‌اور الگوی مفیدی برای کاربران است تا به عملکردهای اضافی دسترسی پیدا کنند و درعین‌حال حداقل فضا را اشغال کنند. این الگوی رونهاد با پیچیدگی چیدمان همراه است، زیرا پانل باید به عنصر راه‌انداز متصل بماند و درعین‌حال با محدودیت‌های نمای هدف سازگار شود. به‌طور سنتی، این کار به کتابخانه‌های پیچیده جاوا اسکریپت (مانند Popper.js یا Floating UI) برای محاسبه موقعیت‌ها و مدیریت برخوردها نیاز داشت.

«موقعیت‌یابی لنگر CSS» روشی اعلانی و بهینه‌شده ازنظر عملکرد برای مدیریت این روابط به‌طور کامل در CSS ارائه می‌دهد و به مرورگرها امکان می‌دهد منطق موقعیت‌یابی و سرریز را به‌طور بومی مدیریت کنند.

۱. تعریف رابطه دکمه و پانل

اولین مرحله ایجاد دکمه راه‌انداز است که بااستفاده از Popover API، محفظه هم‌پوشانی را باز می‌کند.

تمایز دسترس‌پذیری اجباری: این الگو به‌جای منو ARIA واقعی، صریحاً گروه دکمه‌ای را که در یک پاپ‌اور آشکار شده است مدل‌سازی می‌کند. role="menu" یا role="menuitem" را اعمال نکنید مگراینکه قرارداد پیمایش صفحه‌کلید مربوطه را به‌طور کامل پیاده‌سازی کنید (مثلاً مدیریت پیمایش کلید جهت‌نمای فضایی بین موارد). به همین دلیل، aria-haspopup را به راه‌انداز اضافه نکنید — مقدار آن (menu،‏ listbox،‏ tree،‏ grid، یا true قدیمی) تضمین می‌کند که هدف نقش منطبقی را نشان می‌دهد، که این الگو این کار را نمی‌کند.

<button popovertarget="action-panel">
  Open Actions
</button>
<!-- Use the Popover API (`popover="auto"`) for the overlay to ensure it is placed in the top layer and handled accessibly by the browser. -->
<div id="action-panel" popover="auto" class="panel">
  <button class="action-item" type="button">Edit</button>
</div>

این کار یک ارتباط لنگر ضمنی بین دکمه و پانل ایجاد می‌کند، به‌طوری‌که پانل می‌تواند به‌طور بومی نسبت به دکمه قرار گیرد بدون اینکه نیازی به anchor-name روی دکمه یا position-anchor روی پانل باشد.

۲. موقعیت‌یابی با position-area

به‌جای جابه‌جایی دستی top/left، از position-area برای قرار دادن هدف در جدول ۳×۳ نسبت‌به لنگر استفاده کنید.

.panel {
  /* 
     Position the panel below the anchor (block-end), 
     aligned to the start of the anchor and spanning to its end (span-inline-end).
  */
  position-area: block-end span-inline-end;
  
  /* Reset insets to allow the grid to take control */
  inset: auto;
}

برای پشتیبانی خودکار از زبان‌های راست‌به‌چپ و حالت‌های نوشتاری مختلف، کلیدواژه‌های منطقی (span-inline-end، block-start) را به کلیدواژه‌های فیزیکی (left، top) ترجیح دهید.

اجباری: کلیدواژه‌های فیزیکی و منطقی را در position-area باهم ترکیب نکنید.

۳. پیاده‌سازی تاب‌آوری لبه (جایگزین‌ها)

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

.panel {
  /* 
     If the panel overflows the bottom, flip it to the top (flip-block).
     If it overflows the inline edges, flip it horizontally (flip-inline).
     If it overflows both (e.g., in a corner), flip on both axes (flip-block flip-inline).
  */
  position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
}

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

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

پشتیبانی مرورگر و بازگشت به حالت قبلی برای Popover

«میانای برنامه‌سازی کاربردی Popover» عمدتاً ارتقای پیش‌رو است، اما رفتارهای تعریف‌کننده آن (ارتقای لایه بالایی، رد کردن با کلیک در خارج از عنصر، و فراخوانی popovertarget) معادل CSS-only ندارند. مرورگرهای قدیمی‌تر به شبیه‌ساز مرورگر نیاز دارند، یا اگر ترجیح می‌دهید شبیه‌ساز مرورگر ارسال نکنید، به بازگشت دستی نیاز دارند.

شبیه‌ساز مرورگر: برای پشتیبانی از مشخصه popover در مرورگرهای قدیمی‌تر، @oddbird/popover-polyfill را به‌صورت شرطی بار کنید. اجباری: ویژگی را با بررسی کردن ویژگی popover در HTMLElement.prototype شناسایی کنید و شبیه‌ساز مرورگر را فقط زمانی بار کنید که پشتیبانی بومی وجود ندارد — آن را بدون قیدوشرط بار نکنید.

با بسته‌بندی یا نقشه واردات:

// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
  import("@oddbird/popover-polyfill");
}

بدون بسته‌بندی، از CDN داخل <script type="module"> وارد کنید:

<script type="module">
  if (!("popover" in HTMLElement.prototype)) {
    import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
  }
</script>

هشدار سبک‌بندی: شبیه‌ساز مرورگر نمی‌تواند کلاس کاذب واقعی :popover-open را تعریف کند، بنابراین به‌جای آن کلاس .\:popover-open را اعمال می‌کند. اجباری: این دو را با :is() یا :where() ترکیب کنید، درغیراین‌صورت مرورگرهایی که فاقد :popover-open هستند کل قانون را نادیده می‌گیرند:

[popover]:is(:popover-open, .\:popover-open) {
  display: block;
}

یا برای بازگشت به نسخه قدیمی بدون شبیه‌ساز مرورگر، از position: fixed استفاده کنید و مختصات را به‌صورت دستی ازطریق getBoundingClientRect() محاسبه کنید یا اگر برای مورد استفاده قابل‌قبول است، به موقعیت‌یابی پیش‌فرض با inset: auto تکیه کنید.

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

برای برخی‌از موارد استفاده، ممکن است بتوانید از شبیه‌ساز مرورگر @oddbird/css-anchor-positioning استفاده کنید که پشتیبانی از برخی موارد استفاده از موقعیت‌یابی لنگر را اضافه می‌کند. از لنگرهای ضمنی پشتیبانی نمی‌کند، بنابراین باید نام لنگرها را به راه‌انداز اضافه کنید. علاوه‌براین، position-area در پاپ‌اورها توسط شبیه‌ساز مرورگر پشتیبانی نمی‌شود، بنابراین باید از anchor() در درج‌های موردنظر استفاده کنید.

<!-- MANDATORY: Conditionally install the anchor positioning polyfill -->
<script type="module">
  if (!("anchorName" in document.documentElement.style)) {
    await import("https://unpkg.com/@oddbird/css-anchor-positioning");
  }
</script>
.panel {
  /* Mandatory: use explicit anchor name */
  position-anchor: --kebab-anchor;
  /* Mandatory: use insets rather than position-area for positioning */
  bottom: auto;
  right: auto;
  top: anchor(bottom);
  left: anchor(left);
  margin: 0;
}