• องค์ประกอบ HTML <dialog> ใช้สร้างกล่องโต้ตอบแบบ modal และ non-modal แบบเนทีฟของเบราว์เซอร์ โดย modal จะทำให้พื้นที่ส่วนที่เหลือของหน้าอยู่ในสถานะ inert เพื่อบล็อกการโต้ตอบ
  • วิธีเปิดและปิดพื้นฐานคือ showModal(), show(), close() และยังสามารถควบคุมแบบ declarative ได้ด้วย <form method="dialog">, Invoker Commands API และ Popover API
  • แอตทริบิวต์ closedby แบ่งช่องทางที่ผู้ใช้สามารถปิดกล่องโต้ตอบได้เป็น any, closerequest, none และพฤติกรรมเริ่มต้นจะแตกต่างกันตามวิธีที่เปิด
  • ด้าน accessibility สิ่งสำคัญคือ โฟกัสเริ่มต้น และปุ่มปิดที่ระบุชัดเจน โดยกล่องโต้ตอบที่เปิดด้วย showModal() จะให้โฟกัสกับองค์ประกอบที่โฟกัสได้ตัวแรก และปิดด้วยปุ่ม Esc ได้โดยค่าเริ่มต้น
  • การจัดสไตล์ใช้ :modal, :open, ::backdrop และสำหรับ animation ต้องจัดการ discrete transition เช่น display, overlay, @starting-style, transition-behavior: allow-discrete

บทบาทของ <dialog> และพฤติกรรมแบบ modal

  • องค์ประกอบ HTML <dialog> คือองค์ประกอบสำหรับสร้างกล่องโต้ตอบแบบ modal และ non-modal
  • กล่องโต้ตอบแบบ modal จะบล็อกการโต้ตอบกับองค์ประกอบ UI อื่น และทำให้ส่วนที่เหลือของหน้าอยู่ในสถานะ inert
  • กล่องโต้ตอบแบบ non-modal ยังสามารถโต้ตอบกับส่วนที่เหลือของหน้าได้ต่อไปแม้จะเปิดอยู่

สถานะเปิดและนโยบายการปิด

  • <dialog> รองรับแอตทริบิวต์สากล แต่ ไม่ควรใช้แอตทริบิวต์ tabindex
    • ตัว <dialog> เองไม่ใช่องค์ประกอบแบบโต้ตอบและไม่รับโฟกัส
    • เนื้อหาภายในและปุ่มปิดสามารถรับโฟกัสและโต้ตอบได้
  • แอตทริบิวต์ open ระบุว่ากล่องโต้ตอบอยู่ในสถานะ active และสามารถโต้ตอบได้
    • หากไม่มีแอตทริบิวต์ open ผู้ใช้จะมองไม่เห็น
    • เมื่อต้องการแสดงกล่องโต้ตอบ แนะนำให้ใช้ .show() หรือ .showModal() มากกว่าแอตทริบิวต์ open
    • <dialog> ที่เปิดด้วยแอตทริบิวต์ open จะเป็นแบบ non-modal
    • สามารถเปลี่ยนสถานะเปิด·ปิดของกล่องโต้ตอบแบบ non-modal ด้วยการ toggle แอตทริบิวต์ open ได้ แต่ไม่แนะนำ
  • แอตทริบิวต์ closedby กำหนดว่าผู้ใช้สามารถปิดกล่องโต้ตอบได้ด้วยวิธีใด
    • any: ปิดได้ทั้งสามวิธี
      • light dismiss เช่น คลิกหรือแตะด้านนอกกล่องโต้ตอบ
      • การทำงานเฉพาะแพลตฟอร์ม เช่น ปุ่ม Esc, ปุ่มย้อนกลับบนมือถือ หรือ gesture สำหรับ dismiss
      • วิธีที่นักพัฒนากำหนด เช่น ปุ่มที่เรียก HTMLDialogElement.close() หรือการ submit <form method="dialog">
    • closerequest: ปิดได้ด้วยการทำงานเฉพาะแพลตฟอร์มและวิธีที่นักพัฒนากำหนด
    • none: ปิดได้เฉพาะวิธีที่นักพัฒนากำหนดเท่านั้น
    • หากไม่มีค่า closedby ที่ถูกต้อง เมื่อเปิดด้วย showModal() จะทำงานเหมือน closerequest ส่วนกรณีอื่นจะทำงานเหมือน none

การควบคุมด้วย JavaScript และแบบ declarative

  • สามารถควบคุมการแสดงและการปิด <dialog> ได้โดยตรงด้วย JavaScript
    • showModal(): แสดงกล่องโต้ตอบแบบ modal
    • show(): แสดงกล่องโต้ตอบแบบ non-modal
    • close(): ปิดกล่องโต้ตอบ
    • ยังสามารถปิดได้ด้วยการ submit <form> ภายใน <dialog> โดยตั้ง method="dialog"
    • กล่องโต้ตอบแบบ modal ยังปิดด้วยปุ่ม Esc ได้ด้วย
  • Invoker Commands API ทำให้เปิดและปิดกล่องโต้ตอบแบบ modal ได้ด้วยแอตทริบิวต์ของปุ่มเท่านั้น
    • กำหนดแอตทริบิวต์ commandfor และ command ให้กับ <button>
    • คำสั่งที่ใช้กับกล่องโต้ตอบได้คือ "show-modal", "close", "request-close"
Open dialog

  This dialog was opened using an invoker command.

  Close

  • Popover API ทำให้เปิด ปิด และ toggle กล่องโต้ตอบแบบ non-modal ได้ในเชิง declarative
    • เพิ่มแอตทริบิวต์ popover ให้ <dialog> เพื่อทำให้เป็น popover
    • กำหนด popovertarget, popovertargetaction ให้ปุ่มหรือองค์ประกอบ input
    • กล่องโต้ตอบแบบ popover เป็น non-modal จึงปิดได้ด้วยการคลิกด้านนอก
    • หากไม่ระบุค่า popover จะใช้ค่าเริ่มต้น "auto" และเปิดใช้ light dismiss
    • popover="manual" จะปิดใช้ light dismiss และต้องมีวิธีอื่น เช่น ปุ่มปิด
    • หากละ popovertargetaction จะใช้ค่าเริ่มต้น toggle

การ submit ฟอร์มและการจัดการปิด

  • <dialog> ทุกตัวจำเป็นต้องมีกลไกการปิด และต้องใช้งานได้แม้บนอุปกรณ์ที่ไม่มีคีย์บอร์ดจริง
  • มีหลายวิธีในการปิด
    • ตั้งค่า method="dialog" ใน <form> ภายใน <dialog> แล้ว submit
    • คลิกด้านนอกกล่องโต้ตอบเมื่อเปิดใช้ light dismiss
    • กดปุ่ม Esc ในกล่องโต้ตอบที่อนุญาต
    • เรียก HTMLDialogElement.close()
  • method="dialog" ของ <form> หรือ formmethod="dialog" ของปุ่ม submit จะปิดกล่องโต้ตอบ
    • สถานะของ form controls จะถูกบันทึกไว้ แต่จะไม่ถูก submit
    • returnValue จะถูกตั้งเป็นค่าของปุ่มที่ถูก activate
  • ในฟอร์มที่มีค่าบังคับกรอก user agent จะไม่ให้ปิดกล่องโต้ตอบด้วยการ submit ปกติจนกว่าจะมีการกรอกค่า
    • ใช้ formnovalidate กับปุ่มปิดเพื่อข้ามการตรวจสอบฟอร์มได้
    • หรือเรียก dialog.close() ใน JavaScript ก็ปิดได้

โฟกัสและ accessibility

  • เมื่อเปิด <dialog> ด้วย showModal() โดยค่าเริ่มต้นโฟกัสจะถูกตั้งไปที่องค์ประกอบที่โฟกัสได้ตัวแรกที่ซ้อนอยู่ภายใน
  • หากต้องการกำหนดตำแหน่งโฟกัสเริ่มต้นที่เหมาะสมที่สุดสำหรับกล่องโต้ตอบหนึ่ง ๆ สามารถใช้แอตทริบิวต์ autofocus ได้
    • หากไม่มีองค์ประกอบที่ต้องโต้ตอบทันที แนะนำให้ใส่ autofocus ที่ปุ่มปิด
    • หากตำแหน่งโฟกัสเริ่มต้นไม่แน่นอน เช่น กล่องโต้ตอบที่ render แบบ dynamic ตัว <dialog> เองอาจเป็นตำแหน่งโฟกัสเริ่มต้นที่เหมาะสมได้
  • วิธีที่แข็งแรงที่สุดคือใส่ ปุ่มที่ชัดเจน เช่น ปุ่มยืนยัน ยกเลิก หรือปิด เพื่อให้ผู้ใช้ทุกคนปิดได้
  • กล่องโต้ตอบที่เรียกด้วย showModal() จะปิดด้วยปุ่ม Esc โดยค่าเริ่มต้น
    • กล่องโต้ตอบแบบ non-modal โดยค่าเริ่มต้นจะไม่ปิดด้วยปุ่ม Esc
    • ผู้ใช้คีย์บอร์ดคาดหวังว่ากล่องโต้ตอบแบบ modal จะปิดด้วยปุ่ม Esc ได้
    • หากมีกล่องโต้ตอบแบบ modal เปิดอยู่หลายตัว ปุ่ม Esc ควรปิดเฉพาะกล่องโต้ตอบที่แสดงล่าสุด และเมื่อใช้ <dialog> เบราว์เซอร์จะจัดพฤติกรรมนี้ให้
  • <dialog> แบบเนทีฟให้ฟีเจอร์ด้าน usability และ accessibility ที่ต้องทำซ้ำเองเมื่อสร้าง custom dialog ด้วยองค์ประกอบอื่น
  • เบราว์เซอร์ expose <dialog> คล้ายกับ custom dialog ที่ใช้ ARIA role="dialog"
    • <dialog> ที่เรียกด้วย showModal() จะมี aria-modal="true" โดยนัย
    • <dialog> ที่แสดงด้วย show(), แอตทริบิวต์ open หรือการเปลี่ยน display พื้นฐาน จะถูก expose เป็น aria-modal="false"
    • เมื่อ implement กล่องโต้ตอบแบบ modal ทุกอย่างนอกเหนือจาก <dialog> และเนื้อหาภายในควรถูก render เป็น inert และเมื่อใช้ showModal() เบราว์เซอร์จะจัดพฤติกรรมนี้ให้

การจัดสไตล์ CSS และ backdrop

  • <dialog> สามารถเลือกด้วยชื่อองค์ประกอบได้เหมือนองค์ประกอบทั่วไป
  • สำหรับการจัดสไตล์ตามสถานะ สามารถใช้ pseudo-class :modal, :open ได้
  • พื้นหลังของกล่องโต้ตอบแบบ modal สามารถจัดสไตล์ด้วย pseudo-element ::backdrop ได้
    • ใช้กับ backdrop ที่ปรากฏอยู่ด้านหลัง <dialog> เมื่อแสดงกล่องโต้ตอบด้วย showModal()
    • สามารถทำให้เนื้อหาด้านหลังที่อยู่ในสถานะ inert เบลอ มืดลง หรือถูกบังได้

รูปแบบการใช้งานจากตัวอย่าง

  • ตัวอย่าง Invoker Commands API เปิดกล่องโต้ตอบด้วยปุ่ม command="show-modal" และปิดด้วยปุ่ม command="close"
    • เปิดได้ด้วยปุ่ม “Open dialog”
    • ปิดได้ด้วยปุ่ม “Close” หรือปุ่ม Esc
  • ตัวอย่าง Popover API เปิดและปิดกล่องโต้ตอบแบบ non-modal ด้วย popover, popovertarget, popovertargetaction
    • ปิดได้ด้วยปุ่ม “Close”, ปุ่ม Esc หรือการเลือกด้านนอกกล่องโต้ตอบ
    • หากใช้ popover="manual" จะปิดใช้ light dismiss
  • ตัวอย่างแอตทริบิวต์ open สร้างกล่องโต้ตอบแบบ non-modal แบบ HTML-only ที่เปิดอยู่แล้วเมื่อโหลดหน้า
    • ปิดได้ด้วยปุ่ม “OK” ของ <form method="dialog">
    • หลังจากปิดแล้วไม่มีวิธีเปิดใหม่ให้
    • สำหรับการแสดงกล่องโต้ตอบแบบ non-modal นิยมใช้ HTMLDialogElement.show() มากกว่า
  • ตัวอย่างกล่องโต้ตอบแบบ modal เปิดด้วย .showModal() และปิดด้วย close()
    • จัดสไตล์พื้นหลัง gradient ด้วย ::backdrop
    • เมื่อกล่องโต้ตอบเปิดอยู่ ภายนอกกล่องโต้ตอบจะอยู่ในสถานะ inert และไม่สามารถโต้ตอบกับเอกสารได้
  • ตัวอย่าง returnValue จัดการค่าที่ส่งคืนของกล่องโต้ตอบด้วยฟอร์มและค่าของปุ่ม
    • ค่า returnValue เริ่มต้นเป็นสตริงว่าง หรือเป็นค่าของปุ่มที่ submit ฟอร์มภายในกล่องโต้ตอบ
    • ปุ่ม “Confirm” ส่งค่าที่เลือกให้ close() เพื่อใช้เป็นค่าที่ส่งคืน
    • หากปิดด้วยปุ่ม Esc ค่า returnValue จะไม่ถูกอัปเดต และ event close ก็ไม่เกิดขึ้น ทำให้ข้อความ <output> ไม่ถูกอัปเดต

Animation ของ <dialog>

  • <dialog> ที่ซ่อนอยู่จะเป็น display: none และ <dialog> ที่แสดงอยู่จะเป็น display: block
  • เมื่อสถานะการแสดงเปลี่ยน จะถูกเพิ่มเข้าไปหรือลบออกจาก top layer และ accessibility tree
  • หากต้องการทำ animation ให้ <dialog> พร็อพเพอร์ตี display ต้องสามารถ animate ได้
    • เบราว์เซอร์ที่รองรับจะจัดการ display ด้วยวิธี discrete animation
    • เมื่อเปลี่ยนจาก none เป็น block จะสลับเป็น block ที่จุดเวลา 0% จึงมองเห็นตลอดทั้ง animation
    • เมื่อเปลี่ยนจาก block เป็น none จะสลับเป็น none ที่จุดเวลา 100% จึงมองเห็นตลอดทั้ง animation
  • ทำ animation ด้วย CSS transition

    • หากต้องการทำ animation ให้ <dialog> ด้วย CSS transition ต้องมีฟีเจอร์ต่อไปนี้
    • @starting-style: ให้ค่าเริ่มต้นของ transition ทุกครั้งที่กล่องโต้ตอบเปิด
    • transition ของ display: คงค่า display ที่ทำให้มองเห็นกล่องโต้ตอบไว้ระหว่าง transition
    • transition ของ overlay: หน่วงการนำออกจาก top layer จนกว่า transition จะเสร็จ
    • transition-behavior: allow-discrete: เปิดใช้ discrete transition ของ display, overlay ซึ่งโดยปกติไม่ถูก animate
    • ในเบราว์เซอร์ที่ไม่รองรับ pseudo-class :open สามารถจัดสไตล์สถานะเปิดด้วย attribute selector dialog[open] ได้
    • ทุกครั้งที่ <dialog> ถูกแสดง จะเปลี่ยนจาก display: none เป็น display: block ดังนั้นทุก entry transition จะเปลี่ยนจาก @starting-style ไปเป็นสไตล์ dialog:open
  • keyframe animation

    • CSS keyframe animation มีข้อจำกัดต่างจาก transition
    • ไม่มี @starting-style
    • รวมค่า display ไว้ใน keyframe
    • ไม่จำเป็นต้องเปิดใช้ allow-discrete อย่างชัดเจน
    • ไม่จำเป็นต้องตั้งค่า overlay ใน keyframe ด้วย
    • backdrop fade-out ไม่สามารถ animate ได้ เพราะเมื่อกล่องโต้ตอบปิด backdrop จะถูกนำออกจาก DOM ทันที

สรุปทางเทคนิค

  • หมวดหมู่เนื้อหา: flow content, sectioning root
  • เนื้อหาที่อนุญาต: flow content
  • ต้องมีทั้งแท็กเปิดและแท็กปิด และไม่มีการละแท็ก
  • parent ที่อนุญาต: องค์ประกอบทั้งหมดที่รับ flow content
  • บทบาท ARIA โดยนัย: dialog
  • บทบาท ARIA ที่อนุญาต: alertdialog
  • DOM interface: HTMLDialogElement
  • สเปก: HTML # the-dialog-element

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

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