โฮเวอร์การ์ดจะแสดงตัวอย่างเนื้อหาแบบอินเทอร์แอกทีฟเมื่อผู้ใช้แสดงความสนใจในลิงก์ (ผ่านการวางเมาส์เหนือหรือโฟกัส) ซึ่งจะแสดงต่อผู้ใช้ก่อนที่จะไปยังส่วนต่างๆ และให้เนื้อหาที่ผู้ใช้ต้องการหรือช่วยยืนยันว่าลิงก์จะมีเนื้อหาที่ผู้ใช้กำลังมองหา
หากต้องการเคล็ดลับเครื่องมือแบบข้อความธรรมดาที่ไม่มีการโต้ตอบแทนตัวอย่างลิงก์ที่มีโครงสร้าง โปรดดูหัวข้อแสดงเคล็ดลับเครื่องมือเมื่อวางเมาส์เหนือ
1. การทริกเกอร์โฮเวอร์การ์ด
ใช้ API Interest Invokers เพื่อทริกเกอร์โฮเวอร์การ์ด ซึ่งจะช่วยให้มั่นใจว่าการ์ดจะปรากฏทั้งเมื่อวางเมาส์เหนือและเมื่อโฟกัส และจัดการการเชื่อมต่อการช่วยเหลือพิเศษโดยอัตโนมัติ
- เพิ่มแอตทริบิวต์
popover="hint"ลงในคอนเทนเนอร์บัตร ใช้hintเพื่อหลีกเลี่ยงการปิดเมนูป๊อปโอเวอร์ที่ไม่เกี่ยวข้องซึ่งอาจเปิดอยู่ - เพิ่มแอตทริบิวต์
interestforลงในลิงก์ทริกเกอร์ซึ่งชี้ไปยังidของการ์ด
<a href="/article" interestfor="article-preview">Article title</a>
<!-- The `id` must match the `interestfor` value on the trigger. -->
<div id="article-preview" popover="hint" class="hovercard">
<h2>The buzz on hummingbirds</h2>
<p class="byline">By Delphi Aguilar</p>
<div>
<img src="bird.jpg" alt="A vibrant hummingbird">
<p>Brief summary of the article...</p>
</div>
</div>
คุณไม่จำเป็นต้องใส่ลิงก์เพิ่มเติมไปยังเนื้อหาภายในโฮเวอร์การ์ด เนื่องจากจะซ้ำซ้อนกับลิงก์ที่ทริกเกอร์
การช่วยเหลือพิเศษในตัวสำหรับ interestfor
เมื่อใช้ interestfor เบราว์เซอร์จะจัดการการเชื่อมต่อเทคโนโลยีความช่วยเหลือพิเศษให้คุณ ดังนี้
- ความหมายโดยนัย: เป้าหมายที่มี
popover="hint"จะได้รับบทบาทขั้นต่ำโดยนัยเป็นtooltipอย่าตั้งค่าrole="tooltip"ด้วยตนเอง - การเชื่อมโยงโดยนัย: เบราว์เซอร์จะเชื่อมโยงองค์ประกอบต้นทางกับเป้าหมายโดยนัยผ่าน
aria-describedbyเมื่อเป้าหมายเป็นข้อความธรรมดา หรือผ่านaria-detailsเมื่อเป้าหมายมีเนื้อหาแบบอินเทอร์แอกทีฟ อย่าเพิ่มaria-describedbyหรือaria-detailsลงในทริกเกอร์ - เนื้อหาแบบอินเทอร์แอกทีฟ: เนื่องจากสมาคมจะเปลี่ยนไปใช้
aria-detailsเมื่อจำเป็น เป้าหมายจึงได้รับอนุญาตให้มีเนื้อหาแบบอินเทอร์แอกทีฟ (เช่น ลิงก์ภายใน "การ์ดความสนใจ")
2. การจัดตำแหน่งด้วยการจัดตำแหน่ง Anchor
จัดตำแหน่งโฮเวอร์การ์ดให้สัมพันธ์กับทริกเกอร์โดยใช้การจัดตำแหน่ง Anchor ของ CSS เมื่อใช้ interestfor ทริกเกอร์จะกลายเป็น Anchor โดยนัยสำหรับป๊อปโอเวอร์
[popover].hovercard {
/* Position the card below the trigger, aligned with its inline-start edge
and spanning toward the inline-end, flipping if it overflows the viewport. */
position-area: block-end span-inline-end;
position-try-fallbacks: flip-block, flip-inline;
}
3. การสร้างภาพเคลื่อนไหวสำหรับการเข้าและออกฉาก
โดยค่าเริ่มต้น ระบบจะแสดงและยกเลิกการแสดงความสนใจสำหรับผู้ใช้แป้นพิมพ์และเมาส์โดยมีความล่าช้าครึ่งวินาที ซึ่งจะป้องกันไม่ให้ป๊อปโอเวอร์เป้าหมายเปิดขึ้นขณะกด Tab เพื่อไปยังส่วนต่างๆ ของหน้าหรือเลื่อนเมาส์ไปมา และป้องกันไม่ให้ปิดขณะเลื่อนเมาส์จากทริกเกอร์ไปยังป๊อปโอเวอร์ หากต้องการปรับเวลา ให้ใช้พร็อพเพอร์ตี้ CSS interest-delay
[interestfor]{
/* Shorthand for interest-delay-start and interest-delay-end */
interest-delay: 0.2s 0.1s;
}
หากผู้ใช้มีแนวโน้มที่จะเลื่อนผ่านทริกเกอร์หลายรายการอย่างรวดเร็ว ให้ตั้งค่าการหน่วงเวลาเริ่มต้นเป็น 0s หากป๊อปโอเวอร์ที่ทริกเกอร์ตามความสนใจเปิดอยู่แล้ว
:root:has(:interest-source) [interestfor] {
interest-delay-start: 0s;
}
ใช้ @starting-style เพื่อกำหนดภาพเคลื่อนไหวสำหรับการเข้า และใช้ transition-behavior: allow-discrete (ร่วมกับ display และ overlay) เพื่อสร้างภาพเคลื่อนไหวสำหรับการออกจากเลเยอร์บนสุด โดยจำกัดการเปลี่ยนภาพไว้หลัง @media (prefers-reduced-motion: no-preference)
[popover].hovercard {
opacity: 0;
transform-origin: top;
}
[popover].hovercard:popover-open {
opacity: 1;
transform: translateY(0) scale(1);
}
@starting-style {
[popover].hovercard:popover-open {
opacity: 0;
transform: translateY(-10px) scale(0.95);
}
}
/* MANDATORY: Respect user preference for reduced motion by selectively applying transitions. */
@media (prefers-reduced-motion: no-preference) {
[popover].hovercard {
transition:
opacity,
transform,
display,
overlay;
transition-duration: 0.4s;
transition-behavior: allow-discrete;
}
}
4. ไม่บังคับ: การเปลี่ยนรูปแบบไปยังหน้าถัดไปอย่างราบรื่น
คุณสามารถเลือกใช้การเปลี่ยนมุมมองข้ามเอกสารเพื่อสร้างภาพเคลื่อนไหว "มอร์ฟ" ที่ราบรื่นระหว่างโฮเวอร์การ์ดกับหน้าปลายทางได้ ดูคำแนะนำในการติดตั้งใช้งานได้ที่การเปลี่ยนข้ามเอกสารที่สอดคล้องกัน
เมื่อกำหนดค่า view-transition-name ที่ตรงกันให้กับองค์ประกอบในโฮเวอร์การ์ดและองค์ประกอบที่ตรงกันในหน้าถัดไป เบราว์เซอร์จะแสดงภาพเคลื่อนไหวขององค์ประกอบเหล่านั้นในการไปยังส่วนต่างๆ คุณสามารถตั้งชื่อองค์ประกอบหลายรายการ (เช่น ชื่อ รูปภาพ ข้อมูลผู้เขียน) เพื่อสร้างเอฟเฟกต์การเปลี่ยนรูปแบบที่ซับซ้อนและมีองค์ประกอบหลายรายการได้ กำหนด view-transition-name ให้กับองค์ประกอบในป๊อปโอเวอร์ที่เปิดอยู่โดยใช้ :popover-open เพื่อหลีกเลี่ยงการสร้าง view-transition-name ที่ซ้ำกันหรือต้องใช้ view-transition-name เฉพาะลิงก์
/* Opt-in to cross-document transitions on both pages */
@view-transition {
navigation: auto;
}
/* Don't show transitions when loading this page */
::view-transition-group(*) {
animation-duration: 0s;
}
/* Assign names ONLY when the popover is open to ensure only the correct elements are selected. */
[popover]:popover-open {
view-transition-name: --hovercard;
view-transition-class: morph;
h2 {
view-transition-name: --title;
view-transition-class: morph;
}
img {
view-transition-name: --image;
view-transition-class: morph;
}
}
บังคับ: เพื่อให้การเปลี่ยนผ่านมีความเสถียรและไม่กะพริบ หน้าปลายทางควรใช้ blocking="render" และ <link rel="expect"> เพื่อรอให้เนื้อหาสำคัญได้รับการแยกวิเคราะห์ก่อนแสดงผลเฟรมแรก
<!-- On the destination page: -->
<head>
<!-- Block rendering until the hero image and title are parsed,
ensuring the view transition snapshot is taken at the right time. -->
<link rel="expect" href="#main-content" blocking="render">
</head>
<body>
<main id="main-content">
<h1>The buzz on hummingbirds</h1>
<img src="bird.jpg">
</main>
</body>
/* On the destination page: */
main {
view-transition-name: --hovercard;
view-transition-class: morph;
}
h1 {
view-transition-name: --title;
view-transition-class: morph;
}
img {
view-transition-name: --image;
view-transition-class: morph;
}
/* By default no transition */
::view-transition-group(*) {
animation-duration: 0s;
}
/* Short transition for morphing elements */
::view-transition-group(.morph) {
animation-duration: 0.4s;
}
/* Disable transition if no `old` view */
::view-transition-new(.morph):only-child {
animation-duration: 0s;
}
กลยุทธ์สำรอง
เนื่องจากทริกเกอร์เป็นลิงก์ <a href="..."> มาตรฐาน เบราว์เซอร์ที่ไม่รองรับจึงยังคงไปยังส่วนต่างๆ ได้เมื่อคลิก หากคุณเลือกที่จะถือว่าโฮเวอร์การ์ดเป็นการเพิ่มประสิทธิภาพแบบต่อเนื่อง เมื่อจำเป็นต้องรองรับโฮเวอร์การ์ดข้ามเบราว์เซอร์ ให้โหลด Polyfill แบบมีเงื่อนไขตามความจำเป็น
การรองรับเบราว์เซอร์และทางเลือกสำรองสำหรับ 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 หากยอมรับได้สำหรับกรณีการใช้งาน
การสำรองและการรองรับเบราว์เซอร์สำหรับ Interest Invoker
Interest Invoker ต้องใช้ Polyfill แบบมีเงื่อนไขโดยใช้แพ็กเกจ Polyfill interestfor จาก NPM แนะนำให้รวม Polyfill แทนการใช้ CDN
บังคับ: ตรวจหาฟีเจอร์โดยตรวจสอบพร็อพเพอร์ตี้ interestForElement ใน HTMLButtonElement.prototype และโหลด Polyfill เฉพาะเมื่อไม่มีการรองรับแบบเนทีฟ
<script type="module">
if (!HTMLButtonElement.prototype.hasOwnProperty("interestForElement")) {
// CDN link only used for example, prefer bundling.
await import("https://unpkg.com/interestfor@latest");
}
</script>
ข้อควรระวังเกี่ยวกับ CSS Polyfill
เมื่อใช้ Polyfill, CSS API จะเปลี่ยนแปลงเล็กน้อยเพื่อรองรับการขาดการสนับสนุนคลาสเทียมและพร็อพเพอร์ตี้แบบเนทีฟ
- Pseudo-class: Polyfill ไม่สามารถกำหนด Pseudo-class
:interest-sourceและ:interest-targetจริงได้ จึงใช้คลาส.interest-sourceและ.interest-targetแทน บังคับ: รวมเข้ากับ:is()เพื่อรองรับทั้งสถานะเนทีฟและ Polyfill
/* Styles to apply when the effect is being previewed */
:is(:interest-source, .interest-source) { /* ... */ }
:is(:interest-target, .interest-target) { /* ... */ }
- พร็อพเพอร์ตี้ CSS: สำหรับ
interest-delay,interest-delay-startและinterest-delay-endPolyfill ต้องใช้ตัวแปร CSS เนื่องจากไม่สามารถอ่านคุณสมบัติที่กำหนดเองได้โดยตรงในเบราว์เซอร์ทั้งหมด
/* Adjust the start and end delay for interest invokers */
[interestfor] {
--interest-delay-start: 0.2s;
interest-delay-start: var(--interest-delay-start);
--interest-delay-end: 0.1s;
interest-delay-end: var(--interest-delay-end);
}