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

เผยแพร่เมื่อวันที่ 6 พ.ย. 2024

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

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

การรองรับเบราว์เซอร์

  • Chrome: 131
  • Edge: ไม่รองรับ
  • Firefox: ไม่รองรับ
  • Safari: ไม่รองรับ

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

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

ในตัวอย่างต่อไปนี้ 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", "blockเครื่องหมายคำพูด", "center", "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "main", "summary", "nav", "olsearch", "summary", "nav", "olsearch"

หากกององค์ประกอบที่เปิดอยู่มีองค์ประกอบ 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

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

นอกจากการใช้ประเภทการแสดงผลเพิ่มเติมใน <details> แล้ว ตอนนี้คุณยังกําหนดเป้าหมายช่องเนื้อหาได้โดยใช้องค์ประกอบจำลอง ::details-content คุณสามารถใช้สิ่งเทียมนี้เพื่อจัดรูปแบบคอนเทนเนอร์ที่ห่อหุ้มเนื้อหาขององค์ประกอบ <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 จะเปลี่ยนแปลงระหว่างสถานะ "ไม่ได้เปิด" และ "เปิด" ตามที่ระบุไว้ในสไตล์ชีต 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

แอคคอร์เดียนของ UIKit

สาธิต

กำลังบันทึก

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

ตัวอย่างนี้สร้างขึ้นหลังจาก Accordion ของ UIKit โค้ดนั้นเหมือนกันกับหีบเพลง UI ของ Material ที่ได้แชร์ไปก่อนหน้านี้

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

สาธิต

กำลังบันทึก

การบันทึก 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 จะเคลื่อนไหว