CSS 状态检测革命:样式查询与滚动状态查询实战指南

CSS 状态检测革命:样式查询与滚动状态查询实战指南

CSS 状态检测革命:样式查询与滚动状态查询实战指南

2026/4/3css

在 Web 开发中,我们一直依赖 JavaScript 来检测和响应 UI 状态变化。但随着 CSS 的演进,现在我们有了原生解决方案:样式查询滚动状态查询。这两个特性让纯 CSS 状态检测成为现实,彻底改变了我们构建响应式 UI 的方式。

样式查询:基于 CSS 属性值的状态检测

它解决了什么问题?

传统上,当我们需要根据组件内部状态改变样式时,必须使用 JavaScript:

// 传统 JavaScript 方案
if (element.hasAttribute('data-active')) {
  element.classList.add('active-style');
}

这导致样式逻辑分散在 CSS 和 JavaScript 中,维护困难且性能不佳。样式查询的出现,让状态检测和样式响应统一在 CSS 中。

核心语法与用法

样式查询通过 @container style()检测 CSS 自定义属性的值变化:

/* 1. 定义状态变量 */
.alert {
  --severity: info;  /* 状态变量:info, warning, error */
  container-type: normal;  /* 必需:声明为容器 */
}

/* 2. 查询状态并响应 */
@container style(--severity: warning) {
  .alert {
    border-color: #ff9800;
    background: #fff3e0;
  }
  /* 可以修改任意样式 */
  .alert-icon::before { content: "⚠️"; }
}

@container style(--severity: error) {
  .alert {
    border-color: #f44336;
    background: #ffebee;
  }
  .alert-icon::before { content: "❌"; }
}

实战:主题切换系统

/* 定义主题变量 */
.theme-provider {
  --theme: light;
  --primary-color: #2196f3;
  container-type: normal;
}

/* 暗色主题 */
@container style(--theme: dark) {
  .theme-provider {
    --primary-color: #90caf9;
    background: #121212;
    color: #ffffff;
  }
  
  .card {
    background: #1e1e1e;
    border: 1px solid #333;
  }
}

/* 高对比度主题 */
@container style(--theme: high-contrast) {
  .theme-provider {
    --primary-color: #ffff00;
    background: #000000;
    color: #ffffff;
  }
  
  .card {
    border: 3px solid yellow;
  }
}

/* 应用主题色 */
.button {
  background: var(--primary-color);
  color: white;
}

组合多个状态查询

.dialog {
  --state: closed; /* closed, open, minimized */
  --priority: normal; /* normal, important */
  container-type: normal;
}

/* 打开的重要对话框 */
@container style(--state: open) and style(--priority: important) {
  .dialog {
    box-shadow: 0 0 0 3px #f44336;
    z-index: 9999;
  }
  
  .dialog::after {
    content: "重要!";
    color: #f44336;
  }
}

/* 最小化的对话框 */
@container style(--state: minimized) {
  .dialog {
    width: 60px;
    height: 60px;
    overflow: hidden;
  }
  
  .dialog-content { display: none; }
}

动态改变状态

<!-- HTML -->
<button onclick="toggleSeverity()">切换状态</button>
<div class="alert" id="myAlert">这是一条消息</div>

<script>
function toggleSeverity() {
  const alert = document.getElementById('myAlert');
  const current = alert.style.getPropertyValue('--severity') || 'info';
  const next = current === 'info' ? 'warning' : 
               current === 'warning' ? 'error' : 'info';
  alert.style.setProperty('--severity', next);
}
</script>

滚动状态查询:专门检测滚动和粘滞状态

它解决了什么问题?

检测滚动状态(如粘性导航是否粘住)一直是前端难题:

// 传统的 JavaScript 方案
window.addEventListener('scroll', () => {
  const rect = element.getBoundingClientRect();
  if (rect.top <= 0) {
    element.classList.add('sticky');
  } else {
    element.classList.remove('sticky');
  }
});

这种方法有性能问题(频繁触发滚动事件)和时序问题(可能不同步)。滚动状态查询让浏览器原生处理这些检测。

核心语法与用法

/* 1. 声明滚动状态容器 */
.sticky-header {
  position: sticky;
  top: 0;
  container-type: scroll-state;  /* 关键:启用滚动状态查询 */
}

/* 2. 检测粘滞状态 */
@container scroll-state(stuck: top) {
  .sticky-header {
    /* 粘在顶部时的样式 */
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(10px);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  }
  
  /* 可以添加状态指示器 */
  .sticky-header::after {
    content: "已固定";
    color: #666;
  }
}

/* 3. 检测未粘滞状态 */
@container scroll-state(stuck: none) {
  .sticky-header {
    background: transparent;
    box-shadow: none;
  }
}

实战:智能粘性侧边栏

.sidebar {
  position: sticky;
  top: 20px;
  container-type: scroll-state;
  height: fit-content;
  transition: all 0.3s ease;
}

/* 粘在顶部 */
@container scroll-state(stuck: top) {
  .sidebar {
    top: 0;
    padding-top: 20px;
    max-height: 100vh;
    overflow-y: auto;
  }
  
  /* 添加返回顶部按钮 */
  .sidebar::before {
    content: "回到顶部";
    display: block;
    padding: 10px;
    background: #f5f5f5;
    cursor: pointer;
  }
}

/* 粘在底部 */
@container scroll-state(stuck: bottom) {
  .sidebar {
    box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
  }
}

/* 接近边界时提示 */
@container scroll-state(stuck-proximity: top < 50px) {
  .sidebar {
    border-top: 2px solid #ff9800;
  }
  
  .sidebar::after {
    content: "接近顶部";
    color: #ff9800;
  }
}

检测滚动方向和位置

.scroll-aware-element {
  container-type: scroll-state;
  position: sticky;
  top: 0;
  transition: transform 0.3s ease;
}

/* 向上滚动时显示 */
@container scroll-state(scrolling: up) {
  .scroll-aware-element {
    transform: translateY(0);
    opacity: 1;
  }
}

/* 向下滚动时隐藏 */
@container scroll-state(scrolling: down) {
  .scroll-aware-element {
    transform: translateY(-100%);
    opacity: 0;
  }
}

/* 检测在视口中的可见比例 */
@container scroll-state(visibility: 0% to 30%) {
  .scroll-aware-element {
    opacity: 0.3;
  }
}

@container scroll-state(visibility: 30% to 70%) {
  .scroll-aware-element {
    opacity: 0.7;
  }
}

@container scroll-state(visibility: 70% to 100%) {
  .scroll-aware-element {
    opacity: 1;
  }
}

实战:阅读进度指示器

.progress-tracker {
  container-type: scroll-state;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: #e0e0e0;
  z-index: 1000;
}

/* 根据滚动进度改变颜色 */
@container scroll-state(visibility: 0% to 25%) {
  .progress-tracker::before {
    content: "";
    display: block;
    height: 100%;
    width: var(--scroll-progress);
    background: #4caf50; /* 绿色:开始 */
  }
}

@container scroll-state(visibility: 25% to 75%) {
  .progress-tracker::before {
    background: #2196f3; /* 蓝色:中间 */
  }
}

@container scroll-state(visibility: 75% to 100%) {
  .progress-tracker::before {
    background: #f44336; /* 红色:接近完成 */
  }
}

/* 接近底部时提示 */
@container scroll-state(stuck-proximity: bottom < 100px) {
  .progress-tracker::after {
    content: "接近底部";
    position: absolute;
    right: 20px;
    top: 10px;
    background: #333;
    color: white;
    padding: 5px 10px;
    border-radius: 4px;
  }
}

组合使用:样式查询 + 滚动状态查询

真正的强大之处在于组合使用这两种技术:

.smart-navbar {
  --variant: normal; /* normal, transparent, solid */
  position: sticky;
  top: 0;
  container-type: scroll-state style;
}

/* 透明变体 + 粘滞状态 */
@container scroll-state(stuck: top) and style(--variant: transparent) {
  .smart-navbar {
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(10px);
  }
  
  /* 滚动时改变链接颜色 */
  .nav-link { color: #333; }
}

/* 实心变体 + 向上滚动 */
@container scroll-state(scrolling: up) and style(--variant: solid) {
  .smart-navbar {
    transform: translateY(0);
    box-shadow: 0 2px 20px rgba(0,0,0,0.1);
  }
}

/* 实心变体 + 向下滚动 */
@container scroll-state(scrolling: down) and style(--variant: solid) {
  .smart-navbar {
    transform: translateY(-100%);
  }
}

浏览器支持与渐进增强

当前浏览器支持情况:

  • 样式查询:Chrome 111+,Edge 111+,其他浏览器跟进中
  • 滚动状态查询:Chrome 133+,Edge 133+,最新特性

渐进增强策略

/* 1. 基础样式(所有浏览器) */
.sticky-header {
  position: sticky;
  top: 0;
  background: white;
}

/* 2. 检测滚动状态支持 */
@supports (container-type: scroll-state) {
  .sticky-header {
    container-type: scroll-state;
  }
  
  @container scroll-state(stuck: top) {
    .sticky-header {
      /* 现代浏览器的增强样式 */
      backdrop-filter: blur(10px);
    }
  }
}

/* 3. 回退方案(旧浏览器) */
.sticky-header.stuck {
  /* 通过 JavaScript 添加的类 */
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

/* 4. 检测样式查询支持 */
@supports (container-type: style) {
  .component {
    container-type: style;
  }
}

总结:为什么这是 CSS 的革命?

样式查询的核心价值:

  1. 状态与样式统一:状态逻辑不再分散在 JavaScript 和 CSS 中
  2. 性能优化:浏览器原生优化状态检测,避免 JavaScript 性能开销
  3. 维护性提升:组件状态自包含,易于理解和调试

滚动状态查询的核心价值:

  1. 滚动性能革命:浏览器原生处理滚动检测,60fps 保证
  2. 开发体验简化:告别复杂的 IntersectionObserver 和滚动事件监听
  3. 时序问题解决:状态检测与渲染同步,避免视觉闪烁

最佳实践建议:

  1. 语义化状态名:使用 --state-前缀,如 --state-active--state-visible
  2. 渐进增强:始终为不支持新特性的浏览器提供回退
  3. 组合使用:样式查询定义业务状态,滚动状态查询处理滚动行为
  4. 性能优化:避免在状态查询中做昂贵操作,保持简单

这两种技术代表了 CSS 从样式描述语言状态响应系统的转变。通过掌握它们,你可以创建更高效、更优雅的 Web 界面,同时减少对 JavaScript 的依赖。

现在就开始尝试:从简单的粘性头部或主题切换开始,体验纯 CSS 状态检测的强大能力。这不仅是技术的进步,更是开发范式的转变。

评论