CSS2024-10-14
返回首页

CSS Anchor Positioning 实战

CSS Anchor Positioning 实战

CSS Anchor Positioning API 让元素可以相对于其他元素定位,不再需要 JavaScript 计算位置。

基础概念

/* 定义锚点 */
.anchor {
  anchor-name: --my-anchor;
}

/* 相对于锚点定位 */
.tooltip {
  position: absolute;
  position-anchor: --my-anchor;
  top: anchor(bottom);
  left: anchor(center);
}

实际案例:Tooltip

<button class="btn">
  Hover me
  <span class="tooltip">Tooltip content</span>
</button>
.btn {
  position: relative;
  anchor-name: --btn-anchor;
}

.tooltip {
  position: absolute;
  position-anchor: --btn-anchor;
  
  /* 定位在锚点下方 */
  top: anchor(bottom);
  left: anchor(center);
  transform: translateX(-50%);
  
  /* 间距 */
  margin-top: 8px;
  
  /* 样式 */
  background: #333;
  color: white;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  
  /* 默认隐藏 */
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
}

.btn:hover .tooltip {
  opacity: 1;
}

下拉菜单

<div class="dropdown">
  <button class="dropdown-trigger">
    Menu
  </button>
  <div class="dropdown-menu">
    <a href="#">Option 1</a>
    <a href="#">Option 2</a>
    <a href="#">Option 3</a>
  </div>
</div>
.dropdown-trigger {
  anchor-name: --dropdown-anchor;
}

.dropdown-menu {
  position: absolute;
  position-anchor: --dropdown-anchor;
  
  top: anchor(bottom);
  left: anchor(left);
  
  margin-top: 4px;
  
  background: white;
  border: 1px solid #ddd;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
  
  /* 默认隐藏 */
  display: none;
}

.dropdown:focus-within .dropdown-menu {
  display: block;
}

锚点定位函数

anchor() 函数支持多种值:

.positioned {
  /* 相对于锚点的边 */
  top: anchor(top);
  right: anchor(right);
  bottom: anchor(bottom);
  left: anchor(left);
  
  /* 相对于锚点的中心 */
  top: anchor(center);
  left: anchor(center);
  
  /* 组合 */
  top: anchor(bottom); /* 在锚点下方 */
  left: anchor(center); /* 水平居中 */
  
  /* 计算值 */
  top: calc(anchor(bottom) + 8px);
}

边界处理

position-try-fallbacks 处理空间不足的情况:

.tooltip {
  position: absolute;
  position-anchor: --anchor;
  
  /* 默认在下方 */
  top: anchor(bottom);
  left: anchor(center);
  
  /* 空间不足时尝试其他位置 */
  position-try-fallbacks: 
    flip-block,           /* 上下翻转 */
    flip-inline,          /* 左右翻转 */
    flip-block flip-inline;
  
  /* 或自定义 */
  position-try-fallbacks: 
    --top-position,
    --right-position;
}

@position-try --top-position {
  top: anchor(top);
  bottom: auto;
}

@position-try --right-position {
  left: anchor(right);
  right: auto;
}

弹出层

配合 Popover API:

<button popovertarget="menu" class="trigger">
  Open Menu
</button>
<div id="menu" popover class="menu">
  <a href="#">Item 1</a>
  <a href="#">Item 2</a>
</div>
.trigger {
  anchor-name: --trigger-anchor;
}

.menu {
  position-anchor: --trigger-anchor;
  top: anchor(bottom);
  left: anchor(left);
}

居中对话框

.dialog-trigger {
  anchor-name: --dialog-anchor;
}

.dialog {
  position: fixed;
  position-anchor: --dialog-anchor;
  
  /* 居中 */
  top: anchor(center);
  left: anchor(center);
  transform: translate(-50%, -50%);
  
  /* 或使用 inset-area */
  inset-area: center;
}

浏览器支持

浏览器 版本
Chrome 125+
Edge 125+
Safari 实验性
Firefox 实验性

兼容性检测:

@supports (position-anchor: --test) {
  /* 支持 Anchor Positioning */
}
// JS 检测
if (CSS.supports('position-anchor', '--test')) {
  // 支持
} else {
  // 降级方案
}

降级方案

.tooltip {
  /* 降级:相对于直接父元素 */
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
}

@supports (position-anchor: --test) {
  .trigger {
    anchor-name: --trigger-anchor;
  }
  
  .tooltip {
    position-anchor: --trigger-anchor;
    top: anchor(bottom);
    left: anchor(center);
  }
}

小结

CSS Anchor Positioning 的优势:

  • 无需 JavaScript 计算位置
  • 自动处理边界情况
  • 与 Popover API 配合好
  • 性能更好

适合场景:

  • Tooltip
  • 下拉菜单
  • 弹出层
  • 拖拽辅助

2024 年底开始在 Chrome 中可用,可以作为渐进增强方案。