CSS scroll-state()

与容器查询类似,但适用于卡住、固定和溢出查询。

发布时间:2025 年 1 月 15 日

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

第二步是选择将响应状态的容器子元素,与容器查询一样,此元素不能是包含 container-type 的元素。

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

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

第三步是试用。以下 CSS 示例会在 .stuck-top 元素在 0 处固定到顶部时将背景样式设置为红色。只需在我们已经编写的 CSS 中添加几行代码,并添加一个用于代理浏览器状态的额外容器元素,我们的组件就能更智能地处理周围环境。

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

渐进增强

借助 @supports at 规则和嵌套,您只需额外添加几行代码,即可添加渐进式增强或条件功能使用:

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

完整语法列表

在卡住时添加阴影

卡住的查询的一个最常见用例是,导航栏希望在卡住时添加 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);
    }
  }
}

激活当前卡住的标题

另一种常见的粘性界面反馈场景是突出显示当前卡住的元素。在按字母顺序排列的乐队列表中,这非常有用,有助于提升用户体验。

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 和固定事件中移除一些责任,并将处理工作移至 CSS。

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

完整语法列表

温馨提示:如果您跳过了首次滚动状态查询部分,请注意,用于快捷查询的容器是包含 scroll-snap-align 的元素,并且可自适应的元素必须是该元素的子元素。这意味着,您需要设置以下三个元素:

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

在幻灯片元素中添加动画效果

在演讲时为幻灯片或演示文稿中的元素添加动画效果非常常见。以前,为此编写交叉观察器非常麻烦,因为它只会在幻灯片上设置一个类。现在,我们不需要任何 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) {}

完整语法列表

使用阴影指示滚动

Lea Verou 的 CSS 技巧中有一个著名的示例,使用 background-attachment: local 实现了类似的效果,还有一个示例使用滚动驱动型动画实现了类似的效果。每种方法都有利弊,我们需要探索每种方法最适合在何时何地使用。

以下示例使用一个跨越滚动边界的固定元素。当上下两侧的渐变应用其上下文滚动状态查询 @container scroll-state(scrollable: top) 时,其不透明度会使用 @property 进行动画处理。

另请注意,这是第一个同时是 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);
}

继续学习

如果您想了解更多信息,请参阅以下资源,其中包括规范详情以及其他介绍此主题的优秀文章: