Animate to height: auto; (และคำค้นหาการปรับขนาดอื่นๆ ที่เป็นค่าเริ่มต้น) ใน CSS

ใช้พร็อพเพอร์ตี้ interpolate-size หรือฟังก์ชัน calc-size() เพื่อเปิดใช้การเปลี่ยนภาพและภาพเคลื่อนไหวที่ราบรื่นจากความยาวเป็นคีย์เวิร์ดการปรับขนาดตามค่าเริ่มต้นและกลับกัน

เผยแพร่: 17 ก.ย. 2024

บทนำ

ฟีเจอร์ CSS ที่ขอกันบ่อยคือความสามารถในการทำให้ height: auto เคลื่อนไหว คําขอที่แตกต่างออกไปเล็กน้อยคือการเปลี่ยนพร็อพเพอร์ตี้ width แทน height หรือเปลี่ยนไปใช้ขนาดตามธรรมชาติอื่นๆ ที่แสดงโดยคีย์เวิร์ด เช่น min-content, max-content และ fit-content

ตัวอย่างเช่น ในการสาธิตต่อไปนี้ ป้ายกำกับควรเคลื่อนไหวอย่างราบรื่นเป็นขนาดตามปกติเมื่อวางเมาส์เหนือไอคอน

CSS ที่ใช้มีดังนี้

nav a {
    width: 80px;
    overflow-x: clip;
    transition: width 0.35s ease; /* 👈 Transition the width */

    &:hover,
    &:focus-visible {
        width: max-content; /* 👈 Doesn't work with transitions */
    }
}

แม้ว่าจะมีการประกาศ transition เพื่อเปลี่ยนพร็อพเพอร์ตี้ width และมีการประกาศ width: auto ใน :hover แต่การเปลี่ยนก็ไม่ราบรื่น แต่การเปลี่ยนแปลงกลับเกิดขึ้นอย่างกะทันหัน

สร้างภาพเคลื่อนไหวจากคีย์เวิร์ดการปรับขนาดตามเนื้อหาไปยังคีย์เวิร์ดการปรับขนาดตามบริบทด้วย interpolate-size

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

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

แหล่งที่มา

พร็อพเพอร์ตี้ interpolate-size ของ CSS ช่วยให้คุณควบคุมได้ว่าควรอนุญาตภาพเคลื่อนไหวและการเปลี่ยนรูปแบบของคีย์เวิร์ดการปรับขนาดตามค่าเริ่มต้นของ CSS หรือไม่

ค่าเริ่มต้นคือ numeric-only ซึ่งจะไม่เปิดใช้การประมาณ เมื่อตั้งค่าพร็อพเพอร์ตี้เป็น allow-keywords แสดงว่าคุณเลือกใช้การหาค่าเฉลี่ยจากความยาวเป็นคีย์เวิร์ดการปรับขนาดตามค่าเริ่มต้นของ CSS ในกรณีที่เบราว์เซอร์สามารถทำให้คีย์เวิร์ดเหล่านั้นเคลื่อนไหวได้

ตามข้อมูลจำเพาะ

  • numeric-only: ไม่สามารถหาค่าเฉลี่ยของ<intrinsic-size-keyword>
  • allow-keywords: ระบบจะหาค่าประมาณของค่า 2 ค่าได้หากค่าใดค่าหนึ่งเป็น <intrinsic-size-keyword> และอีกค่าหนึ่งเป็น <length-percentage> […]

เนื่องจากพร็อพเพอร์ตี้ interpolate-size เป็นพร็อพเพอร์ตี้ที่รับค่ามา คุณจึงประกาศพร็อพเพอร์ตี้นี้ใน :root เพื่อเปิดใช้การเปลี่ยนจากและไปยังคีย์เวิร์ดการปรับขนาดตามเนื้อหาสำหรับทั้งเอกสารได้ นี่เป็นแนวทางที่แนะนำ

/* Opt-in the whole page to interpolate sizes to/from keywords */
:root {
    interpolate-size: allow-keywords; /* 👈 */
}

ในการแสดงตัวอย่างต่อไปนี้ ระบบจะเพิ่มกฎนี้ลงในโค้ด ด้วยเหตุนี้ ภาพเคลื่อนไหวจาก width: auto ไปยัง width: auto จึงทำงานได้อย่างถูกต้อง (ในเบราว์เซอร์ที่รองรับ)

จํากัดการเข้าถึงของการเลือกรับโดยจํากัดตัวเลือกให้แคบลง

หากต้องการจํากัดการเลือกใช้ allow-keywords ไว้เฉพาะที่ส่วนย่อยของเอกสาร ให้ปรับตัวเลือกจาก :root เฉพาะองค์ประกอบที่คุณต้องการกําหนดเป้าหมาย ตัวอย่างเช่น ในกรณีที่ <header> ของหน้าเว็บใช้ร่วมกับการเปลี่ยนประเภทเหล่านี้ไม่ได้ คุณอาจจำกัดการเลือกใช้ไว้เฉพาะองค์ประกอบ <main> และองค์ประกอบที่สืบทอดมา ดังนี้

main { /* 👈 Scope the opt-in to only <main> and its descendants */
    interpolate-size: allow-keywords;
}

เหตุใดจึงไม่อนุญาตให้มีภาพเคลื่อนไหวจากคีย์เวิร์ดการปรับขนาดและไปยังคีย์เวิร์ดการปรับขนาดโดยค่าเริ่มต้น

ความคิดเห็นที่พบบ่อยเกี่ยวกับกลไกการเลือกรับนี้คือ เบราว์เซอร์ควรอนุญาตให้ใช้การเปลี่ยนภาพและภาพเคลื่อนไหวจากคีย์เวิร์ดการปรับขนาดตามเนื้อหาเป็นความยาวโดยค่าเริ่มต้น

เราได้ศึกษาตัวเลือกในการเปิดใช้ลักษณะการทำงานนี้ระหว่างการพัฒนาฟีเจอร์ คณะทำงานพบว่าการเปิดใช้การตั้งค่านี้โดยค่าเริ่มต้นใช้งานร่วมกับเวอร์ชันเก่าไม่ได้ เนื่องจากสไตล์ชีตจำนวนมากถือว่าคีย์เวิร์ดการปรับขนาดตามค่าเริ่มต้น (เช่น auto หรือ min-content) ไม่สามารถเคลื่อนไหวได้ ดูรายละเอียดได้ในความคิดเห็นนี้เกี่ยวกับปัญหาของกลุ่มทํางาน CSS ที่เกี่ยวข้อง

ดังนั้นพร็อพเพอร์ตี้จึงเป็นแบบเลือกใช้ การเลือกรับทั้งเอกสารเป็นเพียงinterpolate-size: allow-sizesการประกาศใน :root ตามที่อธิบายไว้ก่อนหน้านี้ เนื่องจากลักษณะการสืบทอด

สร้างภาพเคลื่อนไหวจากคีย์เวิร์ดการปรับขนาดตามเนื้อหาไปยังคีย์เวิร์ดการปรับขนาดตามบริบทด้วย calc-size()

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

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

แหล่งที่มา

อีกวิธีในการเปิดใช้การประมาณค่าจากและไปยังคีย์เวิร์ดการปรับขนาดตามข้อมูลที่มีอยู่คือการใช้ฟังก์ชัน calc-size() ซึ่งช่วยให้สามารถดำเนินการทางคณิตศาสตร์กับขนาดที่แท้จริงได้อย่างปลอดภัยและชัดเจน

ฟังก์ชันนี้รับอาร์กิวเมนต์ 2 รายการตามลําดับดังนี้

  • พื้นฐานขนาดการคํานวณ ซึ่งอาจเป็น <intrinsic-size-keyword> หรือ calc-size() ที่ฝังอยู่ก็ได้
  • การคํานวณขนาดการคาดคะเน ซึ่งช่วยให้คุณทําการคํานวณโดยใช้พื้นฐานขนาดการคาดคะเนได้ หากต้องการอ้างอิงพื้นฐานขนาดการคํานวณ ให้ใช้คีย์เวิร์ด size

ตัวอย่างเช่น

width: calc-size(auto, size);        // = the auto width, unaltered
width: calc-size(min-content, size); // = the min-content width, unaltered

เมื่อเพิ่ม calc-size() ลงในเดโมต้นฉบับ โค้ดจะมีลักษณะดังนี้

nav a {
    width: 80px;
    overflow-x: clip;
    transition: width 0.35s ease;

    &:hover,
    &:focus-visible {
        width: calc-size(max-content, size); /* 👈 */
    }
}

ผลลัพธ์ที่แสดงจะเหมือนกับเมื่อใช้ interpolate-size ทุกประการ ดังนั้นในกรณีนี้ คุณควรใช้ interpolate-size

สิ่งที่ calc-size() ทำได้ดีคือความสามารถในการคํานวณ ซึ่งเป็นสิ่งที่ interpolate-size ทําไม่ได้

width: calc-size(auto, size - 10px); // = The auto width minus 10 pixels
width: calc-size(min-content, size + 1rem); // = The min-content width plus 1rem
width: calc-size(max-content, size * .5);   // = Half the max-content width

เช่น หากต้องการให้ย่อหน้าทั้งหมดในหน้าเว็บมีขนาดเป็นจำนวนที่หารด้วย 50px ได้สนิทที่สุด ให้ใช้คำสั่งต่อไปนี้

p {
    width: calc-size(fit-content, round(up, size, 50px));
    height: calc-size(auto, round(up, size, 50px));
}

นอกจากนี้ calc-size() ยังช่วยให้คุณหาค่าประมาณของ calc-size() 2 รายการได้เมื่อฐานขนาดการคํานวณของทั้ง 2 รายการเหมือนกัน การดำเนินการนี้ยังทำไม่ได้ใน interpolate-size

#element {
    width: min-content; /* 👈 */
    transition: width 0.35s ease;

    &:hover {
        width: calc-size(min-content, size + 10px); /* 👈 */
    }
}

เหตุใดจึงไม่อนุญาตให้ใช้ <intrinsic-size-keyword> ใน calc()

คำถามที่มักเกิดขึ้นกับ calc-size() คือเหตุใดกลุ่มผู้เชี่ยวชาญ CSS จึงไม่ปรับฟังก์ชัน calc() ให้รองรับคีย์เวิร์ดการปรับขนาดตามค่าเริ่มต้น

สาเหตุหนึ่งคือคุณไม่ได้รับอนุญาตให้ผสมคีย์เวิร์ดการปรับขนาดตามข้อมูลที่มีอยู่เมื่อทำการคำนวณ เช่น คุณอาจอยากเขียน calc(max-content - min-content) ซึ่งดูเหมือนว่าถูกต้อง แต่จริงๆ แล้วไม่ถูกต้อง calc-size() บังคับใช้ความถูกต้องเนื่องจากยอมรับเฉพาะ <intrinsic-size-keyword> รายการเดียวเป็นอาร์กิวเมนต์แรก ต่างจาก calc()

อีกเหตุผลหนึ่งคือความสามารถในการรับรู้บริบท อัลกอริทึมเลย์เอาต์บางรายการมีลักษณะการทํางานพิเศษสําหรับคีย์เวิร์ดการปรับขนาดตามบริบทที่เฉพาะเจาะจง calc-size() ได้รับการกําหนดไว้อย่างชัดเจนเพื่อแสดงขนาดที่แท้จริง ไม่ใช่ <length> ด้วยเหตุนี้ อัลกอริทึมเหล่านั้นจึงสามารถถือว่า calc-size(<intrinsic-size-keyword>, …) เป็น <intrinsic-size-keyword> ได้ เพื่อคงลักษณะการทำงานพิเศษของคีย์เวิร์ดนั้นไว้

แนวทางใดที่ควรใช้

ในกรณีส่วนใหญ่ ให้ประกาศ interpolate-size: allow-keywords ใน :root นี่เป็นวิธีที่ง่ายที่สุดในการเปิดใช้ภาพเคลื่อนไหวจากคีย์เวิร์ดการปรับขนาดตามเนื้อหาและกลับไปยังคีย์เวิร์ดดังกล่าว เนื่องจากเป็นคำสั่งแบบบรรทัดเดียว

/* Opt-in the whole page to animating to/from intrinsic sizing keywords */
:root {
    interpolate-size: allow-keywords; /* 👈 */
}

โค้ดนี้เป็นการเพิ่มประสิทธิภาพแบบเป็นขั้นเป็นตอนที่ดี เนื่องจากเบราว์เซอร์ที่ไม่รองรับจะเปลี่ยนไปใช้แบบไม่มีทรานซิชัน

เมื่อคุณต้องการควบคุมสิ่งต่างๆ อย่างละเอียดยิ่งขึ้น เช่น การทำการคำนวณ หรือต้องการใช้ลักษณะการทำงานที่ calc-size() ทำได้เท่านั้น คุณก็ใช้ calc-size() ได้

#specific-element {
    width: 50px;

    &:hover {
        width: calc-size(fit-content, size + 1em); /* 👈 Only calc-size() can do this */
    }
}

อย่างไรก็ตาม การใช้ calc-size() ในโค้ดจะทำให้คุณต้องใส่ทางเลือกสำรองสำหรับเบราว์เซอร์ที่ไม่รองรับ calc-size() เช่น การเพิ่มการประกาศขนาดเพิ่มเติม หรือกลับไปใช้การตรวจหาองค์ประกอบโดยใช้ @supports

width: fit-content;
width: calc-size(fit-content, size + 1em);
       /* 👆 Browsers with no calc-size() support will ignore this second declaration,
             and therefore fall back to the one on the line before it. */

ตัวอย่างเพิ่มเติม

ลองดูตัวอย่างการใช้งาน interpolate-size: allow-keywords เพิ่มเติมที่เป็นประโยชน์

การแจ้งเตือน

เดโมต่อไปนี้เป็นเวอร์ชันแยกมาจากเดโม @starting-style นี้ เราได้ปรับโค้ดเพื่อให้เพิ่มรายการที่มีความสูงแตกต่างกันได้

โดยทั้งหน้าจะเลือกใช้การประมาณขนาดคีย์เวิร์ด และตั้งค่า height ในเอลิเมนต์ .item แต่ละรายการเป็น auto มิฉะนั้น โค้ดจะเหมือนกับก่อนแยกออกมาทุกประการ

:root {
    interpolate-size: allow-keywords; /* 👈 */
}

.item {
    height: auto; /* 👈 */

    @starting-style {
        height: 0px;
    }
}

สร้างภาพเคลื่อนไหวขององค์ประกอบ <details>

Use Case ทั่วไปที่คุณต้องการใช้การอินเตอร์โพเลชันประเภทนี้คือการสร้างภาพเคลื่อนไหววิดเจ็ตการเปิดเผยหรือกล่องแอคคอร์เดียนเฉพาะขณะเปิด ใน HTML คุณใช้องค์ประกอบ <details>

interpolate-size: allow-keywords ช่วยให้คุณทำสิ่งต่อไปนี้ได้

@supports (interpolate-size: allow-keywords) {
    :root {
        interpolate-size: allow-keywords;
    }
    
    details {
        transition: height 0.5s ease;
        height: 2.5rem;
        
        &[open] {
            height: auto;
            overflow: clip; /* Clip off contents while animating */
        }
    }
}

แต่อย่างที่เห็น ภาพเคลื่อนไหวจะทำงานก็ต่อเมื่อวิดเจ็ตการเปิดเผยข้อมูลเปิดอยู่เท่านั้น Chrome กำลังพัฒนาแอตทริบิวต์ ::details-content จำลองเพื่อรองรับกรณีนี้ ซึ่งจะพร้อมใช้งานใน Chrome ภายในปีนี้ (และจะกล่าวถึงในโพสต์ในอนาคต) เมื่อใช้ interpolate-size: allow-keywords และ ::details-content ร่วมกัน คุณจะได้ภาพเคลื่อนไหวทั้ง 2 ทิศทางดังนี้