ป๊อปอัป: ส่วนขยายเหล่านี้กลับมาได้รับความนิยมอีกครั้ง

ใหม่แล้ว

เป้าหมายของโครงการริเริ่ม Open UI คือการช่วยให้นักพัฒนาแอปสร้างประสบการณ์ของผู้ใช้ที่ยอดเยี่ยมได้ง่ายขึ้น เราจึงพยายามจัดการกับรูปแบบที่มีปัญหามากขึ้นที่นักพัฒนาแอปพบ เราจะทำเช่นนี้ได้ด้วยการจัดหา API และคอมโพเนนต์ในตัวของแพลตฟอร์มที่ดีขึ้น

ปัญหาดังกล่าวอย่างหนึ่งคือป๊อปอัป ซึ่งอธิบายไว้ใน Open UI ว่าเป็น "ป๊อปโอเวอร์"

ป๊อปโอเวอร์มีชื่อเสียงที่ค่อนข้างแตกต่างกันมาเป็นเวลานาน ซึ่งส่วนหนึ่งเป็นเพราะวิธีการสร้างและติดตั้งใช้งาน แม้ว่าการสร้างรูปแบบนี้ให้ดีอาจไม่ใช่เรื่องง่าย แต่ก็สามารถสร้างคุณค่าได้มากด้วยการนำผู้ใช้ไปยังสิ่งต่างๆ หรือทำให้ผู้ใช้ทราบถึงเนื้อหาในเว็บไซต์ของคุณ โดยเฉพาะอย่างยิ่งเมื่อใช้ในลักษณะที่เหมาะสม

โดยปกติแล้วจะมีข้อกังวลหลัก 2 ประการเมื่อสร้างป๊อปโอเวอร์

  • วิธีตรวจสอบว่าระบบจะวางโฆษณาเหนือเนื้อหาอื่นๆ ในตำแหน่งที่เหมาะสม
  • วิธีทำให้เข้าถึงได้ (ใช้แป้นพิมพ์ได้ โฟกัสได้ และอื่นๆ)

Popover API ในตัวมีเป้าหมายที่หลากหลาย โดยมีเป้าหมายหลักเดียวกันคือการช่วยให้นักพัฒนาแอปสร้างรูปแบบนี้ได้ง่ายๆ เป้าหมายที่สำคัญมีดังนี้

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

ดูรายละเอียดทั้งหมดเกี่ยวกับป๊อปอัปได้ในเว็บไซต์ OpenUI

ความเข้ากันได้กับเบราว์เซอร์

ตอนนี้คุณใช้ Popover API ในตัวได้ที่ใด โดยฟีเจอร์นี้รองรับใน Chrome Canary ที่อยู่เบื้องหลังค่าสถานะ "ฟีเจอร์แพลตฟอร์มบนเว็บเวอร์ชันทดลอง" ณ เวลาที่เขียนบทความนี้

หากต้องการเปิดใช้ Flag ดังกล่าว ให้เปิด Chrome Canary แล้วไปที่ chrome://flags จากนั้นเปิดใช้การติดธง "ฟีเจอร์แพลตฟอร์มเว็บเวอร์ชันทดลอง"

นอกจากนี้ยังมีOrigin Trial สำหรับนักพัฒนาแอปที่ต้องการทดสอบฟีเจอร์นี้ในสภาพแวดล้อมการใช้งานจริงด้วย

สุดท้ายนี้ เรากำลังพัฒนา polyfill สำหรับ API อย่าลืมดูที่เก็บข้อมูลที่ github.com/oddbird/popup-polyfill

คุณตรวจสอบการสนับสนุนแบบป๊อปอัปได้โดยทำดังนี้

const supported = HTMLElement.prototype.hasOwnProperty("popover");

โซลูชันปัจจุบัน

ปัจจุบันคุณทำอะไรได้บ้างเพื่อโปรโมตเนื้อหาของคุณเหนือสิ่งอื่นใด หากเบราว์เซอร์รองรับ คุณจะใช้องค์ประกอบ HTML Dialog ได้ คุณจะต้องใช้ในรูปแบบ "โมดัล" และต้องใช้ JavaScript จึงจะใช้งานได้

Dialog.showModal();

มีข้อควรพิจารณาบางประการเกี่ยวกับการช่วยเหลือพิเศษ ขอแนะนำให้ใช้ a11y-dialog เช่น หากรองรับผู้ใช้ Safari เวอร์ชันต่ำกว่า 15.4

หรือจะใช้ไลบรารีป๊อปโอเวอร์ การแจ้งเตือน หรือเคล็ดลับเครื่องมือที่มีอยู่มากมายก็ได้ ซึ่งส่วนใหญ่จะทำงานในลักษณะที่คล้ายกัน

  • ต่อท้ายคอนเทนเนอร์บางรายการกับเนื้อหาเพื่อแสดงป๊อปโอเวอร์
  • จัดรูปแบบให้วางอยู่เหนือทุกอย่าง
  • สร้างองค์ประกอบและต่อท้ายคอนเทนเนอร์เพื่อแสดงป๊อปโอเวอร์
  • ซ่อนโดยนำองค์ประกอบป๊อปโอเวอร์ออกจาก DOM

ซึ่งต้องมีทรัพยากร Dependency เพิ่มเติมและนักพัฒนาแอปต้องตัดสินใจมากขึ้น นอกจากนี้ คุณยังต้องค้นหาข้อเสนอที่ตอบโจทย์ทุกความต้องการด้วย Popover API มีจุดมุ่งหมายเพื่อรองรับหลายสถานการณ์ รวมถึงเคล็ดลับเครื่องมือ เป้าหมายคือการครอบคลุมสถานการณ์ทั่วไปทั้งหมดเหล่านั้น เพื่อช่วยให้นักพัฒนาแอปไม่ต้องตัดสินใจอีกต่อไปและสามารถมุ่งเน้นที่การสร้างประสบการณ์การใช้งานได้

ป๊อปอัปแรก

คุณต้องมีเพียงเท่านี้

<div id="my-first-popover" popover>Popover Content!</div>
<button popovertoggletarget="my-first-popover">Toggle Popover</button>

แต่เกิดอะไรขึ้นที่นี่

  • คุณไม่จำเป็นต้องใส่องค์ประกอบป๊อปโอเวอร์ลงในคอนเทนเนอร์หรืออะไรก็ตาม เนื่องจากระบบจะซ่อนองค์ประกอบดังกล่าวโดยค่าเริ่มต้น
  • คุณไม่จำเป็นต้องเขียน JavaScript ใดๆ เพื่อให้ปุ่มปรากฏ แอตทริบิวต์ popovertoggletarget จะจัดการเรื่องนี้
  • เมื่อปรากฏขึ้น ระบบจะเลื่อนไปที่เลเยอร์บนสุด ซึ่งหมายความว่าวิดีโอจะได้รับการโปรโมตเหนือ document ในวิวพอร์ต คุณไม่ต้องจัดการ z-index หรือกังวลว่าป๊อปโอเวอร์จะอยู่ที่ใดใน DOM ซึ่งอาจซ้อนกันลึกลงไปใน DOM โดยมีองค์ประกอบระดับบนสุดที่ครอบตัด นอกจากนี้ คุณยังดูได้ว่าองค์ประกอบใดอยู่ในเลเยอร์บนสุดในขณะนี้ผ่านเครื่องมือสำหรับนักพัฒนาเว็บ ดูข้อมูลเพิ่มเติมเกี่ยวกับเลเยอร์บนสุดได้ที่บทความนี้

GIF ของการสาธิตการรองรับเลเยอร์บนสุดของเครื่องมือสำหรับนักพัฒนาเว็บ

  • คุณจะได้รับ "ปิดอย่างรวดเร็ว" ทันที ซึ่งหมายความว่าคุณสามารถปิดป๊อปโอเวอร์ด้วยสัญญาณปิด เช่น การคลิกนอกป๊อปโอเวอร์ การไปยังองค์ประกอบอื่นด้วยแป้นพิมพ์ หรือการกดปุ่ม Esc เปิดแอปอีกครั้งแล้วลองใช้เลย

คุณจะได้รับอะไรอีกบ้างจากป๊อปโอเวอร์ มาดูตัวอย่างเพิ่มเติมกัน ลองดูการสาธิตนี้ที่มีเนื้อหาบางอย่างในหน้า

ปุ่มการทำงานแบบลอยนั้นมีตำแหน่งคงที่และมี z-index สูง

.fab {
  position: fixed;
  z-index: 99999;
}

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

นอกจากนี้ คุณอาจสังเกตเห็นว่าป๊อปโอเวอร์มี::backdropองค์ประกอบเสมือนแล้ว องค์ประกอบทั้งหมดที่อยู่ในเลเยอร์บนสุดจะมี::backdropองค์ประกอบเสมือนที่จัดรูปแบบได้ ตัวอย่างนี้จัดรูปแบบ ::backdrop ด้วยสีพื้นหลังที่มีค่าอัลฟ่าลดลงและฟิลเตอร์ฉากหลัง ซึ่งจะเบลอเนื้อหาที่อยู่ด้านล่าง

การจัดรูปแบบป๊อปโอเวอร์

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

[popover] { display: block; }

ไม่ว่าคุณจะโปรโมตป๊อปโอเวอร์ด้วยวิธีใด เมื่อโปรโมตป๊อปโอเวอร์ไปยังเลเยอร์บนสุดแล้ว คุณอาจต้องจัดวางหรือกำหนดตำแหน่ง คุณไม่สามารถกำหนดเป้าหมายเลเยอร์บนสุดและทำสิ่งต่างๆ เช่น

:open {
  display: grid;
  place-items: center;
}

โดยค่าเริ่มต้น ป๊อปโอเวอร์จะจัดวางที่กึ่งกลางวิวพอร์ตโดยใช้ margin: auto แต่ในบางกรณี คุณอาจต้องการระบุตำแหน่งอย่างชัดเจน เช่น

[popover] {
  top: 50%;
  left: 50%;
  translate: -50%;
}

หากต้องการจัดวางเนื้อหาภายในป๊อปโอเวอร์โดยใช้ CSS Grid หรือ Flexbox คุณอาจต้องห่อหุ้มเนื้อหานี้ในองค์ประกอบ ไม่เช่นนั้น คุณจะต้องประกาศกฎแยกต่างหากที่จะเปลี่ยน display เมื่อป๊อปโอเวอร์อยู่ในเลเยอร์บนสุด การตั้งค่าเป็นค่าเริ่มต้นจะทำให้แสดงโดยค่าเริ่มต้น ซึ่งจะลบล้าง display: none

[popover]:open {
 display: flex;
}

หากคุณลองใช้เดโมดังกล่าว คุณจะเห็นว่าตอนนี้ป๊อปโอเวอร์จะเปลี่ยนเข้าและออก คุณเปลี่ยนป๊อปโอเวอร์เข้าและออกได้โดยใช้:openตัวเลือกเสมือน :openตัวเลือกเทียมจะตรงกับป๊อปโอเวอร์ที่แสดง (และอยู่ในเลเยอร์บนสุด)

ตัวอย่างนี้ใช้คุณสมบัติที่กำหนดเองเพื่อขับเคลื่อนการเปลี่ยนผ่าน และคุณยังใช้การเปลี่ยนกับ ::backdrop ของป๊อปโอเวอร์ได้ด้วย

[popover] {
  --hide: 1;
  transition: transform 0.2s;
  transform: translateY(calc(var(--hide) * -100vh))
            scale(calc(1 - var(--hide)));
}

[popover]::backdrop {
  transition: opacity 0.2s;
  opacity: calc(1 - var(--hide, 1));
}


[popover]:open::backdrop  {
  --hide: 0;
}

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

@media(prefers-reduced-motion: no-preference) {
  [popover] { transition: transform 0.2s; }
  [popover]::backdrop { transition: opacity 0.2s; }
}

จนถึงตอนนี้ คุณได้เห็นการใช้ popovertoggletarget เพื่อแสดงป๊อปโอเวอร์แล้ว เราใช้ "ปิดอย่างรวดเร็ว" เพื่อปิด แต่คุณยังได้รับแอตทริบิวต์ popovershowtarget และ popoverhidetarget ที่ใช้ได้ด้วย มาเพิ่มปุ่มในป๊อปโอเวอร์ที่ซ่อนป๊อปโอเวอร์นั้นและเปลี่ยนปุ่มเปิด/ปิดเพื่อใช้ popovershowtarget กัน

<div id="code-popover" popover>
  <button popoverhidetarget="code-popover">Hide Code</button>
</div>
<button popovershowtarget="code-popover">Reveal Code</button>

ดังที่ได้กล่าวไปก่อนหน้านี้ว่า Popover API ครอบคลุมมากกว่าแนวคิดป๊อปอัปในอดีตของเรา คุณสามารถสร้างสำหรับสถานการณ์ทุกประเภท เช่น การแจ้งเตือน เมนู เคล็ดลับเครื่องมือ เป็นต้น

บางสถานการณ์เหล่านั้นต้องใช้รูปแบบการโต้ตอบที่แตกต่างกัน การโต้ตอบ เช่น การวางเมาส์ เราได้ทดลองใช้แอตทริบิวต์ popoverhovertarget แต่ยังไม่ได้นำมาใช้ในขณะนี้

<div popoverhovertarget="hover-popover">Hover for Code</div>

แนวคิดคือการวางเมาส์เหนือองค์ประกอบเพื่อแสดงเป้าหมาย คุณกำหนดค่าลักษณะการทำงานนี้ได้ผ่านพร็อพเพอร์ตี้ CSS พร็อพเพอร์ตี้ CSS เหล่านี้จะกำหนดช่วงเวลาสำหรับการวางเมาส์เหนือและออกจากองค์ประกอบที่ป๊อปโอเวอร์ตอบสนอง ลักษณะการทำงานเริ่มต้นที่ใช้ในการทดสอบคือการแสดงป๊อปโอเวอร์หลังจากที่ผู้ใช้0.5s:hoverอย่างชัดเจน จากนั้นจะต้องปิดด้วยการแตะด้านนอกหรือเปิดป๊อปโอเวอร์อื่นเพื่อปิด (ดูข้อมูลเพิ่มเติมได้ในส่วนถัดไป) ซึ่งเป็นเพราะระยะเวลาซ่อนป๊อปโอเวอร์ถูกตั้งค่าเป็น Infinity

ในระหว่างนี้ คุณสามารถใช้ JavaScript เพื่อ Polyfill ฟังก์ชันการทำงานดังกล่าวได้

let hoverTimer;
const HOVER_TRIGGERS = document.querySelectorAll("[popoverhovertarget]");
const tearDown = () => {
  if (hoverTimer) clearTimeout(hoverTimer);
};
HOVER_TRIGGERS.forEach((trigger) => {
  const popover = document.querySelector(
    `#${trigger.getAttribute("popoverhovertarget")}`
  );
  trigger.addEventListener("pointerenter", () => {
    hoverTimer = setTimeout(() => {
      if (!popover.matches(":open")) popover.showPopover();
    }, 500);
    trigger.addEventListener("pointerleave", tearDown);
  });
});

การตั้งค่าให้บางอย่างเป็นหน้าต่างการวางเมาส์ที่ชัดเจนมีประโยชน์ตรงที่ช่วยให้มั่นใจได้ว่าการกระทำของผู้ใช้เป็นไปโดยเจตนา (เช่น ผู้ใช้วางเคอร์เซอร์เหนือเป้าหมาย) เราไม่ต้องการแสดงป๊อปอัป เว้นแต่ผู้ใช้จะตั้งใจ

ลองใช้เดโมนี้ซึ่งคุณสามารถวางเมาส์เหนือเป้าหมายโดยตั้งค่าหน้าต่างเป็น 0.5s


ก่อนที่จะไปดูตัวอย่างกรณีการใช้งานที่พบบ่อย เรามาดูเรื่องต่างๆ กันก่อน


ประเภทของป๊อปโอเวอร์

เราได้กล่าวถึงลักษณะการทำงานของการโต้ตอบที่ไม่ใช่ JavaScript แล้ว แต่พฤติกรรมของป๊อปโอเวอร์โดยรวมล่ะ จะเกิดอะไรขึ้นหากคุณไม่ต้องการใช้ "ปิดอย่างรวดเร็ว" หรือต้องการใช้รูปแบบ Singleton กับป๊อปโอเวอร์

Popover API ช่วยให้คุณระบุป๊อปโอเวอร์ได้ 3 ประเภทซึ่งมีลักษณะการทำงานแตกต่างกัน

[popover=auto]/[popover]:

  • การรองรับการซ้อน ซึ่งไม่ได้หมายถึงการซ้อนใน DOM เท่านั้น คำจำกัดความของป๊อปอัปบรรพบุรุษคือป๊อปอัปที่มีลักษณะดังนี้
    • ที่เกี่ยวข้องตามตำแหน่ง DOM (องค์ประกอบย่อย)
    • ที่เกี่ยวข้องโดยการทริกเกอร์แอตทริบิวต์ในองค์ประกอบย่อย เช่น popovertoggletarget, popovershowtarget และอื่นๆ
    • ที่เกี่ยวข้องกับแอตทริบิวต์ anchor (ภายใต้การพัฒนา CSS Anchoring API)
  • ปิดอย่างรวดเร็ว
  • การเปิดจะปิดป๊อปโอเวอร์อื่นๆ ที่ไม่ใช่ป๊อปโอเวอร์บรรพบุรุษ ลองเล่นเดโมด้านล่างซึ่งไฮไลต์วิธีการซ้อนป๊อปโอเวอร์ขององค์ประกอบหลัก ดูว่าการเปลี่ยนอินสแตนซ์ popoverhidetarget/popovershowtarget บางรายการเป็น popovertoggletarget จะเปลี่ยนแปลงสิ่งต่างๆ ได้อย่างไร
  • การปิดไฟดวงใดดวงหนึ่งจะปิดไฟทั้งหมด แต่การปิดไฟดวงใดดวงหนึ่งในกองจะปิดเฉพาะดวงที่อยู่เหนือขึ้นไปในกองเท่านั้น

[popover=manual]:

  • ไม่ปิดป๊อปโอเวอร์อื่นๆ
  • ปิดไม่ได้เมื่อแตะที่อื่น
  • ต้องปิดอย่างชัดเจนผ่านองค์ประกอบทริกเกอร์หรือ JavaScript

JavaScript API

เมื่อต้องการควบคุมป๊อปโอเวอร์ได้มากขึ้น คุณสามารถใช้ JavaScript ได้ คุณจะได้รับทั้งวิธีshowPopoverและhidePopover นอกจากนี้ คุณยังฟังเหตุการณ์ popovershow และ popoverhide ได้ด้วย

แสดงป๊อปโอเวอร์ js popoverElement.showPopover() ซ่อนป๊อปโอเวอร์

popoverElement.hidePopover()

ฟังว่ามีการแสดงป๊อปโอเวอร์หรือไม่

popoverElement.addEventListener('popovershow', doSomethingWhenPopoverShows)

ฟังว่ามีการแสดงป๊อปโอเวอร์และยกเลิกการแสดงป๊อปโอเวอร์

popoverElement.addEventListener('popovershow',event => {
  event.preventDefault();
  console.warn(We blocked a popover from being shown);
})

ฟังว่ามีการซ่อนป๊อปโอเวอร์หรือไม่

popoverElement.addEventListener('popoverhide', doSomethingWhenPopoverHides)

คุณยกเลิกการซ่อนป๊อปโอเวอร์ไม่ได้

popoverElement.addEventListener('popoverhide',event => {
  event.preventDefault();
  console.warn("You aren't allowed to cancel the hiding of a popover");
})

ตรวจสอบว่าป๊อปโอเวอร์อยู่ในเลเยอร์บนสุดหรือไม่ โดยทำดังนี้

popoverElement.matches(':open')

ซึ่งจะช่วยเพิ่มประสิทธิภาพในบางสถานการณ์ที่พบได้ไม่บ่อย เช่น แสดงป๊อปโอเวอร์หลังจากไม่มีการใช้งานเป็นระยะเวลาหนึ่ง

การสาธิตนี้มีป๊อปโอเวอร์ที่มีเสียงป๊อป ดังนั้นเราจึงต้องใช้ JavaScript เพื่อเล่นเสียง เมื่อคลิก เราจะซ่อนป๊อปโอเวอร์ เล่นเสียง แล้วแสดงป๊อปโอเวอร์อีกครั้ง

การช่วยเหลือพิเศษ

การช่วยเหลือพิเศษเป็นสิ่งสำคัญอันดับแรกในการพิจารณาเกี่ยวกับ Popover API การแมปการช่วยเหลือพิเศษจะเชื่อมโยงป๊อปโอเวอร์กับองค์ประกอบทริกเกอร์ตามที่จำเป็น ซึ่งหมายความว่าคุณไม่จำเป็นต้องประกาศแอตทริบิวต์ aria-* เช่น aria-haspopup หากคุณใช้แอตทริบิวต์ที่ทริกเกอร์รายการใดรายการหนึ่ง เช่น popovertoggletarget

สำหรับการจัดการโฟกัส คุณสามารถใช้แอตทริบิวต์ autofocus เพื่อย้ายโฟกัสไปยังองค์ประกอบภายในป๊อปโอเวอร์ได้ ซึ่งเหมือนกับ Dialog แต่จะแตกต่างกันเมื่อส่งคืนโฟกัส เนื่องจากมีการปิดด้วยการแตะนอกองค์ประกอบ ในกรณีส่วนใหญ่ การปิดป๊อปโอเวอร์จะคืนโฟกัสไปยังองค์ประกอบที่โฟกัสก่อนหน้านี้ แต่ระบบจะย้ายโฟกัสไปยังองค์ประกอบที่คลิกเมื่อปิดอย่างรวดเร็ว หากองค์ประกอบนั้นรับโฟกัสได้ ดูส่วนเกี่ยวกับการจัดการโฟกัสในคำอธิบาย

คุณจะต้องเปิด "เวอร์ชันเต็มหน้าจอ" ของการสาธิตนี้เพื่อดูการทำงาน

ในการสาธิตนี้ องค์ประกอบที่โฟกัสจะได้รับเส้นขอบสีเขียว ลองใช้แป้น Tab เพื่อไปยังส่วนต่างๆ ของอินเทอร์เฟซด้วยแป้นพิมพ์ โปรดทราบว่าระบบจะเปลี่ยนโฟกัสไปที่ใดเมื่อปิดป๊อปโอเวอร์ นอกจากนี้ คุณอาจสังเกตเห็นว่าหากกด Tab ไปเรื่อยๆ ป๊อปโอเวอร์จะปิด ระบบได้รับการออกแบบมาเช่นนี้ แม้ว่าป๊อปโอเวอร์จะมีการจัดการโฟกัส แต่ก็ไม่ได้ดักจับโฟกัส และการไปยังส่วนต่างๆ ด้วยแป้นพิมพ์จะระบุสัญญาณปิดเมื่อโฟกัสย้ายออกจากป๊อปโอเวอร์

การยึด (อยู่ระหว่างการพัฒนา)

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

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

การสาธิตนี้ใช้ Anchoring API ในสถานะปัจจุบัน ตำแหน่งของเรือจะตอบสนองต่อตำแหน่งของสมอในวิวพอร์ต

ต่อไปนี้คือตัวอย่าง CSS ที่ทำให้การสาธิตนี้ทำงานได้ ไม่ต้องใช้ JavaScript

.anchor {
  --anchor-name: --anchor;
}
.anchored {
  position: absolute;
  position-fallback: --compass;
}
@position-fallback --compass {
  @try {
    bottom: anchor(--anchor top);
    left: anchor(--anchor right);
  }
  @try {
    top: anchor(--anchor bottom);
    left: anchor(--anchor right);
  }
}

คุณดูรายละเอียดได้ที่นี่ นอกจากนี้ยังมี Polyfill สำหรับ API นี้ด้วย

ตัวอย่าง

ตอนนี้คุณคงคุ้นเคยกับสิ่งที่ป๊อปโอเวอร์มีให้และวิธีใช้แล้ว มาดูตัวอย่างกัน

การแจ้งเตือน

การสาธิตนี้แสดงการแจ้งเตือน "คัดลอกไปยังคลิปบอร์ด"

  • ใช้ [popover=manual]
  • เมื่อดำเนินการ ให้แสดงป๊อปโอเวอร์พร้อม showPopover
  • หลังจาก2000msหมดเวลา ให้ซ่อนด้วย hidePopover

ข้อความโทสต์

เดโมนี้ใช้ชั้นบนสุดเพื่อแสดงการแจ้งเตือนสไตล์ข้อความโทสต์

  • ป๊อปโอเวอร์ 1 รายการที่มีประเภท manual จะทำหน้าที่เป็นคอนเทนเนอร์
  • ระบบจะเพิ่มการแจ้งเตือนใหม่ลงในป๊อปโอเวอร์และแสดงป๊อปโอเวอร์
  • ระบบจะนำออกด้วย Web Animations API เมื่อคลิกและนำออกจาก DOM
  • หากไม่มีข้อความป๊อปอัปให้แสดง ระบบจะซ่อนป๊อปโอเวอร์

เมนูแบบซ้อน

การสาธิตนี้แสดงให้เห็นว่าเมนูการนำทางแบบซ้อนอาจทำงานอย่างไร

  • ใช้ [popover=auto] เนื่องจากอนุญาตให้ใช้ป๊อปโอเวอร์ที่ซ้อนกันได้
  • ใช้ autofocus ในลิงก์แรกของเมนูแบบเลื่อนลงแต่ละรายการเพื่อไปยังส่วนต่างๆ ด้วยแป้นพิมพ์
  • ซึ่งเหมาะอย่างยิ่งสำหรับ CSS Anchoring API แต่สำหรับการสาธิตนี้ คุณสามารถใช้ JavaScript จำนวนเล็กน้อยเพื่ออัปเดตตำแหน่งโดยใช้พร็อพเพอร์ตี้ที่กำหนดเอง
const ANCHOR = (anchor, anchored) => () => {
  const { top, bottom, left, right } = anchor.getBoundingClientRect();
  anchored.style.setProperty("--top", top);
  anchored.style.setProperty("--right", right);
  anchored.style.setProperty("--bottom", bottom);
  anchored.style.setProperty("--left", left);
};

PRODUCTS_MENU.addEventListener("popovershow", ANCHOR(PRODUCT_TARGET, PRODUCTS_MENU));

โปรดทราบว่าเนื่องจากเดโมนี้ใช้ autofocus จึงต้องเปิดใน "มุมมองแบบเต็มหน้าจอ" เพื่อใช้การไปยังส่วนต่างๆ ด้วยแป้นพิมพ์

ป๊อปโอเวอร์สื่อ

การสาธิตนี้แสดงวิธีป๊อปอัปสื่อ

  • ใช้ [popover=auto] เพื่อปิดอย่างรวดเร็ว
  • JavaScript จะรอฟังเหตุการณ์ play ของวิดีโอและแสดงวิดีโอขึ้นมา
  • ป๊อปโอเวอร์popoverhideจะหยุดวิดีโอชั่วคราว

ป๊อปโอเวอร์สไตล์ Wiki

การสาธิตนี้แสดงวิธีสร้างเคล็ดลับเครื่องมือเนื้อหาในบรรทัดที่มีสื่อ

  • ใช้ [popover=auto] การแสดงรายการหนึ่งจะซ่อนรายการอื่นๆ เนื่องจากไม่ได้เป็นบรรพบุรุษ
  • แสดงใน pointerenter ด้วย JavaScript
  • อีกหนึ่งตัวอย่างที่เหมาะอย่างยิ่งสำหรับ CSS Anchoring API

การสาธิตนี้สร้างลิ้นชักการนำทางโดยใช้ป๊อปโอเวอร์

  • ใช้ [popover=auto] เพื่อปิดอย่างรวดเร็ว
  • ใช้ autofocus เพื่อโฟกัสรายการนำทางแรก

การจัดการฉากหลัง

การสาธิตนี้แสดงวิธีจัดการฉากหลังสำหรับป๊อปโอเวอร์หลายรายการในกรณีที่คุณต้องการให้ ::backdrop แสดงเพียงรายการเดียว

  • ใช้ JavaScript เพื่อดูแลรายการป๊อปโอเวอร์ที่มองเห็นได้
  • ใช้ชื่อคลาสกับป๊อปโอเวอร์ที่ต่ำที่สุดในเลเยอร์บนสุด

ป๊อปโอเวอร์เคอร์เซอร์ที่กำหนดเอง

การสาธิตนี้แสดงวิธีใช้ popover เพื่อเลื่อน canvas ไปยังเลเยอร์บนสุดและใช้เพื่อแสดงเคอร์เซอร์ที่กำหนดเอง

  • โปรโมต canvas ไปยังเลเยอร์บนสุดด้วย showPopover และ [popover=manual]
  • เมื่อเปิดป๊อปโอเวอร์อื่นๆ ให้ซ่อนและแสดงป๊อปโอเวอร์ canvas เพื่อให้แน่ใจว่าป๊อปโอเวอร์นี้อยู่ด้านบน

ป๊อปอัป ActionSheet

การสาธิตนี้แสดงวิธีใช้ป๊อปโอเวอร์เป็นแผ่นการดำเนินการ

  • แสดงป๊อปโอเวอร์โดยค่าเริ่มต้นโดยลบล้าง display
  • ActionSheet จะเปิดขึ้นพร้อมทริกเกอร์ป๊อปโอเวอร์
  • เมื่อแสดงป๊อปโอเวอร์ ระบบจะเลื่อนป๊อปโอเวอร์ไปที่เลเยอร์บนสุดและแปลเป็นมุมมอง
  • คุณใช้การปิดอย่างรวดเร็วเพื่อกลับไปที่หน้าเดิมได้

ป๊อปโอเวอร์ที่เปิดใช้งานแป้นพิมพ์

การสาธิตนี้แสดงวิธีใช้ป๊อปโอเวอร์สำหรับ UI รูปแบบพาเล็ตคำสั่ง

  • ใช้ cmd + j เพื่อแสดงป๊อปโอเวอร์
  • input จะโฟกัสด้วย autofocus
  • ช่องตัวเลือกรวมคือกล่องที่ 2 popover ซึ่งอยู่ใต้ช่องป้อนข้อมูลหลัก
  • การปิดอย่างรวดเร็วจะปิดจานสีหากไม่มีเมนูแบบเลื่อนลง
  • อีกตัวอย่างหนึ่งของ Anchoring API

ป๊อปอัปที่กำหนดเวลา

การสาธิตนี้แสดงป๊อปอัปการไม่มีการใช้งานหลังจากผ่านไป 4 วินาที รูปแบบ UI ที่มักใช้ในแอปที่มีข้อมูลที่ปลอดภัยเกี่ยวกับผู้ใช้เพื่อแสดงโมดอลการออกจากระบบ

  • ใช้ JavaScript เพื่อแสดงป๊อปโอเวอร์หลังจากไม่มีการใช้งานเป็นระยะเวลาหนึ่ง
  • รีเซ็ตตัวจับเวลาเมื่อแสดงป๊อปโอเวอร์

โปรแกรมรักษาหน้าจอ

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

  • ใช้ JavaScript เพื่อแสดงป๊อปโอเวอร์หลังจากไม่มีการใช้งานเป็นระยะเวลาหนึ่ง
  • ปัดเบาๆ เพื่อซ่อนและรีเซ็ตตัวจับเวลา

การติดตามเคอร์เซอร์ข้อความ

การสาธิตนี้แสดงวิธีทำให้ป๊อปโอเวอร์ติดตามเคอร์เซอร์ของอินพุต

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

เมนูปุ่มการทำงานแบบลอย

การสาธิตนี้แสดงวิธีใช้ป๊อปโอเวอร์เพื่อใช้เมนูของปุ่มการทำงานแบบลอยโดยไม่ต้องใช้ JavaScript

  • โปรโมตป๊อปอัปประเภท manual ด้วยเมธอด showPopover นี่คือปุ่มหลัก
  • เมนูเป็นป๊อปโอเวอร์อีกรายการหนึ่งซึ่งเป็นเป้าหมายของปุ่มหลัก
  • เปิดเมนูด้วย popovertoggletarget
  • ใช้ autofocus เพื่อโฟกัสรายการเมนูแรกที่แสดง
  • การปิดแบบเบาจะปิดเมนู
  • การบิดไอคอนใช้ :has() อ่านเพิ่มเติมเกี่ยวกับ :has() ได้ในบทความนี้

เท่านี้ก็เรียบร้อย

ดังนั้นนี่คือข้อมูลเบื้องต้นเกี่ยวกับป๊อปโอเวอร์ ซึ่งจะเปิดตัวในอนาคตเป็นส่วนหนึ่งของความคิดริเริ่ม Open UI หากใช้อย่างเหมาะสม ฟีเจอร์นี้จะเป็นส่วนเสริมที่ยอดเยี่ยมสำหรับแพลตฟอร์มเว็บ

อย่าลืมดู Open UI เราจะคอยอัปเดตคำอธิบายเกี่ยวกับป๊อปโอเวอร์อยู่เสมอเมื่อ API มีการเปลี่ยนแปลง และนี่คือคอลเล็กชันสำหรับการสาธิตทั้งหมด

ขอขอบคุณที่แวะมา