CSS scroll-state()

Like container queries; but for stuck, snapped, and overflowing queries.

Chrome 133 မှာ scroll state container queries ကိုစပြီးတော့ မိတ်ဆက်လာတယ် sticky positioning, scroll snap points, scrollable elements ဒီလို state တွေကို CSS ကနေ query လုပ်လို့ ရသွားပါပြီ

Overview

scroll state queries တွေမရှိခင်ကဆိုရင် အပေါ်မှာပြောခဲ့တဲ့ state တွေ ဥပမာ element တစ်ခုသည် sticky ဖြစ်နေသလား၊ scroll area ထဲမှာရှိသေးလား မရှိတော့ဘူးလား၊ overflow ဖြစ်ပြီး scroll လုပ်လို့ရနေတာလား ဆိုတာတွေကို စစ်ဖို့ JavaScript ကနေပဲ လုပ်ရတယ်၊ အခုကျ JavaScript မလိုတော့ဘဲ CSS နဲ့တင် အဆင်ပြေသွားတယ်ပေါ့ scroll state queries တွေအကြောင်းပြောချင်ရင် container queries တွေကိုတော့အရင်ဖတ်ထားဖို့လိုပါတယ်

အဓိကကတော့ scroll state queries သုံးမျိုးရှိမယ်

Stuck state

သူကတော့ element တစ်ခုက အစွန်ဆုံးတစ်ဖက်မှာ stuck ဖြစ်နေတဲ့ အခြေနေ ဆိုလိုတာက sticky ဖြစ်နေတဲ့အချိန်ကို စစ်ဖို့ပါ

Snapped state

သူကတော့ element တစ်ခုက အစွန်တစ်ဘက်ဘက်ကိုဝင်သွားရင် ဆိုလိုတာက hidden ဖြစ်သွားတဲ့ အခြေနေကို စစ်ဖို့ပါ

Scrollable state

သူကတော့ element သည် scrollable ဖြစ်နေလား မဖြစ်နေသလား ဆိုလိုတာက overflow:scroll ဖြစ်နေတဲ့အခြေနေဟုတ်မဟုတ်ကို စစ်ဖို့ဖြစ်ပါတယ်

scroll driven animations နဲ့ scroll state queries တွေကိုသုံးပြီး ဖန်တီးတဲ့ animations တွေနဲ့က ကွာခြားမှုရှိပါတယ်၊ အဓိကက timing နဲ့ context ကွာပါလိမ့်မယ်၊ scroll state queries တွေက scroll driven animations တွေထက်ပိုပြီးတော့ control လုပ်ခွင့်ပေးနိုင်တဲ့သဘောရှိပါတယ်

အောက်မှာ နမူနာကြည့်လို့ရပါတယ်

(left) scroll-state() triggered animation, (right) scroll-driven animation

Scroll-state query ဘယ်လိုရေးရသလဲ

Scroll-state query ဆိုတာ ပြောရရင် container query တစ်ခုထပ်တိုးတဲ့သဘောပဲ container type ထဲမှာ နောက်တစ်မျိုးတိုးလာတာပေါ့

.stuck-top {
  container-type: scroll-state; /* container ကို scroll-state အမျိုးစားသတ်မှတ်မယ် */
  position: sticky;
  top: 0px;

  > nav {
    /* query အမျိုးအစားပေါ်မူတည်ပြီး style တွေပြောင်းမယ် */
    @container scroll-state(stuck: top) {
      background: Highlight;
      color: HighlightText;
    }
  }
}

ပိုကောင်းတာကတော့ browser တိုင်းမှာ မရသေးတာဖြစ်လို့ @support နဲ့စစ်ပေးထားသင့်တယ်

.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;
      }
    }
  }
}

Use Cases

Add a shadow when stuck

.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);
    }
  }
}

Activate the current stuck header

.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;
      }
    }
  }
}

Visually boost the snapped item

.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;
        }
      }
    }
  }
}

Show the caption for the snapped item

.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);
          }
        }
      }
    }
  }
}

Animating in slide elements

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);
        }
      }
    }
  }
}

Indicate scroll with shadow

.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%);
    }
  }
}

Arrow prompt

@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;
}

Return to top

@container not scroll-state(scrollable: top) {
  translate: 0 calc(100% + 10px);
}

Reference:https://developer.chrome.com/blog/css-scroll-state-queries

Last updated