• Popover API เข้ามาแทนที่ JavaScript event listener, การจัดการสถานะ และการซิงก์แอตทริบิวต์ ARIA แบบแมนนวลที่เคยจำเป็นสำหรับการทำทูลทิป
  • แค่มีแอตทริบิวต์ popover และ popovertarget ก็เปิด/ปิดได้ พร้อมรองรับปุ่ม Esc และ การนำทางด้วยคีย์บอร์ด โดยอัตโนมัติ
  • ทำให้การทำงานร่วมกับ screen reader คาดเดาได้มากขึ้น, ซิงก์ aria-expanded อัตโนมัติ และ กู้คืนโฟกัส ได้ จนบั๊กด้านการเข้าถึงทั้งบางหมวดหายไปเลย
  • แม้บางส่วนอย่างการควบคุมจังหวะเวลาและการตรวจจับ hover intent ยังต้องใช้ JavaScript แต่โมเดลปฏิสัมพันธ์หลักถูกย้ายให้เบราว์เซอร์ดูแล
  • ถ้าเป็นดีไซน์ซิสเต็มขนาดใหญ่หรือกรณีที่ต้องการการจัดวางตำแหน่งซับซ้อน ไลบรารียังมีประโยชน์อยู่ แต่ ค่าเริ่มต้นกำลังเปลี่ยนไปเป็น Native API

ปัญหาของทูลทิปแบบเดิม

  • ก่อนมี Popover API เบราว์เซอร์ยังไม่มีแนวคิดเรื่อง ทูลทิปแบบเนทีฟ ที่ทำงานได้ครอบคลุมทั้งเมาส์ คีย์บอร์ด และเทคโนโลยีช่วยการเข้าถึง
  • รูปแบบเดิมถูกทำซ้ำอยู่เสมอ: องค์ประกอบตัวกระตุ้น, องค์ประกอบทูลทิปที่ซ่อนอยู่ และ JavaScript ที่คอยประสานทั้งสองส่วน
  • แม้ดูเหมือนเรียบง่าย แต่พอใช้งานจริงกลับเจอปัญหาหลากหลาย
    • ผู้ใช้คีย์บอร์ดกด Tab เข้าไปที่ trigger แล้วทูลทิปไม่แสดง
    • screen reader อ่านซ้ำสองรอบ หรือไม่อ่านเลย
    • เมื่อเลื่อนเมาส์เร็ว ๆ จะเกิด การกะพริบ (flicker)
    • เนื้อหาซ้อนทับกันบนหน้าจอขนาดเล็ก
    • ปิดด้วยปุ่ม Esc ไม่ได้ หรือโฟกัสหาย
  • เมื่อเวลาผ่านไป โค้ดจะพองขึ้นจากการสะสม event listener, การแยกจัดการ hover/focus, เคสพิเศษของการคลิกภายนอก และการซิงก์แอตทริบิวต์ ARIA แบบแมนนวล

เหตุผลที่ต้องใช้ไลบรารี

  • ไลบรารีช่วยทำงานจริงอย่าง การจัดตำแหน่ง, การพลิกตำแหน่งเมื่อชนขอบ viewport, การประสาน event ตามชนิดอินพุต และการรับรู้การเลื่อนในเลย์เอาต์ที่ซับซ้อน
  • แค่เรื่องการจัดตำแหน่งอย่างเดียวก็ซับซ้อนพอจะทำให้การพึ่งพาไลบรารีดูสมเหตุสมผล เพราะต้องรับมือกับ scroll container, transform และ responsive layout
  • แต่ปัญหาจริงอยู่ที่ พฤติกรรมด้านการเข้าถึง
    • ทูลทิปแสดงช้า หรือไม่แสดงเลย
    • ตอนกดแท็บเร็ว ๆ ทูลทิปถูกข้ามไป
    • การปิดด้วย Esc ไม่เสถียร
  • ผู้ใช้เมาส์คาดหวัง ความทันทีทันใด ขณะที่ผู้ใช้คีย์บอร์ดคาดหวัง ความคาดเดาได้ และเมื่อพยายามรองรับทั้งสองแบบ ก็เกิดทั้งความหน่วงและ edge case
  • บน screen reader ทูลทิปอาจถูกอ่าน, ไม่ถูกอ่าน หรือถูกอ่านซ้ำสองครั้ง เป็น พฤติกรรมที่ไม่สม่ำเสมอ
  • ถ้าพลาดอัปเดตแอตทริบิวต์ ARIA ไปแม้เพียงตัวเดียว ก็อาจทำให้ accessibility tree สับสนหรือกลายเป็นสถานะที่มองไม่เห็น

ไม่ใช่ปัญหาที่ตัวโค้ด แต่เป็นข้อจำกัดของแพลตฟอร์ม

  • แม้อิมพลีเมนเทชันจะผ่านการทดสอบและไลบรารีก็แข็งแรง แต่ปัญหาแกนกลางคือ เว็บแพลตฟอร์มไม่มี affordance ที่เหมาะสม
  • เบราว์เซอร์ไม่มีวิธีรู้เลยว่าองค์ประกอบนั้นคือทูลทิป ทุกอย่างจึงอาศัยองค์ประกอบทั่วไป, event listener, ARIA แบบแมนนวล และตรรกะปิดเองตาม ข้อตกลงร่วม (convention)
  • เมื่อเวลาผ่านไป การเปลี่ยนแปลงเล็ก ๆ ก็มีความเสี่ยง และการแก้ไขเล็กน้อยก็อาจทำให้เกิด regression ได้ เป็น โครงสร้างที่เปราะบาง
  • ทุกครั้งที่เพิ่มทูลทิปใหม่ ก็รับช่วงความซับซ้อนเดิมเข้ามาทั้งหมด

เริ่มใช้ Popover API ครั้งแรก

  • แรงจูงใจไม่ใช่เพราะอยากลองของใหม่ แต่เป็นเพราะ เหนื่อยกับการดูแลพฤติกรรมทูลทิปที่เบราว์เซอร์ควรเข้าใจเองอยู่แล้ว
  • เริ่มจากรูปแบบที่เล็กที่สุด: <button popovertarget="tip-1"> + <div id="tip-1" popover="manual" role="tooltip">
  • ไม่มี event listener, ไม่มีการติดตามสถานะ, ไม่มีการอัปเดต ARIA จาก JavaScript
  • เมื่อโฟกัสที่ปุ่ม ทูลทิปจะแสดง และเมื่อกด Esc ก็หายไป

ความแตกต่างที่รู้สึกได้ทันที

  • เปิด/ปิดได้โดยไม่ต้องใช้ JavaScript: เบราว์เซอร์จัดการการเรียกใช้งานจาก HTML โดยตรง และความสัมพันธ์ระหว่าง trigger กับทูลทิปถูกระบุอย่างชัดเจน
  • ปุ่ม Esc ทำงานอัตโนมัติ: ไม่ต้องเพิ่ม key listener เพราะเบราว์เซอร์เข้าใจเองว่าสามารถยกเลิก popover ได้
  • ซิงก์สถานะ ARIA อัตโนมัติ: แอตทริบิวต์ aria-expanded จะอัปเดตอัตโนมัติเมื่อ popover เปิด/ปิด ไม่ต้องจัดการเอง และไม่มีความเสี่ยงจากสถานะค้างเก่า
  • สิ่งที่สำคัญยิ่งกว่าการลดโค้ดคือ การย้ายความรับผิดชอบ: เดิม JavaScript เป็นผู้ “ทำให้ทูลทิปมีอยู่” แต่ตอนนี้เบราว์เซอร์เข้าใจบทบาทของมันจาก markup และให้มันเข้าไปมีส่วนใน โมเดลโฟกัส, accessibility tree และกฎการปิดแบบเนทีฟ

ทำความเข้าใจ Invoker Commands

  • popovertarget="id" ใช้เชื่อมปุ่มเข้ากับองค์ประกอบ popover
  • popovertargetaction ใช้กำหนดพฤติกรรม
    • show: เปิดอย่างเดียว
    • hide: ปิดอย่างเดียว
    • toggle (ค่าเริ่มต้น): ถ้าเปิดอยู่ให้ปิด ถ้าปิดอยู่ให้เปิด
  • ทูลทิปเดียวกันสามารถมี หลาย trigger ได้ และปฏิสัมพันธ์พื้นฐานก็ไม่ต้องใช้ JavaScript

ของแถมด้านการเข้าถึงที่ได้ฟรี

  • คีย์บอร์ดที่ “ใช้งานได้เลย”

    • ก่อนหน้านี้ต้องมีโครงสร้างหลายชั้น: ให้โฟกัสเป็นตัว trigger, ให้ blur เป็นตัวซ่อน, ผูก Esc เอง และยังต้องจัดจังหวะเวลาให้ถูกด้วย
    • เมื่อกำหนดแอตทริบิวต์ popover (auto หรือ manual) เบราว์เซอร์จะจัดการพื้นฐานให้: Tab/Shift+Tab ทำงานปกติ และ Esc ปิดได้แน่นอนทุกครั้ง
    • ส่งผลให้ ตัด global keydown handler, ตรรกะ cleanup เฉพาะ Esc และการตรวจสถานะระหว่างการนำทางด้วยคีย์บอร์ดออกจากโค้ดเบสได้
  • ความคาดเดาได้ของ screen reader

    • นี่คือส่วนที่ดีขึ้นมากที่สุด เพราะก่อนหน้านี้แม้จะทำ ARIA อย่างระมัดระวังแล้ว พฤติกรรมก็ยังเปลี่ยนได้ และการแก้เล็กน้อยก็มีความเสี่ยง
    • เมื่อใช้ popover="manual" role="tooltip" จะได้ พฤติกรรมที่เสถียรและคาดเดาได้มากขึ้น
    • หลังเปลี่ยนมาใช้แล้ว Lighthouse ก็ไม่แสดงคำเตือนเรื่องสถานะ ARIA ที่ผิดพลาดอีก — เพราะไม่มีสถานะ ARIA แบบคัสตอมให้ทำพลาดแล้ว
  • การจัดการโฟกัส

    • เดิมทีต้องมีกฎซับซ้อน เช่น ให้โฟกัส trigger แล้วแสดง, ถ้าโฟกัสย้ายเข้าไปในทูลทิปก็อย่าปิด, จัดการ blur และกู้คืนโฟกัสเอง
    • ใน Popover API โฟกัสจะย้ายเข้าไปยัง popover อย่างเป็นธรรมชาติ และเมื่อปิดก็จะ คืนโฟกัสกลับไปที่ trigger โดยอัตโนมัติ
    • ไม่ใช่เพิ่มโค้ดกู้คืนโฟกัส แต่เป็นการ ลบ โค้ดนั้นออก

ส่วนที่ Popover API ยังไปไม่ถึง

  • จังหวะเวลาของทูลทิป

    • popover แบบเนทีฟเปิดและปิดทันที ทำให้เมื่อเลื่อนเมาส์เร็วไปนิดเดียวหรือแค่เฉี่ยว trigger ทูลทิปอาจกะพริบและ ให้ความรู้สึกไม่เสถียร
    • จึงยังต้องมี การควบคุม delay ระหว่าง hover/focus กับการเปิด
    • พฤติกรรมเปิด/ปิดพื้นฐานให้เบราว์เซอร์และ HTML invoker commands จัดการไป ส่วน JavaScript ใช้เฉพาะเพื่อ ปรับปรุงพฤติกรรมแบบมีเจตนา เช่น ยกเลิกการซ่อนเมื่อ pointer กำลังย้ายเข้าสู่ทูลทิป
    • ทาง CSS ก็มีการสำรวจเรื่องนี้อยู่เช่นกัน โดย งานด้าน interest/invoker กำลังมุ่งไปสู่การเขียน delay ตอนเข้า/ออกด้วย CSS โดยตรง
  • Hover intent และ Invoker Commands

    • เบราว์เซอร์ไม่สามารถรู้ได้ว่าทำไมใครบางคนถึง hover อยู่บนองค์ประกอบ — ตั้งใจหรือแค่ pointer ผ่านมา ตัดสินไม่ได้
    • เมื่อ invoker commands จัดการการเปิด/ปิดแกนหลักแล้ว JavaScript ก็ไม่ต้องเป็นเจ้าของ interaction model อีกต่อไป แต่เพียง เพิ่มเรื่อง intent ทับลงไปข้างบน
    • ใช้ JavaScript เฉพาะกับพฤติกรรมที่เบราว์เซอร์อนุมานเองไม่ได้ เช่น delay สั้น ๆ ก่อนซ่อน หรือยกเลิกการปิดเมื่อ pointer กำลังเคลื่อนไปยังทูลทิป
  • Manual Popover และโฟกัส

    • ใน popover="manual" เบราว์เซอร์จะ ไม่กู้คืนโฟกัสให้อัตโนมัติ ต่างจาก auto popover
    • ถ้าทูลทิปเปิดด้วยโฟกัสและปิดด้วย blur ก็ต้องคืนโฟกัสกลับไปที่ trigger อย่างชัดเจนเอง
    • นี่คือ เส้นแบ่งที่ชัดเจน ระหว่างพฤติกรรมของแพลตฟอร์มกับความตั้งใจของผู้ใช้
  • ประเมินกันแบบตรงไปตรงมา

    • Popover API ไม่ได้แก้ปัญหาทูลทิปแบบมหัศจรรย์ แต่ช่วย หยุดการต้องสร้างโครงสร้างพื้นฐานที่เปราะบางขึ้นมาใหม่ซ้ำ ๆ
    • ยังต้องใช้ JavaScript และยังต้องคิดถึง edge case อยู่ แต่ตอนนี้สามารถโฟกัสที่ การแก้ปัญหาของผลิตภัณฑ์ แทนการสร้าง UI primitive เดิมซ้ำได้

กรณีที่ยังต้องใช้ไลบรารีทูลทิป

  • ดีไซน์ซิสเต็มขนาดใหญ่หรือมีความเป็นผู้ใหญ่สูง

    • ในดีไซน์ซิสเต็มขนาดใหญ่ที่หลายทีมใช้งานร่วมกัน ไลบรารีเป็นทางเลือกที่สมเหตุสมผลเพื่อให้ได้ พฤติกรรมแบบรวมศูนย์, แพตเทิร์นที่มีเอกสาร, และค่าเริ่มต้นที่สม่ำเสมอ
    • การเปลี่ยน interaction model ที่อยู่ข้างใต้ไม่ใช่แค่การตัดสินใจทางเทคนิค แต่ยังเป็น การตัดสินใจระดับองค์กร
    • ช่วยทำหน้าที่เป็น guardrail ให้กับสมาชิกทีมที่ยังไม่คุ้นกับรายละเอียดด้านการเข้าถึง
  • ความต้องการด้านการจัดตำแหน่งที่ซับซ้อน

    • หากต้องตรวจจับการชนกันระหว่าง nested scroll container, มีตรรกะการพลิกตำแหน่งแบบคัสตอม หรืออยากควบคุม offset/ขอบเขตอย่างละเอียด ไลบรารีอย่าง Floating UI ก็ยังได้เปรียบ
    • CSS anchor positioning เริ่มครอบคลุมปัญหาส่วนใหญ่ในด้านนี้แล้ว — สามารถวางตำแหน่งสัมพันธ์กับ trigger, รับรู้ viewport และพลิกตำแหน่งที่ขอบได้ด้วย CSS ล้วน
    • แม้ยังเป็นฟีเจอร์ใหม่และมี known issue อยู่ แต่ก็ถูกรวมใน Interop แล้ว จึงมีแนวโน้มจะได้การรองรับจากเบราว์เซอร์ที่ครบและสม่ำเสมอ
    • หากตอนนี้ยังต้องการพฤติกรรมข้ามเบราว์เซอร์ที่สม่ำเสมอ ไลบรารียังเป็นตัวเลือกที่ใช้งานได้จริง
  • ทีมที่ยังมีประสบการณ์ด้านการเข้าถึงไม่มาก

    • สำหรับทีมที่ความรู้ด้านการเข้าถึงยังไม่มาก ไลบรารีที่ดีทำหน้าที่เป็น ตาข่ายนิรภัย — ไม่ได้การันตีการเข้าถึงที่สมบูรณ์แบบ แต่ช่วยป้องกันความผิดพลาดที่พบบ่อย
    • แม้ Popover API จะให้ค่าเริ่มต้นที่ดีกว่า แต่ก็ยังต้องรู้ ว่าเมื่อไรควรเพิ่ม role, label, การจัดการโฟกัส และการทดสอบ
    • ถ้าไม่มีความเข้าใจ แม้แต่เครื่องมือแบบเนทีฟก็ยังถูกใช้งานผิดได้

บทสรุป

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

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น