ภาพรวมพื้นฐานของวิธีสร้างโมดัลขนาดเล็กที่ปรับสีได้ ตอบสนองได้ดี และเข้าถึงง่ายด้วยองค์ประกอบ <dialog>
ในโพสต์นี้ ผมอยากแชร์ความคิดเห็นเกี่ยวกับวิธีสร้างโมดัลแบบปรับสี ปรับเปลี่ยนตามอุปกรณ์ และเข้าถึงง่ายด้วยองค์ประกอบ <dialog>
ลองใช้เดโมและดูแหล่งที่มา
หากชอบวิดีโอ นี่คือโพสต์นี้เวอร์ชัน YouTube
ภาพรวม
องค์ประกอบ <dialog>
เหมาะสำหรับการดำเนินการหรือข้อมูลตามบริบทในหน้าเว็บ ลองพิจารณาช่วงเวลาที่ประสบการณ์ของผู้ใช้จะได้รับประโยชน์จากการทำงานบนหน้าเว็บเดียวกันแทนที่จะใช้การกระทำหลายหน้า ซึ่งอาจเป็นเพราะแบบฟอร์มมีขนาดเล็ก หรือมีเพียงการดำเนินการเดียวที่จำเป็นจากผู้ใช้คือยืนยันหรือยกเลิก
เมื่อเร็วๆ นี้ องค์ประกอบ <dialog>
ได้มีความเสถียรในเบราว์เซอร์ต่างๆ ดังต่อไปนี้
จริงๆ แล้วองค์ประกอบบางอย่างหายไป ดังนั้นในชาเลนจ์ GUI นี้ ฉันได้เพิ่มรายการสำหรับประสบการณ์ของนักพัฒนาแอป ที่ฉันคาดหวังไว้ ได้แก่ เหตุการณ์เพิ่มเติม การปิดแสง ภาพเคลื่อนไหวที่กำหนดเอง รวมถึงประเภทมินิและเมกะ
Markup
องค์ประกอบ <dialog>
ที่จำเป็นมีไม่มาก องค์ประกอบจะซ่อนอยู่
โดยอัตโนมัติและมีรูปแบบในตัวเพื่อซ้อนทับเนื้อหา
<dialog>
…
</dialog>
เราสามารถปรับปรุงเกณฑ์พื้นฐานนี้ได้
แต่เดิมองค์ประกอบกล่องโต้ตอบจะใช้ร่วมกับโมดัลมากและมักจะใช้แทนชื่อกันได้ ผมใช้องค์ประกอบกล่องโต้ตอบ
ทั้งป๊อปอัปกล่องโต้ตอบขนาดเล็ก (ขนาดเล็ก) และกล่องโต้ตอบแบบเต็มหน้า (ขนาดใหญ่) ผมตั้งชื่อว่า "เมกะ" และ "มินิ" โดยกล่องโต้ตอบทั้ง 2 แบบจะปรับให้เข้ากับการใช้งานที่ต่างกันเล็กน้อย
ฉันได้เพิ่มแอตทริบิวต์ modal-mode
เพื่อให้คุณระบุประเภทได้ ดังนี้
<dialog id="MegaDialog" modal-mode="mega"></dialog>
<dialog id="MiniDialog" modal-mode="mini"></dialog>
อาจไม่ทุกครั้ง แต่โดยทั่วไปจะใช้องค์ประกอบกล่องโต้ตอบเพื่อรวบรวมข้อมูลการโต้ตอบบางอย่าง ฟอร์มในองค์ประกอบกล่องโต้ตอบสร้างขึ้นเพื่อใช้ร่วมกัน
ควรให้องค์ประกอบแบบฟอร์มรวมเนื้อหากล่องโต้ตอบของคุณ เพื่อให้ JavaScript สามารถเข้าถึงข้อมูลที่ผู้ใช้ป้อนได้ นอกจากนี้ ปุ่มภายในแบบฟอร์มที่ใช้ method="dialog"
ยังปิดกล่องโต้ตอบโดยไม่ใช้ JavaScript และส่งข้อมูลได้ด้วย
<dialog id="MegaDialog" modal-mode="mega">
<form method="dialog">
…
<button value="cancel">Cancel</button>
<button value="confirm">Confirm</button>
</form>
</dialog>
กล่องโต้ตอบขนาดใหญ่
กล่องโต้ตอบขนาดใหญ่มีองค์ประกอบ 3 อย่างภายในแบบฟอร์มดังนี้
<header>
,
<article>
และ
<footer>
พารามิเตอร์เหล่านี้ทำหน้าที่เป็นคอนเทนเนอร์ความหมาย รวมถึงเป้าหมายรูปแบบสำหรับการนำเสนอกล่องโต้ตอบ ส่วนหัวคือชื่อของโมดัลและมีปุ่มปิด บทความนี้มีไว้สำหรับการป้อนข้อมูลแบบฟอร์มและข้อมูล ส่วนท้ายจะมีปุ่มดำเนินการ <menu>
<dialog id="MegaDialog" modal-mode="mega">
<form method="dialog">
<header>
<h3>Dialog title</h3>
<button onclick="this.closest('dialog').close('close')"></button>
</header>
<article>...</article>
<footer>
<menu>
<button autofocus type="reset" onclick="this.closest('dialog').close('cancel')">Cancel</button>
<button type="submit" value="confirm">Confirm</button>
</menu>
</footer>
</form>
</dialog>
ปุ่มเมนูแรกมี autofocus
และเครื่องจัดการเหตุการณ์แบบอินไลน์ onclick
แอตทริบิวต์ autofocus
จะได้รับโฟกัสเมื่อกล่องโต้ตอบเปิดขึ้น และฉันคิดว่าแนวทางปฏิบัติแนะนำคือการใส่ปุ่มนี้บนปุ่มยกเลิก ไม่ใช่ปุ่มยืนยัน การทำเช่นนี้ช่วยให้มั่นใจได้ว่าการยืนยันเป็นไป
โดยไม่เจตนา
กล่องโต้ตอบขนาดเล็ก
กล่องโต้ตอบขนาดเล็กคล้ายกับกล่องโต้ตอบขนาดใหญ่มาก เพียงแต่ว่ามีองค์ประกอบ <header>
ขาดหายไป ทำให้เนื้อหามีขนาดเล็กลงและแทรกในบรรทัดมากขึ้น
<dialog id="MiniDialog" modal-mode="mini">
<form method="dialog">
<article>
<p>Are you sure you want to remove this user?</p>
</article>
<footer>
<menu>
<button autofocus type="reset" onclick="this.closest('dialog').close('cancel')">Cancel</button>
<button type="submit" value="confirm">Confirm</button>
</menu>
</footer>
</form>
</dialog>
องค์ประกอบกล่องโต้ตอบมีรากฐานที่มั่นคงสำหรับองค์ประกอบวิวพอร์ตที่สมบูรณ์ซึ่งรวบรวมข้อมูลและการโต้ตอบของผู้ใช้ได้ ข้อมูลสำคัญเหล่านี้สามารถทำให้เกิดการโต้ตอบที่น่าสนใจและมีประสิทธิภาพ ในเว็บไซต์หรือแอปของคุณ
การช่วยเหลือพิเศษ
องค์ประกอบของกล่องโต้ตอบมีการช่วยเหลือพิเศษในตัวที่ดีมาก แทนที่จะเพิ่มคุณลักษณะเหล่านี้ เหมือนที่ผมทำเป็นประจำ คุณลักษณะหลายอย่างมีอยู่แล้ว
กำลังคืนค่าโฟกัส
อย่างที่เราได้ทำในการสร้างคอมโพเนนต์แผงด้านข้าง สิ่งสำคัญคือการเปิดและปิดบางสิ่งอย่างเหมาะสมจะมุ่งเน้นที่ปุ่มเปิดและปิดที่เกี่ยวข้อง เมื่อการนำทางด้านข้างเปิดขึ้น โฟกัสจะอยู่ที่ปุ่มปิด เมื่อกดปุ่มปิด ระบบจะคืนค่าโฟกัสไปยังปุ่มที่เปิดขึ้นมา
องค์ประกอบนี้จะเป็นลักษณะการทำงานเริ่มต้นในตัวเมื่อใช้องค์ประกอบกล่องโต้ตอบ
ถ้าต้องการให้กล่องโต้ตอบเคลื่อนไหวไปมา ฟังก์ชันนี้จะสูญหายไป ในส่วน JavaScript ผมจะคืนค่าฟังก์ชันนั้น
มุ่งเน้นการดักจับ
องค์ประกอบกล่องโต้ตอบจะจัดการ inert
ให้คุณในเอกสาร ก่อนวันที่ inert
มีการใช้ JavaScript ในการดูโฟกัสที่ออกจากองค์ประกอบ ซึ่งจุดเริ่มจะสกัดกั้นและนำกลับมา
หลังจากวันที่ inert
ส่วนต่างๆ ของเอกสารอาจถูก "ตรึงไว้" ได้ตราบเท่าที่ไม่เป็นเป้าสายตาอีกต่อไปหรือเป็นแบบอินเทอร์แอคทีฟด้วยเมาส์ แทนที่จะดักจับโฟกัส
ระบบจะนําโฟกัสไปยังส่วนแบบอินเทอร์แอกทีฟเพียงอย่างเดียวของเอกสาร
เปิดและโฟกัสองค์ประกอบอัตโนมัติ
โดยค่าเริ่มต้น องค์ประกอบกล่องโต้ตอบจะกำหนดโฟกัสให้กับองค์ประกอบที่โฟกัสได้รายการแรกในมาร์กอัปกล่องโต้ตอบ หากนี่ไม่ใช่องค์ประกอบที่ดีที่สุดสำหรับผู้ใช้หลัก ให้ใช้แอตทริบิวต์ autofocus
ตามที่อธิบายไว้ก่อนหน้านี้ ฉันคิดว่า
แนวทางปฏิบัติแนะนำคือการใส่สิ่งนี้ไว้ที่ปุ่มยกเลิก ไม่ใช่ปุ่มยืนยัน การทำเช่นนี้จะเป็นการช่วยให้มั่นใจว่าการยืนยันนั้นเกิดขึ้นโดยเจตนา และไม่ใช่ความบังเอิญ
ปิดด้วยแป้น Escape
คุณควรปิดองค์ประกอบที่อาจรบกวนนี้ได้โดยง่าย แต่องค์ประกอบกล่องโต้ตอบจะจัดการแป้น Escape ให้คุณ ทำให้ไม่ต้องเหนื่อยกับการจัดการเป็นกลุ่ม
รูปแบบ
มีเส้นทางง่ายๆ ในการจัดรูปแบบองค์ประกอบกล่องโต้ตอบและเส้นทางที่แข็ง วิธีง่ายๆ นั้นทำได้เพราะไม่เปลี่ยนพร็อพเพอร์ตี้การแสดงผลของกล่องโต้ตอบและทำงานกับข้อจำกัดต่างๆ ไปตามเส้นทางยากๆ เพื่อมอบภาพเคลื่อนไหวที่กำหนดเอง
สำหรับการเปิดและปิดกล่องโต้ตอบ ควบคุมพร็อพเพอร์ตี้ display
และอีกมากมาย
การจัดรูปแบบพร้อมของตกแต่งแบบเปิด
ผมได้นำ Open Props ในไลบรารีตัวแปร CSS มาใช้งานในไลบรารีตัวแปร CSS เพื่อเร่งสีที่ปรับอัตโนมัติและความสอดคล้องในการออกแบบโดยรวม นอกเหนือจากตัวแปรที่มีให้ฟรีแล้ว ฉันยังนำเข้าไฟล์ทำให้เป็นมาตรฐานและปุ่มบางปุ่ม ซึ่งทั้ง 2 อย่างนี้ Open Props เป็นการนำเข้าที่ไม่บังคับ ไฟล์ที่นำเข้านี้ช่วยให้ผมโฟกัสกับการปรับแต่งกล่องโต้ตอบและการสาธิต โดยไม่จำเป็นต้องใช้สไตล์มากมายเพื่อรองรับและทำให้ดูดี
การจัดรูปแบบองค์ประกอบ <dialog>
การเป็นเจ้าของพร็อพเพอร์ตี้จอแสดงผล
ลักษณะการแสดงหรือซ่อนองค์ประกอบกล่องโต้ตอบเริ่มต้นจะสลับพร็อพเพอร์ตี้การแสดงผลจาก block
เป็น none
ซึ่งหมายความว่าจะไม่สามารถทำให้ภาพเคลื่อนไหวเข้าและออก
ในภาพได้ ผมอยากจะให้ภาพเคลื่อนไหวเป็นแบบทั้งเข้าและออก และขั้นตอนแรกคือ
การตั้งค่าพร็อพเพอร์ตี้
display ของผมเอง ดังนี้
dialog {
display: grid;
}
เมื่อเปลี่ยนแปลงและเป็นเจ้าของค่าพร็อพเพอร์ตี้ Display ดังที่แสดงในข้อมูลโค้ด CSS ด้านบน สไตล์จำนวนมากต้องได้รับการจัดการเพื่ออำนวยความสะดวกให้ผู้ใช้ได้รับประสบการณ์ใช้งานที่เหมาะสม อย่างแรก สถานะเริ่มต้นของกล่องโต้ตอบจะปิดอยู่ คุณสามารถแสดงถึงสถานะนี้ด้วยสายตา และป้องกันไม่ให้กล่องโต้ตอบรับการโต้ตอบกับรูปแบบต่อไปนี้
dialog:not([open]) {
pointer-events: none;
opacity: 0;
}
ตอนนี้กล่องโต้ตอบจะซ่อนอยู่และจะไม่สามารถโต้ตอบได้อีกเมื่อไม่ได้เปิด หลังจากนั้น
ฉันจะเพิ่ม JavaScript บางส่วนเพื่อจัดการแอตทริบิวต์ inert
ในกล่องโต้ตอบ เพื่อ
ตรวจสอบว่าผู้ใช้แป้นพิมพ์และโปรแกรมอ่านหน้าจอไม่สามารถเข้าถึงกล่องโต้ตอบที่ซ่อนอยู่ได้
เพิ่มธีมสีที่ปรับได้ให้กับกล่องโต้ตอบ
แม้ว่า color-scheme
จะเลือกให้เอกสารของคุณใช้ธีมสีแบบปรับอัตโนมัติที่เบราว์เซอร์มีให้สำหรับค่ากำหนดของระบบสีอ่อนและมืด แต่เราต้องการปรับแต่งองค์ประกอบกล่องโต้ตอบมากกว่านั้น Open Props มีสีพื้นผิว 2-3 แบบซึ่งจะปรับตามค่ากำหนดของระบบแสงและมืดโดยอัตโนมัติ เช่นเดียวกับการใช้ color-scheme
วิธีนี้เหมาะอย่างยิ่งสำหรับการสร้างเลเยอร์ในการออกแบบ และฉันชอบใช้สีเพื่อช่วยสนับสนุนรูปลักษณ์ของพื้นผิวเลเยอร์นี้ สีพื้นหลังคือ var(--surface-1)
หากต้องการวางทับบนเลเยอร์นั้น ให้ใช้ var(--surface-2)
ดังนี้
dialog {
…
background: var(--surface-2);
color: var(--text-1);
}
@media (prefers-color-scheme: dark) {
dialog {
border-block-start: var(--border-size-1) solid var(--surface-3);
}
}
ระบบจะเพิ่มสีที่ปรับเปลี่ยนได้อื่นๆ ในภายหลังสำหรับองค์ประกอบย่อย เช่น ส่วนหัวและส่วนท้าย ฉันคิดว่าส่วนขยายเหล่านี้พิเศษกว่าสำหรับองค์ประกอบของกล่องโต้ตอบ แต่สำคัญมากต่อการสร้าง การออกแบบกล่องโต้ตอบที่น่าสนใจและออกแบบมาเป็นอย่างดี
การปรับขนาดกล่องโต้ตอบที่ปรับเปลี่ยนตามอุปกรณ์
กล่องโต้ตอบจะมีค่าเริ่มต้นเป็นการมอบสิทธิ์ขนาดให้กับเนื้อหา ซึ่งโดยทั่วไปจะดีมาก เป้าหมายของฉันคือการจำกัด max-inline-size
ให้เป็นขนาดที่อ่านได้ (--size-content-3
= 60ch
) หรือ 90% ของความกว้างของวิวพอร์ต การทำเช่นนี้ช่วยให้มั่นใจได้ว่ากล่องโต้ตอบจะไม่เลื่อนไปขอบในอุปกรณ์เคลื่อนที่ และจะไม่กว้างเกินไปบนหน้าจอเดสก์ท็อปซึ่งอ่านยาก จากนั้นก็เพิ่ม max-block-size
กล่องโต้ตอบเพื่อไม่ให้เกินความสูงของหน้าเว็บ และยังหมายความว่าเราจะต้องระบุตำแหน่งของพื้นที่ที่เลื่อนได้ของกล่องโต้ตอบด้วย ในกรณีที่เป็นองค์ประกอบกล่องโต้ตอบสูง
dialog {
…
max-inline-size: min(90vw, var(--size-content-3));
max-block-size: min(80vh, 100%);
max-block-size: min(80dvb, 100%);
overflow: hidden;
}
สังเกตไหมว่าฉันมี max-block-size
2 ครั้งใช่ไหม รายการแรกใช้ 80vh
ซึ่งเป็นหน่วยวิวพอร์ตจริง สิ่งที่ฉันต้องการคือดูแลให้กล่องโต้ตอบอยู่ในลำดับที่สัมพันธ์กันสำหรับผู้ใช้ในประเทศต่างๆ ดังนั้นฉันจึงใช้หน่วย dvb
ที่สมเหตุสมผล ใหม่ และรองรับเพียงบางส่วนในการประกาศที่ 2 เมื่อมีความเสถียรมากขึ้น
การวางตำแหน่งกล่องโต้ตอบขนาดใหญ่
เพื่อช่วยในการจัดตำแหน่งองค์ประกอบกล่องโต้ตอบ คุณควรแยกองค์ประกอบออกเป็น 2 ส่วน ได้แก่ ฉากหลังแบบเต็มหน้าจอและคอนเทนเนอร์ของกล่องโต้ตอบ ฉากหลังต้องปิดทับทุกอย่าง โดยให้มีเอฟเฟกต์เฉดสีที่ช่วยสนับสนุนให้กล่องโต้ตอบนี้อยู่ด้านหน้า และเนื้อหาด้านหลังจะเข้าถึงไม่ได้ คอนเทนเนอร์ของกล่องโต้ตอบจะตั้งศูนย์กลางตัวเองเหนือฉากหลังนี้และใช้รูปร่างใดก็ได้ตามต้องการ
รูปแบบต่อไปนี้จะแก้ไของค์ประกอบของกล่องโต้ตอบกับหน้าต่าง โดยยืดไปทางแต่ละมุม และใช้ margin: auto
เพื่อจัดเนื้อหาให้อยู่กึ่งกลาง
dialog {
…
margin: auto;
padding: 0;
position: fixed;
inset: 0;
z-index: var(--layer-important);
}
รูปแบบกล่องโต้ตอบของอุปกรณ์เคลื่อนที่ขนาดใหญ่
ในวิวพอร์ตขนาดเล็ก ผมจัดรูปแบบโมดัลนี้แบบเต็มหน้าให้ต่างกันเล็กน้อย ผมตั้งค่าระยะขอบล่างเป็น 0
ซึ่งจะนำเนื้อหาของกล่องโต้ตอบมาไว้ที่ด้านล่างของวิวพอร์ต การปรับรูปแบบ 2-3 ครั้งทำให้ฉันสามารถเปลี่ยนกล่องโต้ตอบ
เป็นเวิร์กชีตให้อยู่ใกล้กับนิ้วโป้งของผู้ใช้มากขึ้น ดังนี้
@media (max-width: 768px) {
dialog[modal-mode="mega"] {
margin-block-end: 0;
border-end-end-radius: 0;
border-end-start-radius: 0;
}
}
การวางตำแหน่งกล่องโต้ตอบขนาดเล็ก
เมื่อใช้วิวพอร์ตที่ใหญ่ขึ้น เช่น ในคอมพิวเตอร์เดสก์ท็อป ผมเลือกที่จะจัดตำแหน่งกล่องโต้ตอบขนาดเล็กไว้เหนือองค์ประกอบที่เรียกใช้กล่องโต้ตอบ ต้องมี JavaScript จึงจะดำเนินการนี้ได้ คุณสามารถค้นหาเทคนิคที่ฉันใช้ได้ที่นี่ แต่ฉันคิดว่ามันอยู่นอกเหนือขอบเขตของบทความนี้ หากไม่มี JavaScript กล่องโต้ตอบขนาดเล็กจะปรากฏขึ้นตรงกลางหน้าจอ เหมือนกับกล่องโต้ตอบขนาดใหญ่
ทำให้โดดเด่น
สุดท้าย เพิ่มลูกเล่นลงในกล่องโต้ตอบเพื่อให้ดูเหมือนมีพื้นผิวนุ่มนวล เหนือพื้นผิว ความนุ่มนวลที่ได้มาโดยการปัดเศษมุมของกล่องโต้ตอบ เพิ่มความชัดลึกได้ด้วยอุปกรณ์ประกอบฉากจาก Open Props ที่ได้รับการออกแบบอย่างพิถีพิถันดังต่อไปนี้
dialog {
…
border-radius: var(--radius-3);
box-shadow: var(--shadow-6);
}
การปรับแต่งองค์ประกอบจำลองของฉากหลัง
ฉันเลือกที่จะปรับแต่งฉากหลังแบบเบามาก โดยใส่เอฟเฟกต์เบลอด้วย backdrop-filter
ลงในกล่องโต้ตอบขนาดใหญ่เท่านั้น
dialog[modal-mode="mega"]::backdrop {
backdrop-filter: blur(25px);
}
นอกจากนี้ ผมยังเลือกใส่การเปลี่ยนฉากใน backdrop-filter
โดยหวังว่าเบราว์เซอร์จะอนุญาตให้เปลี่ยนองค์ประกอบฉากหลังได้ในอนาคต ดังนี้
dialog::backdrop {
transition: backdrop-filter .5s ease;
}
เครื่องมือเพิ่มเติมด้านสไตล์
ฉันเรียกส่วนนี้ว่า "ส่วนเพิ่มเติม" เพราะมีความเกี่ยวข้องกับการสาธิตองค์ประกอบกล่องโต้ตอบ มากกว่าองค์ประกอบกล่องโต้ตอบทั่วไป
ระดับการป้องกันการเลื่อน
เมื่อกล่องโต้ตอบแสดงขึ้น ผู้ใช้ยังคงสามารถเลื่อนหน้าเว็บอยู่ด้านหลังได้ ซึ่งฉันไม่ต้องการแล้ว
ปกติแล้ว overscroll-behavior
จะเป็นวิธีแก้ปัญหาปกติของฉัน แต่เมื่อดูจากข้อกำหนด ก็ไม่มีผลกับกล่องโต้ตอบเพราะไม่ใช่พอร์ตการเลื่อน กล่าวคือไม่ใช่ตัวเลื่อน จึงไม่มีอะไรให้ป้องกันได้ ฉันสามารถใช้ JavaScript เพื่อดูเหตุการณ์ใหม่จากคู่มือนี้ เช่น "ปิด" และ "เปิด" แล้วสลับ overflow: hidden
ในเอกสาร หรือรอให้ :has()
เสถียรในทุกเบราว์เซอร์
html:has(dialog[open][modal-mode="mega"]) {
overflow: hidden;
}
ตอนนี้เมื่อเปิดกล่องโต้ตอบขนาดใหญ่ เอกสาร HTML จะมี overflow: hidden
เลย์เอาต์ <form>
นอกจากจะเป็นองค์ประกอบที่สำคัญมากในการรวบรวมข้อมูลการโต้ตอบจากผู้ใช้แล้ว ผมยังใช้รูปนี้เพื่อจัดวางองค์ประกอบส่วนหัว ส่วนท้าย และบทความด้วย เลย์เอาต์นี้ทำให้ผมตั้งใจทำให้บทความเป็นแบบ
พื้นที่ที่เลื่อนได้ ฉันบรรลุเป้าหมายนี้ด้วย
grid-template-rows
องค์ประกอบบทความจะมี 1fr
และตัวแบบฟอร์มเองมีความสูงสูงสุดเท่ากับองค์ประกอบของกล่องโต้ตอบ การตั้งค่าความสูงที่พอดีและขนาดแถวที่มั่นคงนี้เป็นสิ่งที่ทำให้องค์ประกอบบทความถูกจำกัดและเลื่อนเมื่อมาถึงจุดนี้ได้
dialog > form {
display: grid;
grid-template-rows: auto 1fr auto;
align-items: start;
max-block-size: 80vh;
max-block-size: 80dvb;
}
การจัดรูปแบบกล่องโต้ตอบ <header>
บทบาทขององค์ประกอบนี้คือการตั้งชื่อเนื้อหากล่องโต้ตอบและมีปุ่มปิดที่ค้นหาได้ง่าย และให้สีของพื้นผิว ทำให้ดูเหมือนว่าอยู่หลังเนื้อหาบทความในกล่องโต้ตอบ ข้อกำหนดเหล่านี้นำไปสู่คอนเทนเนอร์ Flexbox ซึ่งมีการจัดเรียงรายการในแนวตั้งที่เว้นระยะจนถึงขอบ รวมถึงมีระยะห่างจากขอบและช่องว่างบางส่วนเพื่อให้ชื่อและปุ่มปิดมีพื้นที่ว่าง
dialog > form > header {
display: flex;
gap: var(--size-3);
justify-content: space-between;
align-items: flex-start;
background: var(--surface-2);
padding-block: var(--size-3);
padding-inline: var(--size-5);
}
@media (prefers-color-scheme: dark) {
dialog > form > header {
background: var(--surface-1);
}
}
การจัดรูปแบบปุ่มปิดส่วนหัว
เนื่องจากการสาธิตใช้ปุ่ม "เปิดพร็อพ" ปุ่มปิดจึงได้รับการกำหนดค่าให้เป็นปุ่มศูนย์กลางของไอคอนทรงกลมในลักษณะต่อไปนี้
dialog > form > header > button {
border-radius: var(--radius-round);
padding: .75ch;
aspect-ratio: 1;
flex-shrink: 0;
place-items: center;
stroke: currentColor;
stroke-width: 3px;
}
การจัดรูปแบบกล่องโต้ตอบ <article>
องค์ประกอบบทความมีบทบาทพิเศษในกล่องโต้ตอบนี้ กล่าวคือเป็นพื้นที่สำหรับเลื่อนดูในกรณีของกล่องโต้ตอบสูงหรือยาว
เพื่อให้บรรลุเป้าหมายนี้ องค์ประกอบแบบฟอร์มระดับบนสุดได้กำหนดขีดจำกัดสูงสุดไว้บางส่วนสำหรับตัวเอง ซึ่งจะให้ข้อจำกัดสำหรับองค์ประกอบของบทความนี้ในการเข้าถึงหากสูงเกินไป ตั้งค่า overflow-y: auto
เพื่อให้แถบเลื่อนแสดงเมื่อจำเป็นเท่านั้น
มีการเลื่อนอยู่ภายในด้วย overscroll-behavior: contain
ส่วนที่เหลือจะเป็นรูปแบบงานนำเสนอที่กำหนดเอง ดังนี้
dialog > form > article {
overflow-y: auto;
max-block-size: 100%; /* safari */
overscroll-behavior-y: contain;
display: grid;
justify-items: flex-start;
gap: var(--size-3);
box-shadow: var(--shadow-2);
z-index: var(--layer-1);
padding-inline: var(--size-5);
padding-block: var(--size-3);
}
@media (prefers-color-scheme: light) {
dialog > form > article {
background: var(--surface-1);
}
}
การจัดรูปแบบกล่องโต้ตอบ <footer>
บทบาทของส่วนท้ายคือการมีเมนูของปุ่มการทำงาน ระบบจะใช้ Flexbox เพื่อจัดเนื้อหาให้อยู่ท้ายแกนแทรกในบรรทัดของส่วนท้าย จากนั้นมีการเว้นวรรคเพื่อให้ปุ่มมีพื้นที่บางส่วน
dialog > form > footer {
background: var(--surface-2);
display: flex;
flex-wrap: wrap;
gap: var(--size-3);
justify-content: space-between;
align-items: flex-start;
padding-inline: var(--size-5);
padding-block: var(--size-3);
}
@media (prefers-color-scheme: dark) {
dialog > form > footer {
background: var(--surface-1);
}
}
การจัดรูปแบบเมนูส่วนท้ายของกล่องโต้ตอบ
องค์ประกอบ menu
ใช้เพื่อมีปุ่มการทำงานสำหรับกล่องโต้ตอบ โดยใช้เลย์เอาต์ Flexbox แบบรวมที่มี gap
เพื่อเว้นระยะห่างระหว่างปุ่ม องค์ประกอบเมนูมีระยะห่างจากขอบ เช่น <ul>
ฉันยังนำรูปแบบนั้นออกเพราะไม่จำเป็นต้องใช้
dialog > form > footer > menu {
display: flex;
flex-wrap: wrap;
gap: var(--size-3);
padding-inline-start: 0;
}
dialog > form > footer > menu:only-child {
margin-inline-start: auto;
}
แอนิเมชัน
องค์ประกอบกล่องโต้ตอบมักเป็นภาพเคลื่อนไหวเนื่องจากเข้าและออกจากหน้าต่าง การให้กล่องโต้ตอบแสดงการเคลื่อนไหวที่ช่วยสนับสนุนทั้งทางเข้าและออกนี้จะช่วยให้ผู้ใช้ ปรับตัวเข้ากับกระแสได้
โดยปกติแล้วองค์ประกอบกล่องโต้ตอบจะเป็นแบบภาพเคลื่อนไหวเข้าได้อย่างเดียว แต่ออกไม่ได้ เนื่องจากเบราว์เซอร์สลับพร็อพเพอร์ตี้ display
ในองค์ประกอบ ก่อนหน้านี้ คำแนะนำจะ
ตั้งค่าเป็นตารางกริด วิธีนี้จะช่วยให้
ภาพเคลื่อนไหวเข้าและออก
Open Props มาพร้อมภาพเคลื่อนไหวของคีย์เฟรมมากมายให้ใช้งานง่าย ทำให้การจัดเป็นกลุ่มเป็นเรื่องง่ายและอ่านง่าย เป้าหมายภาพเคลื่อนไหวและวิธีการ แบบเลเยอร์ที่ผมทำมีดังนี้
- การเคลื่อนไหวที่ลดลงคือการเปลี่ยนเริ่มต้น ซึ่งเป็นความทึบแสงที่ค่อยๆ เฟดเข้าและออก
- หากการเคลื่อนไหวไม่มีปัญหา ระบบจะเพิ่มภาพเคลื่อนไหวและปรับขนาด
- มีการปรับเลย์เอาต์อุปกรณ์เคลื่อนที่ที่ปรับเปลี่ยนตามอุปกรณ์สำหรับกล่องโต้ตอบขนาดใหญ่ให้เลื่อนออก
การเปลี่ยนผ่านเริ่มต้นที่ปลอดภัยและมีความหมาย
แม้ว่า Open Props จะมีคีย์เฟรมสำหรับการค่อยๆ เข้าและออก แต่ฉันชอบวิธีการเปลี่ยนแบบเป็นชั้นที่เป็นค่าเริ่มต้นโดยมีภาพเคลื่อนไหวคีย์เฟรมเป็นการอัปเกรดที่เป็นไปได้ ก่อนหน้านี้เราได้จัดรูปแบบระดับการเข้าถึงของกล่องโต้ตอบโดยให้มีความทึบแสง จัดระเบียบ 1
หรือ 0
โดยขึ้นอยู่กับแอตทริบิวต์ [open]
อยู่แล้ว หากต้องการเปลี่ยนจาก 0% ถึง 100% ให้บอกเบราว์เซอร์ว่าคุณต้องการการค่อยๆ เปลี่ยนนานแค่ไหนและประเภทใด
dialog {
transition: opacity .5s var(--ease-3);
}
การเพิ่มการเคลื่อนไหวในการเปลี่ยน
หากผู้ใช้ยอมรับการเคลื่อนไหว กล่องโต้ตอบขนาดใหญ่และกล่องโต้ตอบขนาดเล็กควรเลื่อนขึ้นเป็นทางเข้า และปรับขนาดออกเมื่อออกจากกล่องโต้ตอบ โดยใช้คำค้นหาสื่อ prefers-reduced-motion
และพรอมต์แบบเปิดบางรายการดังต่อไปนี้
@media (prefers-reduced-motion: no-preference) {
dialog {
animation: var(--animation-scale-down) forwards;
animation-timing-function: var(--ease-squish-3);
}
dialog[open] {
animation: var(--animation-slide-in-up) forwards;
}
}
การปรับภาพเคลื่อนไหวขณะออกจากแอปสำหรับอุปกรณ์เคลื่อนที่
ในช่วงต้นของส่วนการจัดรูปแบบ รูปแบบกล่องโต้ตอบขนาดใหญ่ได้รับการปรับเปลี่ยนสำหรับอุปกรณ์เคลื่อนที่ให้เหมือนกับชีตการทำงาน เหมือนกับว่ากระดาษแผ่นเล็กๆ เลื่อนขึ้นมาจากด้านล่างของหน้าจอและยังคงแนบอยู่ด้านล่าง ภาพเคลื่อนไหวจากการขยายขนาดไม่เหมาะกับการออกแบบใหม่นี้ และเราสามารถปรับได้ด้วยข้อความค้นหาสื่อ 2-3 รายการและ Open Props บางส่วนดังนี้
@media (prefers-reduced-motion: no-preference) and @media (max-width: 768px) {
dialog[modal-mode="mega"] {
animation: var(--animation-slide-out-down) forwards;
animation-timing-function: var(--ease-squish-2);
}
}
JavaScript
สิ่งที่ JavaScript เพิ่มได้มีอยู่หลายอย่าง ได้แก่
// dialog.js
export default async function (dialog) {
// add light dismiss
// add closing and closed events
// add opening and opened events
// add removed event
// removing loading attribute
}
ส่วนเพิ่มเติมเหล่านี้เกิดจากความต้องการให้ปิดแสง (คลิกฉากหลังของกล่องโต้ตอบ) ภาพเคลื่อนไหว และเหตุการณ์เพิ่มเติมบางอย่างเพื่อให้รับข้อมูลแบบฟอร์มได้ดีขึ้น
กำลังเพิ่มการปิดแสง
งานนี้ไม่ซับซ้อนและเป็นส่วนเพิ่มเติมที่ยอดเยี่ยมสำหรับองค์ประกอบกล่องโต้ตอบที่ไม่เคลื่อนไหว การโต้ตอบจะเกิดจากการดูการคลิกในองค์ประกอบกล่องโต้ตอบและใช้ประโยชน์จากการฟอกอากาศเหตุการณ์เพื่อประเมินสิ่งที่ถูกคลิก และจะใช้ close()
ก็ต่อเมื่อเป็นองค์ประกอบด้านบนสุดเท่านั้น
export default async function (dialog) {
dialog.addEventListener('click', lightDismiss)
}
const lightDismiss = ({target:dialog}) => {
if (dialog.nodeName === 'DIALOG')
dialog.close('dismiss')
}
ประกาศ dialog.close('dismiss')
ระบบจะเรียกเหตุการณ์และจัดเตรียมสตริงให้
JavaScript อื่นๆ จะดึงสตริงนี้ไปใช้ได้เพื่อดูข้อมูลเชิงลึกเกี่ยวกับการปิดกล่องโต้ตอบ คุณจะเห็นว่าฉันระบุสตริงปิดทุกครั้งที่เรียก
ฟังก์ชันจากปุ่มต่างๆ เพื่อให้บริบทแก่แอปพลิเคชันของฉันเกี่ยวกับ
การโต้ตอบของผู้ใช้
การเพิ่มกิจกรรมการปิดและปิด
องค์ประกอบกล่องโต้ตอบมาพร้อมกับเหตุการณ์ปิด ซึ่งจะปล่อยออกมาทันทีเมื่อมีการเรียกฟังก์ชันกล่องโต้ตอบ close()
เนื่องจากเรากำลังสร้างองค์ประกอบนี้ให้เคลื่อนไหว จึงเป็นการดีที่มีเหตุการณ์ก่อนและหลังภาพเคลื่อนไหว เพื่อให้มีการเปลี่ยนแปลงในการจับข้อมูลหรือรีเซ็ตฟอร์มกล่องโต้ตอบ ฉันใช้ส่วนนี้เพื่อจัดการการเพิ่มแอตทริบิวต์ inert
ในกล่องโต้ตอบแบบปิด และในการสาธิต ฉันใช้รูปภาพเหล่านี้เพื่อแก้ไขรายการรูปโปรไฟล์หากผู้ใช้ส่งรูปภาพใหม่
เพื่อให้บรรลุเป้าหมายนี้ ให้สร้างเหตุการณ์ใหม่ 2 รายการที่ชื่อว่า closing
และ closed
จากนั้นฟังเหตุการณ์ปิดในตัวบนกล่องโต้ตอบ จากที่นี่ ให้ตั้งค่ากล่องโต้ตอบเป็น inert
และส่งเหตุการณ์ closing
งานถัดไปคือการรอให้ภาพเคลื่อนไหวและการเปลี่ยนทำงานในกล่องโต้ตอบเสร็จ จากนั้นจึงส่งเหตุการณ์ closed
const dialogClosingEvent = new Event('closing')
const dialogClosedEvent = new Event('closed')
export default async function (dialog) {
…
dialog.addEventListener('close', dialogClose)
}
const dialogClose = async ({target:dialog}) => {
dialog.setAttribute('inert', '')
dialog.dispatchEvent(dialogClosingEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogClosedEvent)
}
const animationsComplete = element =>
Promise.allSettled(
element.getAnimations().map(animation =>
animation.finished))
ฟังก์ชัน animationsComplete
ซึ่งใช้ในการสร้างคอมโพเนนต์โทสต์ด้วยจะส่งคืนคำสัญญาโดยอิงตามความสำเร็จของภาพเคลื่อนไหวและการเปลี่ยนที่สัญญาไว้ และนี่คือเหตุผลที่ dialogClose
เป็นฟังก์ชันที่ไม่พร้อมกัน จึงทำให้ await
คำสัญญากลับมาได้และเดินหน้าต่อสู่กิจกรรมที่ปิดไปแล้วได้อย่างมั่นใจ
การเพิ่มกิจกรรมที่เปิดอยู่และเปิด
การเพิ่มเหตุการณ์เหล่านี้ไม่ใช่เรื่องง่ายนักเนื่องจากองค์ประกอบกล่องโต้ตอบในตัวไม่ได้ให้เหตุการณ์เปิดเหมือนกับการปิด ฉันใช้ MutationObserver เพื่อให้ข้อมูลเชิงลึกเกี่ยวกับการเปลี่ยนแปลงแอตทริบิวต์ของกล่องโต้ตอบ ในเครื่องมือสังเกตการณ์นี้ ผมจะคอยดูการเปลี่ยนแปลงของแอตทริบิวต์เปิดและจัดการเหตุการณ์ที่กำหนดเองให้สอดคล้องกัน
สร้าง 2 เหตุการณ์ใหม่ชื่อ opening
และ opened
ซึ่งคล้ายกับกิจกรรมที่เราเริ่มกิจกรรมปิดและปิดไปแล้ว ในตอนที่ก่อนหน้านี้เราฟังเหตุการณ์การปิดกล่องโต้ตอบ คราวนี้ก็ใช้ตัวสังเกตการเปลี่ยนแปลงที่สร้างขึ้นเพื่อดูแอตทริบิวต์ของกล่องโต้ตอบ
…
const dialogOpeningEvent = new Event('opening')
const dialogOpenedEvent = new Event('opened')
export default async function (dialog) {
…
dialogAttrObserver.observe(dialog, {
attributes: true,
})
}
const dialogAttrObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(async mutation => {
if (mutation.attributeName === 'open') {
const dialog = mutation.target
const isOpen = dialog.hasAttribute('open')
if (!isOpen) return
dialog.removeAttribute('inert')
// set focus
const focusTarget = dialog.querySelector('[autofocus]')
focusTarget
? focusTarget.focus()
: dialog.querySelector('button').focus()
dialog.dispatchEvent(dialogOpeningEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogOpenedEvent)
}
})
})
ระบบจะเรียกใช้ฟังก์ชันเรียกกลับของผู้สังเกตการเปลี่ยนแปลงเมื่อแอตทริบิวต์ของกล่องโต้ตอบมีการเปลี่ยนแปลง ซึ่งทำให้รายการการเปลี่ยนแปลงเป็นอาร์เรย์ ทำซ้ำการเปลี่ยนแปลงแอตทริบิวต์โดยมองหา attributeName
ที่เปิดอยู่ ถัดไป ให้ตรวจสอบว่าองค์ประกอบมีแอตทริบิวต์หรือไม่ ซึ่งจะบอกว่ากล่องโต้ตอบเปิดขึ้นหรือไม่ หากเปิดอยู่ ให้นำแอตทริบิวต์ inert
ออก ตั้งค่าโฟกัสเป็นองค์ประกอบที่ขอ autofocus
หรือองค์ประกอบ button
แรกที่พบในกล่องโต้ตอบ สุดท้าย ส่งเหตุการณ์เปิดทันที แล้วรอให้ภาพเคลื่อนไหวเสร็จสิ้น แล้วส่งเหตุการณ์ที่เปิดอยู่ แล้วส่งเหตุการณ์ที่เปิดอยู่ คล้ายกับเหตุการณ์ปิดและเหตุการณ์ปิด
การเพิ่มกิจกรรมที่นำออกไปแล้ว
ในแอปพลิเคชันหน้าเว็บเดียว มักมีการเพิ่มและนำกล่องโต้ตอบออกโดยอิงตามเส้นทางหรือความต้องการและสถานะอื่นๆ ของแอปพลิเคชัน การล้างเหตุการณ์หรือข้อมูลจะมีประโยชน์เมื่อนำกล่องโต้ตอบออก
คุณจะดำเนินการได้ด้วยเครื่องมือสังเกตการเปลี่ยนแปลงรายอื่น ครั้งนี้ แทนที่จะสังเกตแอตทริบิวต์ในองค์ประกอบกล่องโต้ตอบ เราจะสังเกตองค์ประกอบย่อยขององค์ประกอบเนื้อหา และคอยดูองค์ประกอบกล่องโต้ตอบที่กำลังนำออก
…
const dialogRemovedEvent = new Event('removed')
export default async function (dialog) {
…
dialogDeleteObserver.observe(document.body, {
attributes: false,
subtree: false,
childList: true,
})
}
const dialogDeleteObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(mutation => {
mutation.removedNodes.forEach(removedNode => {
if (removedNode.nodeName === 'DIALOG') {
removedNode.removeEventListener('click', lightDismiss)
removedNode.removeEventListener('close', dialogClose)
removedNode.dispatchEvent(dialogRemovedEvent)
}
})
})
})
ระบบจะเรียกใช้โค้ดเรียกกลับของผู้สังเกตการเปลี่ยนแปลงเมื่อมีการเพิ่มหรือนำเด็กออกจากเนื้อความของเอกสาร การเปลี่ยนแปลงที่กําลังดูอยู่ของ removedNodes
ที่มีกล่องโต้ตอบ nodeName
หากนำกล่องโต้ตอบออก ระบบจะนำเหตุการณ์การคลิกและปิดออกเพื่อเพิ่มพื้นที่ว่างในหน่วยความจำ และจะส่งเหตุการณ์ที่นำออกที่กำหนดเองออก
การนำแอตทริบิวต์การโหลดออก
หากไม่ต้องการให้ภาพเคลื่อนไหวกล่องโต้ตอบเล่นภาพเคลื่อนไหวการออกเมื่อเพิ่มลงในหน้าเว็บหรือเมื่อหน้าเว็บโหลด ระบบจะเพิ่มแอตทริบิวต์การโหลดลงในกล่องโต้ตอบ สคริปต์ต่อไปนี้จะรอให้ภาพเคลื่อนไหวในกล่องโต้ตอบทำงานเสร็จ จากนั้นจึงนำแอตทริบิวต์ออก ตอนนี้กล่องโต้ตอบมีภาพเคลื่อนไหวเข้าและออกได้อย่างอิสระ และเราซ่อนภาพเคลื่อนไหวที่ไม่ทำให้เสียสมาธิไว้ได้อย่างอิสระ
export default async function (dialog) {
…
await animationsComplete(dialog)
dialog.removeAttribute('loading')
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับปัญหาการป้องกันภาพเคลื่อนไหวของคีย์เฟรมขณะโหลดหน้าเว็บที่นี่
รวมทั้งหมดไว้ด้วยกัน
นี่คือ dialog.js
ทั้งหมดของเรา ตอนนี้เราได้อธิบายไว้ทีละหัวข้อแล้ว
// custom events to be added to <dialog>
const dialogClosingEvent = new Event('closing')
const dialogClosedEvent = new Event('closed')
const dialogOpeningEvent = new Event('opening')
const dialogOpenedEvent = new Event('opened')
const dialogRemovedEvent = new Event('removed')
// track opening
const dialogAttrObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(async mutation => {
if (mutation.attributeName === 'open') {
const dialog = mutation.target
const isOpen = dialog.hasAttribute('open')
if (!isOpen) return
dialog.removeAttribute('inert')
// set focus
const focusTarget = dialog.querySelector('[autofocus]')
focusTarget
? focusTarget.focus()
: dialog.querySelector('button').focus()
dialog.dispatchEvent(dialogOpeningEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogOpenedEvent)
}
})
})
// track deletion
const dialogDeleteObserver = new MutationObserver((mutations, observer) => {
mutations.forEach(mutation => {
mutation.removedNodes.forEach(removedNode => {
if (removedNode.nodeName === 'DIALOG') {
removedNode.removeEventListener('click', lightDismiss)
removedNode.removeEventListener('close', dialogClose)
removedNode.dispatchEvent(dialogRemovedEvent)
}
})
})
})
// wait for all dialog animations to complete their promises
const animationsComplete = element =>
Promise.allSettled(
element.getAnimations().map(animation =>
animation.finished))
// click outside the dialog handler
const lightDismiss = ({target:dialog}) => {
if (dialog.nodeName === 'DIALOG')
dialog.close('dismiss')
}
const dialogClose = async ({target:dialog}) => {
dialog.setAttribute('inert', '')
dialog.dispatchEvent(dialogClosingEvent)
await animationsComplete(dialog)
dialog.dispatchEvent(dialogClosedEvent)
}
// page load dialogs setup
export default async function (dialog) {
dialog.addEventListener('click', lightDismiss)
dialog.addEventListener('close', dialogClose)
dialogAttrObserver.observe(dialog, {
attributes: true,
})
dialogDeleteObserver.observe(document.body, {
attributes: false,
subtree: false,
childList: true,
})
// remove loading attribute
// prevent page load @keyframes playing
await animationsComplete(dialog)
dialog.removeAttribute('loading')
}
การใช้โมดูล dialog.js
คาดว่าฟังก์ชันที่ส่งออกจากโมดูลจะมีการเรียกและส่งผ่านองค์ประกอบกล่องโต้ตอบที่ต้องการให้เพิ่มเหตุการณ์และฟังก์ชันใหม่เหล่านี้
import GuiDialog from './dialog.js'
const MegaDialog = document.querySelector('#MegaDialog')
const MiniDialog = document.querySelector('#MiniDialog')
GuiDialog(MegaDialog)
GuiDialog(MiniDialog)
เช่นเดียวกัน กล่องโต้ตอบ 2 รายการจะได้รับการอัปเกรดด้วยการปิดแสง การแก้ไขการโหลดภาพเคลื่อนไหว และเหตุการณ์อื่นๆ ที่จะทำงานได้
การฟังเหตุการณ์ใหม่ที่กำหนดเอง
ตอนนี้องค์ประกอบกล่องโต้ตอบที่อัปเกรดแต่ละรายการจะตรวจจับเหตุการณ์ใหม่ 5 เหตุการณ์ได้ ดังนี้
MegaDialog.addEventListener('closing', dialogClosing)
MegaDialog.addEventListener('closed', dialogClosed)
MegaDialog.addEventListener('opening', dialogOpening)
MegaDialog.addEventListener('opened', dialogOpened)
MegaDialog.addEventListener('removed', dialogRemoved)
ต่อไปนี้คือ 2 ตัวอย่างของการจัดการเหตุการณ์เหล่านั้น
const dialogOpening = ({target:dialog}) => {
console.log('Dialog opening', dialog)
}
const dialogClosed = ({target:dialog}) => {
console.log('Dialog closed', dialog)
console.info('Dialog user action:', dialog.returnValue)
if (dialog.returnValue === 'confirm') {
// do stuff with the form values
const dialogFormData = new FormData(dialog.querySelector('form'))
console.info('Dialog form data', Object.fromEntries(dialogFormData.entries()))
// then reset the form
dialog.querySelector('form')?.reset()
}
}
ในการสาธิตที่ผมสร้างด้วยองค์ประกอบกล่องโต้ตอบ ผมใช้เหตุการณ์ที่ปิดไปแล้วและข้อมูลแบบฟอร์ม เพื่อเพิ่มองค์ประกอบรูปโปรไฟล์ใหม่ลงในรายการ ช่วงเวลาเหมาะสมที่กล่องโต้ตอบทำให้ภาพเคลื่อนไหวตอนออกจากการทำงานเสร็จสมบูรณ์ แล้วสคริปต์บางตัวก็เคลื่อนไหวในรูปโปรไฟล์ใหม่ ด้วยเหตุการณ์ใหม่ๆ การผสานรวมประสบการณ์ของผู้ใช้จึงราบรื่นยิ่งขึ้น
ประกาศ dialog.returnValue
: ประกอบด้วยสตริงปิดที่ส่งผ่านเมื่อมีการเรียกเหตุการณ์ close()
ของกล่องโต้ตอบ สิ่งสำคัญในเหตุการณ์ dialogClosed
คือต้องทราบว่ากล่องโต้ตอบถูกปิด ยกเลิก หรือยืนยันแล้ว หากยืนยันได้แล้ว สคริปต์ก็จะจับค่าของแบบฟอร์มและรีเซ็ตแบบฟอร์ม การรีเซ็ตมีประโยชน์มากเมื่อกล่องโต้ตอบแสดงขึ้นอีกครั้ง ข้อความจะว่างเปล่าและพร้อมสำหรับการส่งใหม่
บทสรุป
ตอนนี้คุณก็รู้แล้วว่าตัวเองทำยังไง คุณจะทำอะไรบ้าง‽ 🙂
มาลองเปลี่ยนแนวทางของเราและเรียนรู้วิธีทั้งหมดเพื่อสร้างเว็บกันเถอะ
สร้างเดโม ลิงก์ทวีตฉัน แล้วฉันจะเพิ่มลงในส่วนรีมิกซ์ของชุมชนด้านล่าง
รีมิกซ์ของชุมชน
- @GrimLink พร้อมกล่องโต้ตอบ 3-in-1
- @mikemai2awesome ด้วยรีมิกซ์ดีๆ ที่ไม่เปลี่ยนพร็อพเพอร์ตี้
display
- @geoffrich_ กับ Svelte และ Svelte FLIP ที่ขัดเกลาอย่างสวยงาม
แหล่งข้อมูล
- ซอร์สโค้ดบน GitHub
- รูปโปรไฟล์ Doodle