CSS Anchor Positioning Playground

交互式体验 CSS Anchor Positioning API,学习如何使用原生 CSS 实现精确的锚点定位效果,无需 JavaScript 计算。

浏览器支持
  • Chrome 125+ · 完全支持
  • Edge 125+ · 完全支持
  • Safari 26.0+ · 完全支持
  • Firefox 147+ · 完全支持
  • Opera 111+ · 完全支持

此组件使用 CSS Anchor Positioning API。如使用不支持此功能的浏览器,部分效果可能无法正常显示。

什么是 CSS Anchor Positioning?

CSS Anchor Positioning API 是一个强大的新特性,让你能够将一个元素相对于另一个元素精确定位,无需 JavaScript:

  • anchor-name: 为锚点元素命名
  • position-anchor: 指定要锚定到哪个元素
  • anchor(): 函数用于获取锚点元素的位置信息
  • position-try-fallbacks: 自动处理视口溢出,切换备选位置

通过这些 CSS 属性,你可以实现工具提示、下拉菜单、链接预览等复杂的定位效果。

示例演示

精美的链接预览卡片

使用 CSS Anchor Positioning API 实现的优雅链接预览效果,鼠标悬停即可查看链接详情。预览卡片会自动相对于链接定位,并在空间不足时自动切换到合适的位置。

📖示例文章

在现代 Web 开发中,Next.js

Next.js by Vercel - The React Framework
nextjs.org
Next.js by Vercel - The React Framework
The React Framework for the Web. Used by some of the world's largest companies, Next.js enables you to create high-quality web applications.
已经成为构建 React 应用的首选框架。它提供了服务端渲染、静态生成等强大功能。

样式方面,Tailwind CSS

Tailwind CSS - Rapidly build modern websites without ever leaving your HTML
tailwindcss.com
Tailwind CSS - Rapidly build modern websites without ever leaving your HTML
A utility-first CSS framework packed with classes that can be composed to build any design, directly in your markup.
提供了一套实用的工具类,让开发者能够快速构建精美的用户界面,而无需编写大量自定义 CSS。

对于组件库,shadcn/ui

shadcn/ui - Beautifully designed components
ui.shadcn.com
shadcn/ui - Beautifully designed components
Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.
是一个绝佳选择,它提供了一套精心设计、高度可定制的组件,让你的应用既美观又易于维护。

如果你对人工智能感兴趣,Vercel AI SDK

Vercel AI SDK - Build AI-powered applications
sdk.vercel.ai
Vercel AI SDK - Build AI-powered applications
The AI Toolkit for TypeScript. Build AI-powered products with React, Next.js, Vue, Svelte, Node.js, and more.
可以帮助你轻松集成 AI 功能到你的应用中。

最后,别忘了关注 GitHub

GitHub: Let's build from here
github.com
GitHub: Let's build from here
GitHub is where over 100 million developers shape the future of software, together. Contribute to the open source community, manage your Git repositories.
上的开源项目,与全球开发者一起协作!

原生 CSS
无需 JavaScript 计算位置,纯 CSS 实现锚点定位
自动调整
使用 position-try-fallbacks 自动避免视口溢出
精确定位
anchor() 函数提供精确的位置控制能力
展开查看源码
import React, { useState } from 'react';

interface LinkPreviewProps {
  href: string;
  title: string;
  description: string;
  image?: string;
  domain?: string;
  children: React.ReactNode;
}

const LinkPreview: React.FC<LinkPreviewProps> = ({ href, title, description, image, domain, children }) => {
  const [isHovered, setIsHovered] = useState(false);
  const timeoutRef = React.useRef<number | null>(null);
  const anchorId = React.useId().replace(/:/g, '');
  const anchorName = `--anchor-${anchorId}`;

  const handleMouseEnter = () => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
      timeoutRef.current = null;
    }
    setIsHovered(true);
  };

  const handleMouseLeave = () => {
    timeoutRef.current = window.setTimeout(() => {
      setIsHovered(false);
    }, 150);
  };

  React.useEffect(() => {
    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
    };
  }, []);

  return (
    <span className="inline-block" onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
      <a
        href={href}
        target="_blank"
        rel="noopener noreferrer"
        className="inline-flex items-center gap-1 font-600 text-gray-8 underline decoration-gray-4 underline-offset-4 transition-colors hover:decoration-gray-6 dark:decoration-[#525252] dark:hover:decoration-[#a3a3a3]"
        style={{ anchorName } as React.CSSProperties}
      >
        {children}
        <svg className="h-3.5 w-3.5 opacity-50" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
          <path d="M7 17L17 7M17 7H7M17 7V17" />
        </svg>
      </a>

      <div
        className={`rd-xl fixed z-50 w-80 overflow-hidden border border-gray-3 bg-white shadow-2xl transition-all duration-300 ease-out dark:border-[#424242] dark:bg-[#262626] ${
          isHovered ? 'scale-100 opacity-100' : 'pointer-events-none scale-95 opacity-0'
        }`}
        style={
          {
            positionAnchor: anchorName,
            top: 'anchor(bottom)',
            left: 'anchor(center)',
            transform: 'translateX(-50%)',
            marginTop: '12px',
            positionTryFallbacks: 'flip-block, flip-inline',
          } as React.CSSProperties
        }
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
      >
        {image && (
          <div className="relative h-40 overflow-hidden bg-gray-1 dark:bg-[#404040]">
            <img
              src={image}
              alt={title}
              className="h-full w-full object-cover transition-transform duration-500 hover:scale-105"
            />
            {/* <div className="absolute inset-0 bg-gradient-to-t from-white/80 to-transparent dark:from-gray-6/80" /> */}
          </div>
        )}

        <div className="flex flex-col gap-3 p-4">
          <div className="flex items-center gap-2">
            <span className="rd-1 flex h-4 w-4 items-center justify-center bg-gray-1 dark:bg-[#404040]">
              <svg className="h-2.5 w-2.5 text-gray-5" viewBox="0 0 24 24" fill="currentColor">
                <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" />
              </svg>
            </span>
            <span className="truncate text-gray-6 text-xs">{domain || new URL(href).hostname}</span>
          </div>

          <div className="line-clamp-2 font-semibold text-sm leading-snug dark:text-white">{title}</div>

          <div className="line-clamp-2 text-gray-6 text-xs leading-relaxed dark:text-[#a3a3a3]">{description}</div>
        </div>
      </div>
    </span>
  );
};

const Demo: React.FC = () => {
  return (
    <div className="card-default rainbow-border">
      <div className="card-default rounded-2xl border border-gray-3 border-solid p-8">
        <div className="card-header">
          <div className="card-header-title flex items-center gap-3">
            <span className="rd-lg flex h-8 w-8 items-center justify-center bg-gray-3 text-lg">📖</span>
            示例文章
          </div>
        </div>

        <div className="space-y-6 text-gray-7 leading-relaxed dark:text-[#d4d4d4]">
          <p>
            在现代 Web 开发中,
            <LinkPreview
              href="https://nextjs.org"
              title="Next.js by Vercel - The React Framework"
              description="The React Framework for the Web. Used by some of the world's largest companies, Next.js enables you to create high-quality web applications."
              image="https://assets.vercel.com/image/upload/front/nextjs/twitter-card.png"
              domain="nextjs.org"
            >
              Next.js
            </LinkPreview>{' '}
            已经成为构建 React 应用的首选框架。它提供了服务端渲染、静态生成等强大功能。
          </p>

          <p>
            样式方面,
            <LinkPreview
              href="https://tailwindcss.com"
              title="Tailwind CSS - Rapidly build modern websites without ever leaving your HTML"
              description="A utility-first CSS framework packed with classes that can be composed to build any design, directly in your markup."
              image="https://tailwindcss.com/opengraph-image.jpg?opengraph-image.c1dec83c.jpg"
              domain="tailwindcss.com"
            >
              Tailwind CSS
            </LinkPreview>{' '}
            提供了一套实用的工具类,让开发者能够快速构建精美的用户界面,而无需编写大量自定义 CSS。
          </p>

          <p>
            对于组件库,
            <LinkPreview
              href="https://ui.shadcn.com"
              title="shadcn/ui - Beautifully designed components"
              description="Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source."
              image="https://ui.shadcn.com/og?title=The%20Foundation%20for%20your%20Design%20System&description=A%20set%20of%20beautifully%20designed%20components%20that%20you%20can%20customize%2C%20extend%2C%20and%20build%20on.%20Start%20here%20then%20make%20it%20your%20own.%20Open%20Source.%20Open%20Code."
              domain="ui.shadcn.com"
            >
              shadcn/ui
            </LinkPreview>{' '}
            是一个绝佳选择,它提供了一套精心设计、高度可定制的组件,让你的应用既美观又易于维护。
          </p>

          <p>
            如果你对人工智能感兴趣,
            <LinkPreview
              href="https://sdk.vercel.ai"
              title="Vercel AI SDK - Build AI-powered applications"
              description="The AI Toolkit for TypeScript. Build AI-powered products with React, Next.js, Vue, Svelte, Node.js, and more."
              image="https://ai-sdk.dev/og/home?title=AI%20SDK&description=The%20AI%20Toolkit%20for%20TypeScript%2C%20from%20the%20creators%20of%20Next.js."
              domain="sdk.vercel.ai"
            >
              Vercel AI SDK
            </LinkPreview>{' '}
            可以帮助你轻松集成 AI 功能到你的应用中。
          </p>

          <p>
            最后,别忘了关注{' '}
            <LinkPreview
              href="https://github.com"
              title="GitHub: Let's build from here"
              description="GitHub is where over 100 million developers shape the future of software, together. Contribute to the open source community, manage your Git repositories."
              image="https://github.githubassets.com/assets/campaign-social-031d6161fa10.png"
              domain="github.com"
            >
              GitHub
            </LinkPreview>{' '}
            上的开源项目,与全球开发者一起协作!
          </p>
        </div>
      </div>

      <div className="mt-8 grid @sm:grid-cols-3 grid-cols-1 gap-4">
        <div className="rd-xl card-default-border p-5">
          <div className="rd-lg mb-4 flex h-10 w-10 items-center justify-center bg-success-1">
            <svg className="h-5 w-5 text-success" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" />
            </svg>
          </div>
          <div className="mb-1 font-semibold text-sm dark:text-white">原生 CSS</div>
          <div className="text-gray-6 text-xs dark:text-[#a3a3a3]">无需 JavaScript 计算位置,纯 CSS 实现锚点定位</div>
        </div>

        <div className="rd-xl card-default-border p-5">
          <div className="rd-lg mb-4 flex h-10 w-10 items-center justify-center bg-brand-1">
            <svg className="h-5 w-5 text-brand-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z" />
            </svg>
          </div>
          <div className="mb-1 font-semibold text-sm dark:text-white">自动调整</div>
          <div className="text-gray-6 text-xs dark:text-[#a3a3a3]">使用 position-try-fallbacks 自动避免视口溢出</div>
        </div>

        <div className="rd-xl card-default-border p-5">
          <div className="rd-lg mb-4 flex h-10 w-10 items-center justify-center bg-warning-1">
            <svg className="h-5 w-5 text-warning" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <path d="M12 3v18M3 12h18" />
            </svg>
          </div>
          <div className="mb-1 font-semibold text-sm dark:text-white">精确定位</div>
          <div className="text-gray-6 text-xs dark:text-[#a3a3a3]">anchor() 函数提供精确的位置控制能力</div>
        </div>
      </div>
    </div>
  );
};

export default Demo;
💡 原理说明

锚点定位核心:

  • 链接元素通过 anchor-name: --anchor-{id} 注册为锚点
  • 预览卡片通过 position-anchor: --anchor-{id} 绑定到对应的链接
  • 使用 top: anchor(bottom)left: anchor(center) 精确定位到链接下方中央
  • position-try-fallbacks: flip-block, flip-inline 自动处理视口溢出,在上下左右切换位置

视觉效果:

  • 渐变背景遮罩层提升图片的可读性
  • 平滑的透明度和缩放过渡效果,提升交互体验
  • 响应式图片加载和文本截断,确保卡片布局稳定
  • 纯 UnoCSS 实现,无需额外 CSS 文件

优势:

  • 无需 JavaScript 计算位置,性能更优
  • 自动处理滚动和视口变化
  • 原生浏览器支持,代码更简洁

核心特性

1. 原生 CSS 定位

无需 JavaScript 计算坐标,浏览器原生处理所有定位逻辑,性能更好,代码更简洁。

2. 自动位置调整

使用 position-try-fallbacks 自动检测视口边界,智能切换最佳显示位置,避免内容被裁剪。

3. 精确位置控制

anchor() 函数提供精细的位置控制,支持 topbottomleftrightcenter 等多种参考点。


实际应用场景

  • 链接预览卡片: 鼠标悬停显示链接摘要信息
  • 工具提示 (Tooltip): 显示元素的说明文字
  • 下拉菜单 (Dropdown): 相对于按钮定位菜单
  • 弹出式选择器 (Popover): 日期选择器、颜色选择器等
  • 上下文菜单: 右键菜单定位
  • 悬浮面板: 编辑器工具栏、格式化面板等

参考资料