เคล็ดลับเครื่องมือที่คำนึงถึงตำแหน่ง

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

การค้นหาคอนเทนเนอร์ที่ตรึงไว้จะช่วยแก้ปัญหานี้โดยอนุญาตให้คุณค้นหาสถานะการจัดตำแหน่งที่ใช้งานอยู่ขององค์ประกอบและใช้สไตล์ตามนั้น สำหรับตำแหน่งเมนูแบบเลื่อนลงและเมนูย่อยที่ตรึงไว้ทั่วไปซึ่งมีการพลิกการชนวิวพอร์ต (โดยไม่มีการจัดรูปแบบลูกศรบอกทิศทางใหม่) โปรดดูเมนูแบบเลื่อนลงที่รับรู้วิวพอร์ต

ปัญหา

ลองนึกภาพเคล็ดลับเครื่องมือที่ปรากฏเหนือ Anchor โดยค่าเริ่มต้น โดยมีลูกศร "ลง" ที่ด้านล่าง หากผู้ใช้เลื่อนและเคล็ดลับเครื่องมือพลิกไปปรากฏด้านล่าง Anchor ลูกศรจะชี้ผิดทางและอยู่ผิดด้านของเคล็ดลับเครื่องมือ

โซลูชัน: การค้นหาคอนเทนเนอร์ที่ตรึงไว้

การตั้งค่า container-type: anchored ในองค์ประกอบที่กำหนดตำแหน่งจะเปลี่ยนองค์ประกอบดังกล่าวให้เป็นคอนเทนเนอร์การค้นหาที่ทราบสถานะที่กำหนดตำแหน่ง Anchor ของตนเอง จากนั้นคุณจะใช้การค้นหา @container anchored() เพื่ออัปเดตองค์ประกอบสืบทอดหรือองค์ประกอบจำลองได้

1. สร้างเคล็ดลับเครื่องมือและทริกเกอร์

ใช้ Popover API เพื่อสร้างเคล็ดลับเครื่องมือ การเรียกใช้ป๊อปโอเวอร์ผ่าน popovertarget จะสร้างการเชื่อมต่อ Anchor โดยนัยกับปุ่มทริกเกอร์โดยอัตโนมัติ จึงไม่จำเป็นต้องใช้ anchor-name หรือ position-anchor อย่างชัดแจ้ง

<button popovertarget="tooltip" id="anchor" aria-describedby="tooltip">anchor</button>
<div id="tooltip" popover role="tooltip"></div>

รีเซ็ตสไตล์ส่วนแทรกและระยะขอบของป๊อปโอเวอร์เพื่อใช้กับการจัดตำแหน่ง Anchor แต่เฉพาะในกรณีที่รองรับการจัดตำแหน่ง Anchor เท่านั้น

@supports (anchor-name: --my-anchor) {
  [popover] {
    inset: auto;
    margin: unset;
  }
}

2. ตั้งค่าคอนเทนเนอร์

ใช้ container-type: anchored กับองค์ประกอบที่กำลังจัดตำแหน่ง องค์ประกอบนี้ต้องมี position-try-fallbacks ที่กำหนดไว้เพื่อเปิดใช้ลักษณะการทำงานของการพลิกด้วย

#tooltip {
  position: fixed;
  position-area: block-start;
  position-try-fallbacks: flip-block;

  /* Enable anchored container queries */
  container-type: anchored;
}

3. จัดรูปแบบตามโฆษณาสำรอง

ใช้ @container anchored(fallback: <value>) เพื่อใช้สไตล์เมื่อมีการใช้โฆษณาสำรองที่เฉพาะเจาะจง

เช่นเดียวกับการค้นหาคอนเทนเนอร์ทั้งหมด @container สามารถจัดรูปแบบองค์ประกอบสืบทอดของคอนเทนเนอร์ได้เท่านั้น กลยุทธ์ทั่วไปในการสร้างลูกศรคือการใช้ Pseudo-element ::before และ ::after ซึ่งถือเป็นองค์ประกอบสืบทอดและจัดรูปแบบได้โดยตรง อย่างไรก็ตาม หากต้องการจัดรูปแบบเคล็ดลับเครื่องมือ (ดังที่เห็นในขั้นตอนที่ 4) เราจะเพิ่มองค์ประกอบย่อยลงในเคล็ดลับเครื่องมือ และสร้างลูกศรในองค์ประกอบเทียม ::before

<div id="tooltip" popover role="tooltip">
  <div class="tooltip-content">Tooltip</div>
</div>
.tooltip-content::before {
  /* Default "down" arrow for the 'top' position */
  content: "▼";
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 1rem;
}

/* Update to an "up" arrow when the 'flip-block' fallback (bottom) is active */
@container anchored(fallback: flip-block) {
  .tooltip-content::before {
    content: "▲";
    inset-block-start: 0;
    inset-block-end: auto;
  }
}

4. การจัดรูปแบบคอนเทนเนอร์

หากต้องการเปลี่ยนพร็อพเพอร์ตี้ในคอนเทนเนอร์ (เช่น margin หรือ background-color) เมื่อพลิก คุณควรใช้องค์ประกอบ Wrapper ด้านใน

  1. ใช้ container-type: anchored กับองค์ประกอบที่วางตำแหน่งด้านนอก
  2. กำหนดเป้าหมายองค์ประกอบภายในบล็อก @container
@container anchored(fallback: flip-block) {
  .tooltip-content {
    border-radius: 0 0 .5rem .5rem;
    margin-block-start: 0.25rem;
  }
}

แนวทางปฏิบัติแนะนำ

  • ใช้การสำรองเชิงตรรกะ: ใช้คีย์เวิร์ดอย่าง flip-block และ flip-inline ใน position-try-fallbacks สำหรับการค้นหาที่ง่ายขึ้นซึ่งจัดการ RTL และโหมดการเขียนต่างๆ โดยอัตโนมัติ
  • ใช้องค์ประกอบเทียมสำหรับลูกศร: ลูกศรเคล็ดลับเครื่องมือมีไว้เพื่อตกแต่งเท่านั้นและเหมาะอย่างยิ่งสำหรับ ::before หรือ ::after ซึ่งสามารถจัดสไตล์ผ่านการค้นหาคอนเทนเนอร์ที่ยึดไว้โดยไม่ต้องใช้ DOM เพิ่มเติม

กลยุทธ์สำรอง

การวางตำแหน่งลูกศรตามการใช้โหมดสำรองเป็นการเพิ่มประสิทธิภาพแบบต่อเนื่อง และไม่มีวิธีอื่นในการตอบสนองต่อตำแหน่งสำรอง หากต้องการซ่อนลูกศรในเบราว์เซอร์ที่ไม่รองรับการค้นหาคอนเทนเนอร์ตำแหน่ง Anchor ให้ทดสอบการรองรับ CSS ด้วย @supports (container-type: anchored)

@supports (container-type: anchored) {
  .tooltip-content::before {
    content: "▼";
  }
}

การรองรับเบราว์เซอร์และทางเลือกสำรองสำหรับ Popover

Popover API ส่วนใหญ่เป็นการเพิ่มประสิทธิภาพแบบต่อเนื่อง แต่ลักษณะการทำงานที่กำหนดไว้ เช่น การโปรโมตเลเยอร์บนสุด การปิดเมื่อคลิกนอกองค์ประกอบ และการเรียกใช้ popovertarget ไม่มี CSS ที่เทียบเท่า เบราว์เซอร์รุ่นเก่าต้องใช้ Polyfill หรือการสำรองข้อมูลด้วยตนเองหากคุณไม่ต้องการจัดส่ง

Polyfill: หากต้องการรองรับแอตทริบิวต์ popover ในเบราว์เซอร์รุ่นเก่า ให้โหลด @oddbird/popover-polyfill แบบมีเงื่อนไข จำเป็น: ตรวจหาฟีเจอร์โดยการตรวจสอบพร็อพเพอร์ตี้ popover ใน HTMLElement.prototype และโหลด Polyfill เฉพาะเมื่อไม่มีการรองรับแบบเนทีฟ อย่าโหลดโดยไม่มีเงื่อนไข

เมื่อใช้ Bundler หรือแผนที่การนำเข้า ให้ทำดังนี้

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

หากไม่มี Bundler ให้นำเข้าจาก 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>

ข้อควรระวังเกี่ยวกับรูปแบบ: Polyfill ไม่สามารถกำหนดคลาสจำลอง :popover-open จริงได้ จึงใช้คลาส .\:popover-open แทน จำเป็น: รวมทั้ง 2 รายการเข้าด้วยกันโดยใช้ :is() หรือ :where() ไม่เช่นนั้นเบราว์เซอร์ที่ไม่มี :popover-open จะทิ้งกฎทั้งหมด

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

หรือสำหรับทางเลือกสำรองแบบเดิมที่ไม่มี Polyfill ให้ใช้ position: fixed และคำนวณพิกัดด้วยตนเองผ่าน getBoundingClientRect() หรือใช้การกำหนดตำแหน่งเริ่มต้นด้วย inset: auto หากยอมรับได้สำหรับกรณีการใช้งาน

เบราว์เซอร์ที่ไม่รองรับ Popover API จะไม่รองรับการวางตำแหน่ง Anchor ด้วย ดังนั้นเคล็ดลับเครื่องมือจะปรากฏตรงกลางหน้าจอ