scroll-state() ของ CSS

เหมือนกับการค้นหาคอนเทนเนอร์ แต่สําหรับการค้นหาที่ค้างอยู่ หยุดชะงัก และล้น

เผยแพร่: 15 ม.ค. 2025

Chrome 133 พัฒนาจากการค้นหาคอนเทนเนอร์ด้วยการแสดงการค้นหาคอนเทนเนอร์สถานะการเลื่อน ตอนนี้คุณสามารถค้นหาและปรับสถานะที่จัดการโดยเบราว์เซอร์สำหรับตำแหน่งที่ยึด ตำแหน่งที่เลื่อนไปหยุดเอง และองค์ประกอบที่เลื่อนได้จาก CSS แล้ว

ภาพรวม

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

ภาพรวมของการค้นหาสถานะที่พร้อมใช้งานใน Chrome 133 มีดังนี้

สถานะค้าง
ทริกเกอร์การเปลี่ยนแปลงสไตล์เมื่อองค์ประกอบติดอยู่ที่ขอบ
สถานะรวม:
รูปแบบทริกเกอร์จะเปลี่ยนเมื่อองค์ประกอบมีการปักหมุดบนแกน
สถานะเลื่อนได้
ทริกเกอร์การเปลี่ยนแปลงรูปแบบเมื่อองค์ประกอบแสดงเกินขอบ

ข่าวดีคือทุกสิ่งที่คุณได้เรียนรู้จากคําค้นหาคอนเทนเนอร์จะช่วยคุณทํางานกับคําค้นหาสถานะการเลื่อน

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

(ซ้าย) ภาพเคลื่อนไหวที่ทริกเกอร์โดย scroll-state() (ขวา) ภาพเคลื่อนไหวที่ทำงานตามการเลื่อน
https://codepen.io/web-dot-dev/pen/emOrBaV

การค้นหาสถานะการเลื่อนครั้งแรก

ขั้นตอนแรกคือกําหนดคอนเทนเนอร์โดยใช้ค่าใหม่สําหรับพร็อพเพอร์ตี้ container-type เช่นเดียวกับการค้นหาคอนเทนเนอร์ องค์ประกอบที่คุณต้องการค้นหาคือองค์ประกอบที่คุณให้ container-type และ container-name (ไม่บังคับ) เมื่อใช้การค้นหาสถานะการเลื่อน คุณจะระบุcontainer-type: scroll-stateให้กับองค์ประกอบที่ยึด ติด หรือมีการแสดงผลเกิน

.stuck-top {
  container-type: scroll-state;
  position: sticky;
  top: 0px;
}

ขั้นตอนที่ 2 คือเลือกรายการย่อยของคอนเทนเนอร์ที่จะตอบสนองต่อสถานะ เช่นเดียวกับการค้นหาคอนเทนเนอร์ รายการนี้ต้องไม่ใช่องค์ประกอบเดียวกันที่มี container-type

.stuck-top {
  container-type: scroll-state;
  position: sticky;
  top: 0px;

  > nav {
    @container scroll-state(stuck: top) {
      background: Highlight;
      color: HighlightText;
    }
  }
}

ขั้นตอนที่ 3 คือลองใช้ ตัวอย่าง CSS ต่อไปนี้จะจัดรูปแบบพื้นหลังเป็นสีแดงเมื่อองค์ประกอบ .stuck-top ติดอยู่ที่ด้านบนที่ 0 การเพิ่มบรรทัด CSS 2-3 บรรทัดที่เราควรจะเขียนไว้แล้วและองค์ประกอบที่มีเพิ่มเติมซึ่งทำหน้าที่เป็นพร็อกซีสถานะเบราว์เซอร์ ทําให้คอมโพเนนต์ของเราฉลาดขึ้นมากเกี่ยวกับสภาพแวดล้อมรอบตัว

https://codepen.io/web-dot-dev/pen/ByBxpwR

การเพิ่มประสิทธิภาพแบบต่อเนื่อง

@supports at-rule และการฝังช่วยให้คุณเพิ่มการเพิ่มประสิทธิภาพแบบเป็นขั้นเป็นตอนหรือการใช้ฟีเจอร์แบบมีเงื่อนไขได้โดยใช้โค้ดเพียง 2-3 บรรทัด ดังนี้

.stuck-top {
  container-type: scroll-state;
  position: sticky;
  top: 0px;

  @supports (container-type: scroll-state) {
    > nav {
      @container scroll-state(stuck: top) {
        background: Highlight;
        color: HighlightText;
      }
    }
  }
}

นอกจากนี้ อย่าลืมใช้ @media (prefers-reduced-motion: no-preference) {} กับการเคลื่อนไหวด้วย หากคุณทำให้องค์ประกอบในหน้าเว็บเคลื่อนไหวด้วยการค้นหาสถานะการเลื่อน

กรณีการใช้งาน

ติดค้าง

เราควรตั้งชื่อส่วนนี้ว่า "สถานการณ์ที่แก้ไขยาก" ไหม นี่เป็นคอลเล็กชันเล็กๆ ของกรณีการใช้งานสถานะที่ติดหนึบ รวมถึงส่วนเสริมของไอเดียที่ต้องสร้าง

@container scroll-state(stuck: top) {}
@container scroll-state(stuck: bottom) {}

รายการไวยากรณ์แบบเต็ม

เพิ่มเงาเมื่อติดอยู่

Use Case ที่พบบ่อยที่สุดอย่างหนึ่งสำหรับคำค้นหาที่ค้างคือแถบนําทางที่ต้องการเพิ่ม box-shadow เมื่อค้าง เพื่อให้ดูเหมือนว่าลอยอยู่เหนือเนื้อหาที่วางซ้อน

https://codepen.io/web-dot-dev/pen/GgKdryj
.stuck-top {
  container-type: scroll-state;
  position: sticky;
  top: 0px;

  > nav {
    transition: box-shadow .3s ease;

    @container scroll-state(stuck: top) {
      box-shadow: var(--shadow-5);
    }
  }
}

เปิดใช้งานส่วนหัวที่ค้างอยู่ในปัจจุบัน

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

https://codepen.io/web-dot-dev/pen/pvzVRaK
.sticky-slide {
  dt {
    container-type: scroll-state;
    position: sticky;
    inset-block-start: 0;
    inset-inline: 0;

    > header {
      transition: 
        background .3s ease,
        box-shadow .5s ease;

      @container scroll-state(stuck: top) {
        background: hsl(265 100% 27%);
        box-shadow: 0 5px 5px #0003;
      }
    }
  }
}

นี่เป็นรูปแบบอื่นที่ส่วนหัวอยู่ด้านข้างรายการในลิสต์ เป็นไปได้หลายอย่าง

https://codepen.io/web-dot-dev/pen/azoGpGg

ไอเดียที่แสดงเกิน

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

รวมรูปถ่าย

การใช้การค้นหาสถานะแบบยึดตำแหน่งช่วยให้เรานำภาระหน้าที่บางอย่างออกจาก JavaScript และ Snap Events และย้ายการจัดการไปยัง CSS ได้

@container scroll-state(snapped: x) {}
@container scroll-state(snapped: y) {}
@container scroll-state(snapped: inline) {}
@container scroll-state(snapped: block) {}

รายการไวยากรณ์แบบเต็ม

โปรดทราบว่าในกรณีที่คุณข้ามส่วนการค้นหาสถานะการเลื่อนครั้งแรก คอนเทนเนอร์สําหรับการค้นหาแบบ Snap คือองค์ประกอบที่มี scroll-snap-align และองค์ประกอบที่ปรับได้ต้องเป็นองค์ประกอบย่อยขององค์ประกอบนั้น ซึ่งหมายความว่าคุณจะต้องมีองค์ประกอบ 3 อย่างในการตั้งค่านี้ ได้แก่

a scroll container with `scroll-snap-type`
⤷ a snap target with both `scroll-snap-align` and `container-type: scroll-state`
    ⤷ a child of the snap target that can query the container for snap state

เพิ่มขนาดของรายการที่จับภาพ

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

https://codepen.io/web-dot-dev/pen/NPKMdBX
.demo {
  overflow: auto hidden;
  scroll-snap-type: x mandatory;

  > article {
    container-type: scroll-state;
    scroll-snap-align: center;

    @supports (container-type: scroll-state) {
      > * {
        transition: opacity .5s ease;

        @container not scroll-state(snapped: x) {
          opacity: .25;
        }
      }
    }
  }
}

แสดงคำบรรยายสำหรับรายการที่จับภาพ

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

https://codepen.io/web-dot-dev/pen/XJrqpBG
.demo {
  overflow-x: auto;
  scroll-behavior-x: contain;
  scroll-snap-type: x mandatory;

  > .card {
    container-type: scroll-state;
    scroll-snap-align: center;

    @supports (container-type: scroll-state) {
      @media (prefers-reduced-motion: no-preference) {
        figcaption {
          transform: translateY(100%);

          @container scroll-state(snapped: x) {
            transform: translateY(0);
          }
        }
      }
    }
  }
}

การทำองค์ประกอบในสไลด์เคลื่อนไหว

การใช้ภาพเคลื่อนไหวกับองค์ประกอบของภาพสไลด์หรืองานนำเสนอขณะบรรยายนั้นเป็นเรื่องปกติ ก่อนหน้านี้การเขียน IntersectionObserver สำหรับการดำเนินการนี้ค่อนข้างน่ารำคาญ เนื่องจากสิ่งที่ทำได้มีเพียงการตั้งค่าคลาสในสไลด์ ตอนนี้เราไม่จำเป็นต้องใช้ JavaScript เลย

https://codepen.io/web-dot-dev/pen/dPbeNqY
html {
  scroll-snap-type: y mandatory;
}

section {
  container-type: scroll-state;
  scroll-snap-align: start;
  scroll-snap-stop: always;

  @supports (container-type: scroll-state) {
    @media (prefers-reduced-motion: no-preference) {
      > h1 {
        transition: opacity .5s ease, transform .5s var(--ease-spring-3);
        transition-delay: .5s;
        opacity: 0;
        transform: scale(1.25);

        @container scroll-state(snapped: block) {
          opacity: 1;
          transform: scale(1);
        }
      }
    }
  }
}

คุณอาจสังเกตเห็นว่าการค้นหาสถานะ CSS ที่จับภาพไว้ทั้งหมดทํางานเหมือน scrollsnapchanging แทนที่จะเป็น scrollsnapchange ซึ่งจะช่วยให้คุณมีจุดเริ่มต้นที่เร็วที่สุดในการให้ฟีดแบ็กภาพเกี่ยวกับองค์ประกอบที่ปักหมุดไว้ หากการเรียกใช้เกิดขึ้นเร็วเกินไป ให้ลองใช้เหตุการณ์ JavaScript

เลื่อนได้

การค้นหาสถานะ "เลื่อนได้" จะมีประโยชน์อย่างมากในการแสดงสิ่งต่างๆ ที่มองเห็นได้เมื่อพื้นที่เลื่อนสามารถเลื่อนได้จริง ก่อนหน้านี้ ข้อมูลนี้ถือเป็นข้อมูลที่ทราบได้ยาก

@container scroll-state(scrollable: top) {}
@container scroll-state(scrollable: right) {}
@container scroll-state(scrollable: bottom) {}
@container scroll-state(scrollable: left) {}

รายการไวยากรณ์แบบเต็ม

ระบุการเลื่อนด้วยเงา

มีเคล็ดลับ CSS โดย Lea Verou ที่โด่งดังซึ่งใช้ background-attachment: local เพื่อให้ได้เอฟเฟกต์ที่คล้ายกับนี้ รวมถึงวิธีทำด้วยภาพเคลื่อนไหวที่ทำงานตามการเลื่อน เทคนิคแต่ละอย่างมีข้อดีข้อเสียต่างกันไป เราจึงต้องหาว่าเทคนิคแต่ละอย่างเหมาะกับสถานการณ์ใดและเมื่อใด

ตัวอย่างต่อไปนี้ใช้องค์ประกอบที่ติดอยู่รายการเดียวที่ครอบคลุมพื้นที่การเลื่อน ไล่ระดับสีที่ด้านบนและไล่ระดับสีที่ด้านล่างมีการแสดงผลระดับทึบเป็นภาพเคลื่อนไหวด้วย @property เมื่อการค้นหาสถานะการเลื่อนตามบริบทมีผล: @container scroll-state(scrollable: top)

และโปรดทราบว่านี่เป็นคอนเทนเนอร์แรกที่เป็นทั้งคอนเทนเนอร์ size และ scroll-state

https://codepen.io/web-dot-dev/pen/OPLZWBj
.scroll-container {
  container-type: scroll-state size;
  overflow: auto;

  &::after {
    content: " ";

    background: var(--_shadow-top), var(--_shadow-bottom);
    transition: 
      --_scroll-shadow-color-1-opacity .5s ease,
      --_scroll-shadow-color-2-opacity .5s ease;

    @container scroll-state(scrollable: top) {
      --_scroll-shadow-color-1-opacity: var(--_shadow-color-opacity, 25%);
    }

    @container scroll-state(scrollable: bottom) {
      --_scroll-shadow-color-2-opacity: var(--_shadow-color-opacity, 25%);
    }
  }
}

พรอมต์ลูกศร

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

https://codepen.io/web-dot-dev/pen/OPLZWBj
@container scroll-state((scrollable: top) or (not (scrollable: bottom))) {
  translate: 0 calc(100% + 10px);
}

@container scroll-state((scrollable: top) and (not (scrollable: bottom))) {
  translate: 0 calc(100% + 10px);
  rotate: .5turn;
}

กลับไปด้านบน

การโต้ตอบกับสถานะการเลื่อนอีกอย่างหนึ่งที่ได้รับความนิยมคือปุ่ม "เลื่อนขึ้นด้านบน" โค้ดต่อไปนี้จะทำให้ปุ่มเลื่อนขึ้นด้านบนหายไปเมื่อไม่มีที่เลื่อนขึ้น

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

https://codepen.io/web-dot-dev/pen/OPLZWBj
@container not scroll-state(scrollable: top) {
  translate: 0 calc(100% + 10px);
}

การศึกษาต่อเนื่อง

หากต้องการข้อมูลเพิ่มเติม โปรดดูแหล่งข้อมูลต่อไปนี้ซึ่งมีตั้งแต่รายละเอียดข้อกำหนดทางเทคนิคไปจนถึงบทความอื่นๆ ที่ยอดเยี่ยมซึ่งครอบคลุมหัวข้อนี้