ตัวเลือกเพิ่มเติมสำหรับการจัดสไตล์ <details>

เผยแพร่: 6 พ.ย. 2024

ตั้งแต่ Chrome 131 เป็นต้นไป คุณจะมีตัวเลือกเพิ่มเติมในการจัดรูปแบบโครงสร้างขององค์ประกอบ <details> และ <summary> ตอนนี้คุณใช้องค์ประกอบเหล่านี้ได้แล้วเมื่อสร้างวิดเจ็ตการเปิดเผยข้อมูลหรือวิดเจ็ตแบบออร์แกน

โดยเฉพาะอย่างยิ่ง การเปลี่ยนแปลงที่เปิดตัวใน Chrome 131 จะช่วยให้ใช้พร็อพเพอร์ตี้ display ในองค์ประกอบเหล่านี้ได้ และเพิ่มองค์ประกอบเสมือน ::details-content เพื่อจัดรูปแบบส่วนที่ขยายและยุบ

Browser Support

  • Chrome: 131.
  • Edge: 131.
  • Firefox: 143.
  • Safari: 18.4.

Source

การตั้งค่า display ในองค์ประกอบ <details>

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

ในตัวอย่างต่อไปนี้ Exclusive Accordion ประกอบด้วยองค์ประกอบ <details> หลายรายการที่วางอยู่ข้างกัน เมื่อขยายองค์ประกอบ <details> รายการใดรายการหนึ่ง เนื้อหาขององค์ประกอบนั้นจะอยู่ข้าง <summary>

สาธิต

กำลังบันทึก

การบันทึก https://codepen.io/web-dot-dev/pen/VwoBQjY ใน Chrome 131

ซึ่งทำได้โดยใช้เลย์เอาต์ Flex ในองค์ประกอบ <details> โดยใช้ CSS ต่อไปนี้

details {
  display: flex;
  flex-direction: row;
}

นอกจากนี้ ยังอนุญาตให้ใช้ค่าการแสดงผลอื่นๆ เช่น grid ด้วย

หมายเหตุเกี่ยวกับการใช้ display: inline

ค่า display ที่อาจทำให้เกิดผลลัพธ์ที่ไม่คาดคิดคือ inline ไม่ใช่เพราะใช้ไม่ได้ แต่เป็นเพราะข้อจำกัดของโปรแกรมแยกวิเคราะห์ HTML

เมื่อวางองค์ประกอบ <details> ไว้ภายในย่อหน้า จะบังคับให้ตัวแยกวิเคราะห์ HTML ปิดย่อหน้าที่เปิดอยู่ก่อน ตามที่กำหนดไว้ในส่วนที่ 13.2.6.4.7 ของมาตรฐาน HTML

แท็กเริ่มต้นที่มีชื่อแท็กเป็นหนึ่งในแท็กต่อไปนี้ "address", "article", "aside", "blockquote", "center", "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "main", "menu", "nav", "ol", "p", "search", "section", "summary", "ul"

หากกลุ่มองค์ประกอบที่เปิดอยู่มีองค์ประกอบ p ในขอบเขตปุ่ม ให้ปิดองค์ประกอบ p แทรกองค์ประกอบ HTML สำหรับโทเค็น

ด้วยเหตุนี้ <details> จะไหลไปในทิศทางของบล็อก ไม่ว่าคุณจะตั้งค่า display: inline หรือไม่ก็ตาม

ตัวอย่างเช่น มาร์กอัปต่อไปนี้

<p>Hello <details>…</details> world</p>

หลังจากแยกวิเคราะห์แล้ว จะเป็นดังนี้

<p>Hello </p><details>…</details> world<p></p>

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

โปรดทราบว่าการดำเนินการนี้ใช้ได้กับการซ้อน <details> ภายใน <p> เท่านั้น การใช้ display: inline ใน <details> ภายใน <div> จะทำงานได้ดี

องค์ประกอบจำลอง ::details-content

ในเบราว์เซอร์ ระบบจะใช้ Shadow DOM เพื่อใช้งานองค์ประกอบ <details> โดยมี <slot> สำหรับสรุป (มีองค์ประกอบย่อยสรุปเริ่มต้น) และ <slot> สำหรับเนื้อหาที่เหลือทั้งหมด ซึ่งหมายถึงองค์ประกอบย่อยทั้งหมดขององค์ประกอบ <details> ยกเว้นองค์ประกอบ <summary>

<details>
  ↳ #shadow-root (user-agent)
      <slot id="details-summary">
        <summary>Details</summary>
        <!-- The summary goes here -->
      </slot>
      <slot id="details-content">
        <!-- All content goes here -->
      </slot>
</details>

นอกเหนือจากการใช้โฆษณา Display ประเภทอื่นๆ ใน <details> แล้ว ตอนนี้คุณยังกำหนดเป้าหมายช่องเนื้อหาได้โดยใช้::details-contentองค์ประกอบเสมือน คุณสามารถใช้ Pseudo นี้เพื่อจัดรูปแบบคอนเทนเนอร์ที่ครอบเนื้อหาขององค์ประกอบ <details>

details::details-content {
  border: 5px dashed hotpink;
}

หากต้องการใช้รูปแบบที่ตั้งค่าไว้เฉพาะเมื่อองค์ประกอบ <details> อยู่ในสถานะเปิด ให้เพิ่มตัวเลือก [open] ไว้ข้างหน้า

[open]::details-content {
  border: 5px dashed hotpink;
}

ขอแนะนำให้ใช้สไตล์กับองค์ประกอบเสมือน ::details-content เท่านั้นเมื่อองค์ประกอบ <details> อยู่ในสถานะ [open]

สาธิต

กำลังบันทึก

การบันทึก https://codepen.io/web-dot-dev/pen/oNKMEYv ใน Chrome 131

ประเภท display ของ ::details-content ตั้งค่าเป็น block ในสไตล์ชีต UA ในขณะที่ก่อนหน้านี้ตั้งค่าเป็น display: contents การเปลี่ยนแปลงนี้อาจส่งผลเสียต่อคุณในบางกรณี เช่น เนื้อหาที่เปิดเผยซึ่งอิงตามheight: 100% หากคุณพบปัญหานี้ คุณสามารถแก้ไขได้โดยตั้งค่าdisplayกลับเป็นcontents ดังนี้ details[open]::details-content { display: contents; }

การทำให้องค์ประกอบจำลอง ::details-content เคลื่อนไหว

คุณสามารถทำให้เนื้อหาขององค์ประกอบ <details> เคลื่อนไหวขณะขยายได้ ในตัวอย่างต่อไปนี้ ความกว้างจะเคลื่อนไหวจาก 0px เป็น 300px

::details-content {
  transition: width 0.5s ease, content-visibility 0.5s ease allow-discrete;
  width: 0;
}

[open]::details-content {
  width: 300px;
}

นอกเหนือจากการเปลี่ยน width แล้ว พร็อพเพอร์ตี้ content-visibility ก็ต้องเปลี่ยนด้วย เนื่องจากค่าจะเปลี่ยนแปลงระหว่างสถานะที่ยังไม่ได้เปิดและสถานะที่เปิดแล้ว ตามที่กำหนดไว้ในชีตสไตล์ User-Agent เนื่องจากพร็อพเพอร์ตี้นั้นเป็นพร็อพเพอร์ตี้ที่เคลื่อนไหวได้แบบไม่ต่อเนื่อง คุณจึงต้องใช้คีย์เวิร์ด allow-discrete เพื่อให้ทำงานได้

เมื่อเพิ่มลงในเดโม Accordion แบบพิเศษที่แชร์ไว้ก่อนหน้านี้ ผลลัพธ์จะเป็นดังนี้

สาธิต

กำลังบันทึก

การบันทึก https://codepen.io/web-dot-dev/pen/XWvBZNo ใน Chrome 131

height ยังสามารถทำเป็นภาพเคลื่อนไหวได้ด้วย หากต้องการเปลี่ยนภาพเคลื่อนไหวเป็น height: auto คุณต้องใช้ interpolate-size หรือ calc-size() นอกจากนี้ ให้ใช้ overflow: clip กับเนื้อหาเพื่อป้องกันไม่ให้เนื้อหาล้นออกมาจาก ::details-content

::details-content {
    transition: height 0.5s ease, content-visibility 0.5s ease allow-discrete;
    height: 0;
    overflow: clip;
}

/* Browser supports interpolate-size */
@supports (interpolate-size: allow-keywords) {
    :root {
        interpolate-size: allow-keywords;
    }

    [open]::details-content {
        height: auto;
    }
}

/* Fallback for browsers with no interpolate-size support */
@supports not (interpolate-size: allow-keywords) {
    [open]::details-content {
        height: 150px;
        overflow-y: scroll; /* In case the contents should be taller than 150px */
    }
}

คุณดูโค้ดที่ใช้งานได้ในเดโมต่อไปนี้ ซึ่งได้แรงบันดาลใจจาก Accordion ของ Material UI เนื้อหาขององค์ประกอบ <details> แต่ละรายการจะเคลื่อนไหวอย่างสวยงาม

สาธิต

กำลังบันทึก

การบันทึก https://codepen.io/web-dot-dev/pen/ExqpQZM ใน Chrome 131

ในเบราว์เซอร์ที่ไม่รองรับ ::details-content คอมโพเนนต์จะยังคงทำงานได้ดี สิ่งเดียวที่ผู้เข้าชมจะไม่เห็นคือภาพเคลื่อนไหว

การตรวจหาฟีเจอร์

หากต้องการตรวจหาการรองรับ::details-contentเทียมใน CSS ให้ใช้ข้อมูลโค้ดต่อไปนี้

@supports selector(::details-content) {
  
}

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

ข้อควรพิจารณาเกี่ยวกับการช่วยเหลือพิเศษ

การเปิดตัวองค์ประกอบเสมือน ::details-content และความสามารถในการเปลี่ยนประเภทการแสดงผลไม่มีผลต่อการช่วยเหลือพิเศษขององค์ประกอบ <details>

เช่นเดียวกับก่อนหน้านี้ อย่างน้อยในเบราว์เซอร์ที่ใช้ Chromium และตามมาตรฐาน HTML องค์ประกอบ <details> จะค้นหาได้และขยายโดยอัตโนมัติเมื่อเบราว์เซอร์พยายามเลื่อนไปยังเนื้อหาที่ซ่อนอยู่เพื่อตอบสนองต่อการค้นหาในหน้า, ScrollToTextFragment และการนำทางไปยังส่วนย่อยขององค์ประกอบ ซึ่งจะไม่เปลี่ยนแปลง

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

แล้วการจัดรูปแบบเครื่องหมายล่ะ

ปัจจุบันการจัดรูปแบบเครื่องหมายรายการใช้ร่วมกันไม่ได้เนื่องจากมี 2 แนวทางที่แตกต่างกัน โดยแนวทางหนึ่งใช้โดย Gecko และ Chromium (ปัจจุบัน) และอีกแนวทางหนึ่งใช้โดย WebKit (ซึ่งก่อนหน้านี้แชร์กับ Chromium)

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

การสาธิตเพิ่มเติม

สุดท้ายนี้ เรามีวิดีโอสาธิตเพิ่มเติมให้คุณดู ทั้งหมดใช้ ::details-content

Accordion ของ UIKit

สาธิต

กำลังบันทึก

การบันทึก https://codepen.io/web-dot-dev/pen/rNXrJyQ ใน Chrome 131

การสาธิตนี้สร้างขึ้นตาม UIKit Accordion โค้ดนี้แทบจะเหมือนกับ Accordion ของ Material UI ที่แชร์ก่อนหน้านี้

วิดเจ็ตการเปิดเผยข้อมูลที่เปิดบางส่วน

สาธิต

กำลังบันทึก

การบันทึก https://codepen.io/web-dot-dev/pen/PoMBQmW ใน Chrome 131

การสาธิตนี้แสดงวิดเจ็ตการเปิดเผยข้อมูลที่เปิดอยู่บางส่วนซึ่งเนื้อหาปรากฏบนหน้าจออยู่แล้ว โดย content-visibility จะตั้งค่าเป็น visible เสมอ height จะเคลื่อนไหวcalc-size()เนื่องจากมีการคำนวณ

::details-content {
  content-visibility: visible; /* Make it always visible */
    
  transition: height 0.5s ease;
  height: 150px;
  overflow: clip;
}

[open]::details-content {
  height: calc-size(auto, size + 0.5rem); /* calc-size because we need to add a length */
}

เพื่อความสะดวกในการจัดรูปแบบ ระบบจะห่อหุ้มเนื้อหาในองค์ประกอบ div ของ Wrapper องค์ประกอบ div ของ Wrapper จะได้รับรูปแบบเลย์เอาต์ เช่น padding และระบบจะเคลื่อนไหวองค์ประกอบเสมือน ::details-content