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

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

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

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

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

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

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

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

ในเบราว์เซอร์ ระบบจะใช้องค์ประกอบ <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 โค้ดนี้แทบจะเหมือนกับ 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 จำลองภาพเคลื่อนไหว