การสร้างคอมโพเนนต์เคล็ดลับเครื่องมือ

ภาพรวมพื้นฐานของวิธีสร้างองค์ประกอบที่กำหนดเองของเคล็ดลับเครื่องมือที่ปรับสีและเข้าถึงได้ง่าย

ในโพสต์นี้ ฉันต้องการแชร์ความคิดเห็นเกี่ยวกับวิธีสร้างองค์ประกอบที่กำหนดเองของ <tool-tip> ที่ปรับสีได้และเข้าถึงได้ง่าย ลองดูการสาธิตและดูแหล่งที่มา

แสดงเคล็ดลับเครื่องมือซึ่งใช้งานกับตัวอย่างและรูปแบบสีต่างๆ ได้

หากชอบวิดีโอ นี่คือโพสต์นี้เวอร์ชัน YouTube

ภาพรวม

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

สิ่งที่ควรทำ: ติดป้ายกำกับอินพุตเสมอ
อย่าใช้เคล็ดลับเครื่องมือแทนป้ายกำกับ

เปิด/ปิดเคล็ดลับเครื่องมือกับเคล็ดลับเครื่องมือ

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

นี่เป็นวิดีโอเคล็ดลับสลับจากเว็บไซต์ Designcember แบบวางซ้อนพร้อมอินเทอร์แอกทีฟที่ผู้ใช้สามารถปักหมุดเปิดและสำรวจได้ จากนั้นปิดด้วยแสงหรือแป้น Escape

ความท้าทาย GUI นี้เป็นเส้นทางของเคล็ดลับเครื่องมือ โดยพยายามทำเกือบทุกสิ่ง ด้วย CSS และวิธีสร้างมีดังนี้

Markup

ฉันเลือกใช้องค์ประกอบที่กำหนดเอง <tool-tip> ผู้เขียนไม่จำเป็นต้องสร้างองค์ประกอบที่กำหนดเอง เป็นคอมโพเนนต์เว็บหากไม่ต้องการ เบราว์เซอร์จะปฏิบัติต่อ <foo-bar> เหมือนกับ <div> คุณอาจคิดว่าองค์ประกอบที่กำหนดเองก็อย่างเช่นชื่อคลาส ที่มีความเฉพาะเจาะจงน้อยลง โดยไม่จำเป็นต้องใช้ JavaScript

<tool-tip>A tooltip</tool-tip>

ซึ่งคล้ายกับ div ที่มีข้อความอยู่ด้านใน เราสามารถเชื่อมโยงกับโครงสร้างการช่วยเหลือพิเศษของโปรแกรมอ่านหน้าจอที่รองรับได้โดยการเพิ่ม [role="tooltip"]

<tool-tip role="tooltip">A tooltip</tool-tip>

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

ภาพหน้าจอของโครงสร้างการช่วยเหลือพิเศษสำหรับเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome ซึ่งแสดง HTML แสดงลิงก์ที่มีข้อความ &quot;top&quot;; มี tooltip: &quot;Hey, a tooltip!&quot; ที่โฟกัสได้ ข้างในประกอบด้วยข้อความแบบคงที่ของ &quot;top&quot; และองค์ประกอบเคล็ดลับเครื่องมือ

ถัดไป เราต้องการเคล็ดลับเครื่องมือให้ไม่สามารถโฟกัสได้ หากโปรแกรมอ่านหน้าจอไม่เข้าใจบทบาทเคล็ดลับเครื่องมือ โปรแกรมก็จะอนุญาตให้ผู้ใช้โฟกัสที่ <tool-tip> เพื่ออ่านเนื้อหาโดยที่ผู้ใช้ไม่จำเป็นต้องใช้งาน โปรแกรมอ่านหน้าจอ จะเพิ่มเนื้อหาลงในองค์ประกอบระดับบนสุด จึงไม่จำเป็นต้องโฟกัสทำให้เข้าถึงง่าย เราสามารถใช้ inert เพื่อให้แน่ใจว่าไม่มีผู้ใช้พบเนื้อหาเคล็ดลับเครื่องมือนี้โดยไม่ได้ตั้งใจในขั้นตอนแท็บ

<tool-tip inert role="tooltip">A tooltip</tool-tip>

ภาพหน้าจออีกภาพหนึ่งของโครงสร้างการช่วยเหลือพิเศษในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome ตอนนี้องค์ประกอบเคล็ดลับเครื่องมือหายไป

จากนั้นผมเลือกที่จะใช้แอตทริบิวต์เป็นอินเทอร์เฟซเพื่อระบุตำแหน่งของเคล็ดลับเครื่องมือ โดยค่าเริ่มต้น <tool-tip> ทั้งหมดจะถือว่าอยู่ในตำแหน่ง "ด้านบน" แต่คุณปรับแต่งตำแหน่งในองค์ประกอบได้โดยการเพิ่ม tip-position ดังนี้

<tool-tip role="tooltip" tip-position="right ">A tooltip</tool-tip>

ภาพหน้าจอของลิงก์ที่มีเคล็ดลับเครื่องมือทางด้านขวาพร้อมข้อความ &quot;เคล็ดลับเครื่องมือ&quot;

ฉันมักจะใช้แอตทริบิวต์แทนคลาสสำหรับสิ่งต่างๆ แบบนี้เพื่อให้ <tool-tip> กำหนดหลายตำแหน่งพร้อมกันไม่ได้ สามารถเลือกได้อย่างใดอย่างหนึ่งเท่านั้น หรือไม่เลือกเลย

สุดท้าย วางองค์ประกอบ <tool-tip> ไว้ภายในองค์ประกอบที่ต้องการให้เคล็ดลับเครื่องมือ ตรงนี้ผมจะแชร์ข้อความ alt กับผู้ใช้ที่เห็นสายตาโดยการวางรูปภาพและ <tool-tip> ไว้ภายในองค์ประกอบ <picture>

<picture>
  <img alt="The GUI Challenges skull logo" width="100" src="...">
  <tool-tip role="tooltip" tip-position="bottom">
    The <b>GUI Challenges</b> skull logo
  </tool-tip>
</picture>

ภาพหน้าจอของรูปภาพที่มีเคล็ดลับเครื่องมือที่เขียนว่า &quot;โลโก้หัวกะโหลก
GUI Challenge&quot;

ตรงนี้ฉันจะวาง <tool-tip> ไว้ภายในองค์ประกอบ <abbr>:

<p>
  The <abbr>HTML <tool-tip role="tooltip" tip-position="top">Hyper Text Markup Language</tool-tip></abbr> abbr element.
</p>

ภาพหน้าจอของย่อหน้าที่มีตัวย่อ HTML ที่ขีดเส้นใต้ พร้อมเคล็ดลับเครื่องมือด้านบน
ที่เขียนว่า &quot;ภาษามาร์กอัป Hyper Text&quot;

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

เนื่องจากผมเลือกสร้างเคล็ดลับเครื่องมือและไม่ใช่สลับเคล็ดลับ ส่วนนี้จึงง่ายกว่ามาก ก่อนอื่น เราขอสรุปประสบการณ์ของผู้ใช้ที่ต้องการ

  1. ซ่อนข้อความเสริมในพื้นที่ที่จำกัดหรืออินเทอร์เฟซที่ไม่ยุ่งเหยิง
  2. เมื่อผู้ใช้วางเมาส์เหนือองค์ประกอบ โฟกัส หรือใช้การแตะเพื่อโต้ตอบกับองค์ประกอบ ข้อความจะแสดงขึ้นมา
  3. เมื่อวางเมาส์เหนือ โฟกัสหรือการแตะสิ้นสุดลง ให้ซ่อนข้อความอีกครั้ง
  4. สุดท้าย ตรวจสอบว่าการเคลื่อนไหวลดลงหากผู้ใช้ระบุค่ากำหนดสำหรับการเคลื่อนไหวที่ลดลง

เป้าหมายของเราคือการส่งข้อความเสริมแบบออนดีมานด์ ผู้ใช้เมาส์หรือแป้นพิมพ์ที่เห็นสามารถวางเมาส์เหนือข้อความเพื่อดูข้อความด้วยตาของตัวเอง ผู้ใช้โปรแกรมอ่านหน้าจอที่มองไม่เห็นสามารถโฟกัสไปที่ข้อความเพื่อเปิดดูข้อความผ่านเครื่องมือ

ภาพหน้าจอของ MacOS VoiceOver อ่านลิงก์พร้อมเคล็ดลับเครื่องมือ

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

ภาพหน้าจอของโครงสร้างการช่วยเหลือพิเศษสำหรับ Chrome DevTools ซึ่งมีข้อความลิงก์ระบุว่า
&quot;เคล็ดลับเครื่องมือด้านบนนี้!&quot;

เพิ่มองค์ประกอบเทียมเฉพาะโปรแกรมอ่านหน้าจอลงใน <tool-tip> แล้วเราจะเพิ่มข้อความพรอมต์ของเราเองสำหรับผู้ใช้ที่มองไม่เห็น

&::before {
  content: "; Has tooltip: ";
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: inset(50%);
  height: 1px;
  width: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
}

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

ภาพหน้าจอที่อัปเดตของโครงสร้างการช่วยเหลือพิเศษของ Chrome DevTools ซึ่งข้อความลิงก์มีการปรับปรุงวลี &quot;ด้านบน มีเคล็ดลับเครื่องมือ: Hey, tooltip!&quot;

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

รูปแบบ

องค์ประกอบ <tool-tip> จะเป็นองค์ประกอบย่อยขององค์ประกอบที่เป็นตัวแทนข้อความเสริม ดังนั้นมาเริ่มกันด้วยข้อมูลสำคัญสำหรับเอฟเฟกต์การวางซ้อนกันก่อน นำออกจากกระบวนการทำงานของเอกสารด้วย position absolute:

tool-tip {
  position: absolute;
  z-index: 1;
}

หากเนื้อหาหลักไม่ใช่บริบทแบบซ้อนกัน เคล็ดลับเครื่องมือจะจัดตำแหน่งเองให้อยู่ในตำแหน่งที่ใกล้ที่สุด ซึ่งไม่ได้เป็นสิ่งที่เราต้องการ มีตัวเลือกใหม่ในบล็อกที่ช่วยได้ :has() ดังนี้

การสนับสนุนเบราว์เซอร์

  • 105
  • 105
  • 121
  • 15.4

แหล่งที่มา

:has(> tool-tip) {
  position: relative;
}

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

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

tool-tip {
  …
  pointer-events: none;
  user-select: none;
}

จากนั้น ซ่อนเคล็ดลับเครื่องมือที่มีความทึบแสงเพื่อให้เราเปลี่ยนเคล็ดลับเครื่องมือด้วยครอสเฟดได้

tool-tip {
  opacity: 0;
}

:has(> tool-tip):is(:hover, :focus-visible, :active) > tool-tip {
  opacity: 1;
}

:is() และ :has() จะช่วยทำงานแทนในส่วนนี้ โดยทำให้ tool-tip ที่มีองค์ประกอบระดับบนสุดรับรู้ถึงการโต้ตอบของผู้ใช้เพื่อเปิด/ปิดการแสดงเคล็ดลับเครื่องมือย่อย ผู้ใช้เมาส์สามารถโฟกัสที่แป้นพิมพ์และโปรแกรมอ่านหน้าจอ และผู้ใช้แบบแตะจะแตะได้

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

ภาพหน้าจอของเคล็ดลับเครื่องมือในโหมดมืดที่ลอยอยู่เหนือลิงก์ &quot;block-start&quot;

tool-tip {
  --_p-inline: 1.5ch;
  --_p-block: .75ch;
  --_triangle-size: 7px;
  --_bg: hsl(0 0% 20%);
  --_shadow-alpha: 50%;

  --_bottom-tip: conic-gradient(from -30deg at bottom, rgba(0,0,0,0), #000 1deg 60deg, rgba(0,0,0,0) 61deg) bottom / 100% 50% no-repeat;
  --_top-tip: conic-gradient(from 150deg at top, rgba(0,0,0,0), #000 1deg 60deg, rgba(0,0,0,0) 61deg) top / 100% 50% no-repeat;
  --_right-tip: conic-gradient(from -120deg at right, rgba(0,0,0,0), #000 1deg 60deg, rgba(0,0,0,0) 61deg) right / 50% 100% no-repeat;
  --_left-tip: conic-gradient(from 60deg at left, rgba(0,0,0,0), #000 1deg 60deg, rgba(0,0,0,0) 61deg) left / 50% 100% no-repeat;

  pointer-events: none;
  user-select: none;

  opacity: 0;
  transform: translateX(var(--_x, 0)) translateY(var(--_y, 0));
  transition: opacity .2s ease, transform .2s ease;

  position: absolute;
  z-index: 1;
  inline-size: max-content;
  max-inline-size: 25ch;
  text-align: start;
  font-size: 1rem;
  font-weight: normal;
  line-height: normal;
  line-height: initial;
  padding: var(--_p-block) var(--_p-inline);
  margin: 0;
  border-radius: 5px;
  background: var(--_bg);
  color: CanvasText;
  will-change: filter;
  filter:
    drop-shadow(0 3px 3px hsl(0 0% 0% / var(--_shadow-alpha)))
    drop-shadow(0 12px 12px hsl(0 0% 0% / var(--_shadow-alpha)));
}

/* create a stacking context for elements with > tool-tips */
:has(> tool-tip) {
  position: relative;
}

/* when those parent elements have focus, hover, etc */
:has(> tool-tip):is(:hover, :focus-visible, :active) > tool-tip {
  opacity: 1;
  transition-delay: 200ms;
}

/* prepend some prose for screen readers only */
tool-tip::before {
  content: "; Has tooltip: ";
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: inset(50%);
  height: 1px;
  width: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
}

/* tooltip shape is a pseudo element so we can cast a shadow */
tool-tip::after {
  content: "";
  background: var(--_bg);
  position: absolute;
  z-index: -1;
  inset: 0;
  mask: var(--_tip);
}

/* top tooltip styles */
tool-tip:is(
  [tip-position="top"],
  [tip-position="block-start"],
  :not([tip-position]),
  [tip-position="bottom"],
  [tip-position="block-end"]
) {
  text-align: center;
}

การปรับธีม

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

@media (prefers-color-scheme: light) {
  tool-tip {
    --_bg: white;
    --_shadow-alpha: 15%;
  }
}

ภาพหน้าจอแสดงข้างกันของเคล็ดลับเครื่องมือเวอร์ชันสว่างและมืด

สำหรับธีมสว่าง เราปรับพื้นหลังเป็นสีขาวและทำให้เงาไม่ค่อยโดดเด่นด้วยการปรับความทึบแสง

ขวาไปซ้าย

และเพื่อรองรับโหมดการอ่านจากขวาไปซ้าย พร็อพเพอร์ตี้ที่กำหนดเองจะจัดเก็บค่าของทิศทางเอกสารเป็นค่า -1 หรือ 1 ตามลำดับ

tool-tip {
  --isRTL: -1;
}

tool-tip:dir(rtl) {
  --isRTL: 1;
}

ซึ่งสามารถใช้เพื่อช่วยในการจัดตำแหน่งเคล็ดลับเครื่องมือ ดังนี้

tool-tip[tip-position="top"]) {
  --_x: calc(50% * var(--isRTL));
}

และช่วยกำหนดตำแหน่งของรูปสามเหลี่ยม ดังนี้

tool-tip[tip-position="right"]::after {
  --_tip: var(--_left-tip);
}

tool-tip[tip-position="right"]:dir(rtl)::after {
  --_tip: var(--_right-tip);
}

สุดท้ายนี้ ยังใช้สำหรับการแปลงเชิงตรรกะใน translateX() ได้ด้วย

--_x: calc(var(--isRTL) * -3px * -1);

การจัดตำแหน่งเคล็ดลับเครื่องมือ

จัดตำแหน่งเคล็ดลับเครื่องมืออย่างสมเหตุสมผลด้วยพร็อพเพอร์ตี้ inset-block หรือ inset-inline เพื่อจัดการทั้งตำแหน่งเคล็ดลับเครื่องมือทางกายภาพและเชิงตรรกะ โค้ดต่อไปนี้แสดงการจัดรูปแบบตำแหน่งทั้ง 4 ตำแหน่งสำหรับทิศทางจากซ้ายไปขวาและขวาไปซ้าย

การจัดข้อความด้านบนและบล็อกเริ่มต้น

ภาพหน้าจอแสดงความแตกต่างของตำแหน่งระหว่างตำแหน่งบนสุดจากซ้ายไปขวากับตำแหน่งด้านบนจากขวาไปซ้าย

tool-tip:is([tip-position="top"], [tip-position="block-start"], :not([tip-position])) {
  inset-inline-start: 50%;
  inset-block-end: calc(100% + var(--_p-block) + var(--_triangle-size));
  --_x: calc(50% * var(--isRTL));
}

tool-tip:is([tip-position="top"], [tip-position="block-start"], :not([tip-position]))::after {
  --_tip: var(--_bottom-tip);
  inset-block-end: calc(var(--_triangle-size) * -1);
  border-block-end: var(--_triangle-size) solid transparent;
}

การจัดข้อความส่วนท้ายด้านขวาและในบรรทัด

ภาพหน้าจอแสดงความแตกต่างของตำแหน่งระหว่างตำแหน่งด้านขวาจากซ้ายไปขวากับตำแหน่งสิ้นสุดในบรรทัดจากขวาไปซ้าย

tool-tip:is([tip-position="right"], [tip-position="inline-end"]) {
  inset-inline-start: calc(100% + var(--_p-inline) + var(--_triangle-size));
  inset-block-end: 50%;
  --_y: 50%;
}

tool-tip:is([tip-position="right"], [tip-position="inline-end"])::after {
  --_tip: var(--_left-tip);
  inset-inline-start: calc(var(--_triangle-size) * -1);
  border-inline-start: var(--_triangle-size) solid transparent;
}

tool-tip:is([tip-position="right"], [tip-position="inline-end"]):dir(rtl)::after {
  --_tip: var(--_right-tip);
}

การจัดแนวชิดด้านล่างและส่วนปลาย

ภาพหน้าจอแสดงความแตกต่างของตำแหน่งระหว่างตำแหน่งจากซ้ายไปขวากับตำแหน่งปลายบล็อกแบบขวาไปซ้าย

tool-tip:is([tip-position="bottom"], [tip-position="block-end"]) {
  inset-inline-start: 50%;
  inset-block-start: calc(100% + var(--_p-block) + var(--_triangle-size));
  --_x: calc(50% * var(--isRTL));
}

tool-tip:is([tip-position="bottom"], [tip-position="block-end"])::after {
  --_tip: var(--_top-tip);
  inset-block-start: calc(var(--_triangle-size) * -1);
  border-block-start: var(--_triangle-size) solid transparent;
}

การจัดข้อความเริ่มต้นแบบอินไลน์และด้านซ้าย

ภาพหน้าจอแสดงความแตกต่างของตำแหน่งระหว่างตำแหน่งซ้ายไปขวากับตำแหน่งเริ่มต้นในบรรทัดจากขวาไปซ้าย

tool-tip:is([tip-position="left"], [tip-position="inline-start"]) {
  inset-inline-end: calc(100% + var(--_p-inline) + var(--_triangle-size));
  inset-block-end: 50%;
  --_y: 50%;
}

tool-tip:is([tip-position="left"], [tip-position="inline-start"])::after {
  --_tip: var(--_right-tip);
  inset-inline-end: calc(var(--_triangle-size) * -1);
  border-inline-end: var(--_triangle-size) solid transparent;
}

tool-tip:is([tip-position="left"], [tip-position="inline-start"]):dir(rtl)::after {
  --_tip: var(--_left-tip);
}

แอนิเมชัน

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

การเปลี่ยนผ่านเริ่มต้นที่ปลอดภัยและมีความหมาย

จัดรูปแบบองค์ประกอบเคล็ดลับเครื่องมือให้มีความทึบแสงและเปลี่ยนรูปแบบดังนี้

tool-tip {
  opacity: 0;
  transform: translateX(var(--_x, 0)) translateY(var(--_y, 0));
  transition: opacity .2s ease, transform .2s ease;
}

:has(> tool-tip):is(:hover, :focus-visible, :active) > tool-tip {
  opacity: 1;
  transition-delay: 200ms;
}

การเพิ่มการเคลื่อนไหวในการเปลี่ยน

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

@media (prefers-reduced-motion: no-preference) {
  :has(> tool-tip:is([tip-position="top"], [tip-position="block-start"], :not([tip-position]))):not(:hover):not(:focus-visible):not(:active) tool-tip {
    --_y: 3px;
  }

  :has(> tool-tip:is([tip-position="right"], [tip-position="inline-end"])):not(:hover):not(:focus-visible):not(:active) tool-tip {
    --_x: -3px;
  }

  :has(> tool-tip:is([tip-position="bottom"], [tip-position="block-end"])):not(:hover):not(:focus-visible):not(:active) tool-tip {
    --_y: -3px;
  }

  :has(> tool-tip:is([tip-position="left"], [tip-position="inline-start"])):not(:hover):not(:focus-visible):not(:active) tool-tip {
    --_x: 3px;
  }
}

โปรดทราบว่านี่คือการตั้งค่าสถานะ "ออก" เนื่องจากสถานะ "ใน" อยู่ที่ translateX(0)

JavaScript

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

สคริปต์ Polyfill จะดำเนินการ 2 อย่าง โดยจะดำเนินการก็ต่อเมื่อเบราว์เซอร์ไม่รองรับ :has() ขั้นแรก ตรวจสอบการสนับสนุน :has():

if (!CSS.supports('selector(:has(*))')) {
  // do work
}

ถัดไป ค้นหาองค์ประกอบระดับบนสุดของ <tool-tip> แล้วตั้งชื่อคลาสที่จะใช้

if (!CSS.supports('selector(:has(*))')) {
  document.querySelectorAll('tool-tip').forEach(tooltip =>
    tooltip.parentNode.classList.add('has_tool-tip'))
}

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

if (!CSS.supports('selector(:has(*))')) {
  document.querySelectorAll('tool-tip').forEach(tooltip =>
    tooltip.parentNode.classList.add('has_tool-tip'))

  let styles = document.createElement('style')
  styles.textContent = `
    .has_tool-tip {
      position: relative;
    }
    .has_tool-tip:is(:hover, :focus-visible, :active) > tool-tip {
      opacity: 1;
      transition-delay: 200ms;
    }
  `
  document.head.appendChild(styles)
}

เท่านี้ก็เรียบร้อย ตอนนี้เบราว์เซอร์ทุกชนิดจะแสดงเคล็ดลับเครื่องมือได้อย่างมีความสุข หากไม่รองรับ :has()

บทสรุป

ตอนนี้คุณก็รู้แล้วว่าตัวเองทำยังไง คุณ ‽ 🙂 เราหวังเป็นอย่างยิ่งว่าจะได้ใช้ popup API ที่จะช่วยให้สามารถใช้สลับเคล็ดลับได้ง่ายขึ้น, เลเยอร์ด้านบนสำหรับการไม่มีการรบดัชนี z และ anchor API สำหรับจัดตำแหน่งสิ่งต่างๆ ในหน้าต่างให้ดีขึ้น ระหว่างนี้ ผมจะทำเคล็ดลับเครื่องมือให้

มาลองเปลี่ยนแนวทางของเราและเรียนรู้วิธีทั้งหมดเพื่อสร้างเว็บกันเถอะ

สร้างเดโม ลิงก์ทวีตฉัน แล้วฉันจะเพิ่มลงในส่วนรีมิกซ์ของชุมชนด้านล่าง

รีมิกซ์ของชุมชน

ยังไม่มีอะไรให้ดูที่นี่

แหล่งข้อมูล