浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析

从 Chrome 125 开始,支持了一个全新的 CSS 特性 - Anchor Positioning,翻译过来即是锚点定位

在之前的文章中,我们较为系统的讲述了这个新特性的使用,感兴趣的可以翻开一下前文:抢先体验!超强大的 Anchor Positioning 锚点定位

在本文中,我们将使用锚点定位,实现一个简化版本的 Popover 功能。下面,我们将一起一探究竟。

传统 Popover 功能

长话短说,在日常的前端需求开发中,有这么一种场景,我们需要 hover 某个具体元素,以弹出一个弹出层,像是这样:

如果我们将弹出层的 DOM 结构,写在某个具体的元素内部,譬如放在与被 Hover 元素同级。如果被 Hover 元素的祖先元素的某一层设置了 overflow: hidden,则可能会出现这种截断现象:

为了避免这种情况的发生,一般情况下,常见的解决方案都是会将弹出层的 DOM,插入到页面最外层的 <body> 容器之下,再通过实时计算位置,将该弹出层定位到被 hover 元素附近。这也就是类似于 popper.jsTippy.js 等传统库所干的事情。

核心逻辑如下:

  1. 通过 JavaScript 获取触发元素的位置信息(getBoundingClientRect)
  2. 计算视口剩余空间(需考虑滚动位置、窗口尺寸等)
  3. 动态调整 Popover 位置(需处理边界碰撞、翻转逻辑)
  4. 添加 resize/scroll 事件监听器进行位置修正

其核心在于,通过 Javascript 动态计算当前 hover 元素的位置,将弹出层定位到当前 hover 元素附近合适的位置,并且处理好各种边界场景,这里很重要一点是强依赖于 Javascript 的计算。

因为传统的 CSS,是没有办法改变元素的定位父元素的能力的。

而有趣的是,全新的 CSS 特性 - Anchor Positioning 锚点定位就是为了解决这个问题的。

快速了解 Anchor Positioning 锚点定位

那,到底什么是 Anchor Positioning 锚点定位呢?我们通过一个 DEMO 快速上手。

假设我们在页面上有这么三个元素:按钮A、按钮B、被定位元素C,其中被 元素C 是一个插入到任意地方,且为绝对定位的元素,核心 CSS 代码如下:

<body>
  <div class="btn-a">按钮A</div>
  <div class="btn-b">按钮B</div>
  <div class="anchor">被定位元素C</div>
</div>
.btn-a, .btn-b {
    // 高宽各类样式
}
.anchor {
    position: absolute;
}

现在,三个元素属于同级关系,且 C 元素是绝对定位,当前基于 body 进行绝对定位。

大致样式如下:

而锚点定位的属性的核心作用就是,能够改变元素定位的基准,增强元素的绝对定位的能力。Anchor Positioning(锚点定位)允许我们基于其它锚点元素的位置和尺寸去定位上下文,而不是传统意义上的基于父元素去进行绝对定位。

下面,我们利用锚点定位去实现,当两个按钮 A、B 被 Hover 的时候,让定位元素 C 基于当前被 Hover 的按钮元素进行绝对定位,核心 CSS 代码如下:


.btn-a {
    // 将元素声明为定位基准点,命名为 --btn-a
    anchor-name: --btn-a;
}

.btn-b {
    // 将元素声明为定位基准点,命名为 --btn-b
    anchor-name: --btn-b;
}

// 当元素被 hover 的时候,改变 C 元素的样式
.btn-a:hover ~ .anchor {
    // 锚点绑定,建立元素与锚点的定位关系 
    position-anchor: --btn-a;
    // 基于新的锚点元素,设置元素的 left\top 属性
    left: anchor(--btn-a center);
    top: anchor(--btn-a bottom);
    // 利用 transform 轻微调整定位,非核心代码
    transform: translate(-50%, 5px);
}

// 同理,与上面做的事情一致,知识在 hover 按钮 B 时,重新设定锚点元素
.btn-b:hover ~ .anchor {
    position-anchor: --btn-b;
    left: anchor(--btn-b center);
    top: anchor(--btn-b bottom);
    transform: translate(-50%, 5px);
}

.anchor {
    // 方便动图演示,增加元素过渡动画,非核心代码
    transition: all .2s;
}

核心关注上面的 anchor-nameposition-anchoranchor 几个属性,其作用和含义在注释中有说明,在下文还会再描述一次。

如此一来,我们就实现了动态改变 C 元素定位基准的能力,我们看看效果:

简单而言,我们利用锚点定位的能力,在 hover 按钮 A\B 的时候,把 C 元素定位在它们正下方。这个就是锚点定位的能力!

Anchor Positioning 锚点定位核心 API

(1)anchor-name:锚点定义

功能:将元素声明为定位基准点
语法anchor-name: <dashed-ident>;
应用场景:触发元素、参考元素、动态定位源

/* 定义触发元素为锚点 */
.trigger-btn {
  anchor-name: --menu-anchor;
}
(2)position-anchor:锚点绑定

功能:建立元素与锚点的定位关系
语法position-anchor: <dashed-ident>;
注意:需配合定位属性(position: fixed/absolute)使用

.tooltip {
  position: fixed;
  position-anchor: --menu-anchor; /* 绑定到指定锚点 */
}
(3)anchor():动态定位

功能:根据锚点位置计算坐标
语法anchor(<anchor-name>? <anchor-side>)
方位参数

  • 垂直:top/center/bottom
  • 水平:left/center/right
  • 组合:top-left/bottom-right 等
.context-menu {
  /* 锚点右下角对齐 */
  top: anchor(--ctx-anchor bottom);
  left: anchor(--ctx-anchor right);
}

.tooltip {
  /* 水平居中于锚点 */
  left: anchor(center);
  right: anchor(center);
}
(4)anchor-size():尺寸继承

功能:获取锚点元素的尺寸值
语法anchor-size(<anchor-name>? <dimension>)
维度参数:width/height/block/inline

.popover {
  /* 继承锚点宽度 */
  width: anchor-size(width);
  
  /* 最小高度为锚点高度的1.5倍 */
  min-height: calc(anchor-size(height) * 1.5);
}

这里介绍了锚点定位中最为核心的几个属性,掌握了这几个属性,就可以应付大部分场景了。在我之前的一篇入门文章中,对它们也有一些更为详细的描述,感兴趣的同学,可以翻看:抢先体验!超强大的 Anchor Positioning 锚点定位

锚点定位的候补位置

还有一个非常重要的点,传统的 Popover 组件,一般都会有这么个功能 -- 智能边界处理

我们以一个功能比较强大的 Popover 库 floating-ui 举例,其官网展示了如下的一个功能,当元素在滚动过程中,如果原本 Popover 弹窗被遮挡,会自动进行位置移动,将弹窗重新调整到可视区域,效果如下:

令人振奋的是,现在,CSS 的 Anchor Positioning 锚点定位同样支持这种 智能边界处理,在锚点定位中,我们称之为候补位置。

这里,我们主要借助两个锚点定位相关的属性完成锚点定位的候补位置 position-try-fallbacks@position-try 规则。

@position-try 规则

@position-try 用于定义一个备选定位策略(一组定位规则),可以在多个元素中复用。它的语法类似于定义一个命名规则集合。

/* 语法示例:*/
@position-try --strategy-name {
  /* 具体的定位规则 */
  top: anchor(bottom);
  left: anchor(left);
}

关键点:

  • 命名策略:每个 @position-try 规则需要唯一名称(如 --tooltip-below)。
  • 独立作用域:策略内部的定位规则独立于元素自身的样式,仅在被调用时生效。

position-try-fallbacks 属性

position-try-fallbacks 用于在元素上指定备选定位策略的优先级顺序。浏览器会按顺序尝试这些策略,直到找到第一个可用的位置。

/* 语法示例:*/
.element {
  position-try-options: --strategy1, --strategy2, --strategy3;
}

关键点:

  • 顺序敏感:浏览器按列表顺序尝试策略,第一个可行的策略会被应用。
  • 动态回退:如果所有策略均不可行,元素会回退到默认定位(或父容器约束)。

使用锚点定位实现候补位置

基于上述介绍,我们来实现一个基于锚点定位的候补位置。

假设我们如下结构,当前已经使用了锚点定位:

<body>
  <div class="btn">Reference</div>
  <div class="anchor">Popover弹窗元素</div>
</div>

核心 CSS 如下:

.btn {
    anchor-name: --btn;
    border: 1px dashed #000;
    background: #ddd;
}

.anchor {
    position: absolute;
    position-anchor: --btn;
    left: anchor(--btn-a center);
    top: anchor(--btn-a bottom);
    transform: translate(-50%, 5px);
}

此时,两个元素都插入在 <body> 下面,但是 Popover 弹窗元素使用了 position-anchor: --btn 锚点定位,使其绝对定位的父元素是 .btn,并且,定位在按钮的下方,效果如下:

此时,我们只需要再借助 position-try-fallbacks@position-try,实现候补位置:

  1. @position-try 定义一个候补规则
  2. position-try-fallbacks 引入候补规则

核心 CSS 代码如下:

.btn {
    anchor-name: --btn;
    border: 1px dashed #000;
    background: #ddd;
}

.anchor {
    position: absolute;
    position-anchor: --btn;
    left: anchor(--btn-a center);
    top: anchor(--btn-a bottom);
    transform: translate(-50%, 5px);
    position-try-fallbacks: --position-bottom;
}

@position-try --position-bottom {
    left: anchor(--btn center);
    bottom: anchor(--btn top);
    top: unset;
    margin-bottom: 10px;
}

这样,我们在滚动页面的过程中,如果弹窗 popover 有超出视窗,候补规则会自动生效,看看效果:

仔细观察,和上面利用 Javascript 库实现的智能定位,效果一致,只是此时,我们仅仅使用了寥寥几行 CSS 代码!Amazing!

综上所述,到今天,我们已经可以利用 CSS 锚点定位大致实现一个极简版的 Popover 弹窗,并且可以满足大部分场景。不得不感叹 CSS 确实愈发的强力,

当然,本文介绍的关于锚点定位的功能都是基于实现一个最小版本的 Popover 展开的,基于锚点定位的 API 和回退候补,还有更多有趣的内容,感兴趣的可以猛戳 MDN 进行了解:MDN - Anchor PositioningMDN-Anchor Positioning @position try

最后

好了,本文到此结束,一个非常有意思的 CSS 技巧,希望本文对你有所帮助 😃

想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

想 Get 到最有意思的 CSS 资讯,千万不要错过我的 iCSS 公众号 😄 :

image

如果觉得文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打赏支持
+

(^_^)打个赏喝个咖啡(^_^)

微信支付
支付宝支付
原创作者: coco1s 转载于: https://www.cnblogs.com/coco1s/p/18739625
内容概要:本文档《DeepSeek本地部署教程(非ollama)》详细介绍了DeepSeek大语言模型的本地部署流程。首先明确了环境要求,包括Python 3.8以上版本、CUDA 11.7(针对GPU用户)、至少16GB RAM以及推荐的操作系统。接着阐述了安装步骤,如克隆代码仓库、创建虚拟环境、安装依赖等。随后讲解了模型下载方式,支持从Hugging Face平台下载不同版本的DeepSeek模型,如DeepSeek-7B、DeepSeek-67B和DeepSeek-Coder。文档还提供了两种运行模型的方式:命令行运行和使用API服务。此外,针对常见的问题,如CUDA相关错误、内存不足和模型加载失败等,给出了详细的解决方案。最后,文档提出了性能优化建议,如使用量化技术减少内存占用、启用CUDA优化等,并强调了安全注意事项,包括定期更新模型和依赖包、注意API访问权限控制等方面。; 适合人群:对大语言模型感兴趣的研究人员、开发者,特别是希望在本地环境中部署和测试DeepSeek模型的技术人员。; 使用场景及目标:①帮助用户在本地环境中成功部署DeepSeek大语言模型;②解决部署过程中可能遇到的问题,如环境配置、模型下载和运行时的常见错误;③提供性能优化建议,确保模型在不同硬件条件下的最佳表现;④指导用户进行安全配置,保障模型和数据的安全性。; 阅读建议:在阅读本教程时,建议按照文档的步骤顺序逐步操作,同时结合实际情况调整环境配置和参数设置。对于遇到的问题,可以参考常见问题解决部分提供的解决方案。此外,性能优化部分的内容有助于提高模型的运行效率,值得深入研究。
Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目),该项目是个人大作业项目,答辩评审分达到98分,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于SpringCloud架构的简易版个人网上银行系统源码(高分项目)Java基于S
内容概要:本文档详细介绍了基于JavaScript的俄罗斯方块游戏课程设计,旨在通过开发完整的俄罗斯方块游戏帮助学生掌握前端开发技术。课程设计分为课程背景与目标、项目意义、预期成果、需求分析、系统设计、详细设计、界面设计、实现方案、测试方案、项目进度安排以及总结与展望几个部分。系统设计采用模块化思想,包括游戏核心逻辑、界面渲染、用户交互和游戏状态管理四个主要模块。详细设计中定义了方块类、游戏类、渲染类和控制器类,明确了各组件的功能和交互方式。实现方案提供了HTML、CSS和JavaScript的具体代码示例,确保游戏在不同浏览器和设备上的兼容性。测试方案涵盖功能测试、边界测试、用户界面测试和兼容性测试,以保证游戏的质量。项目进度安排分为需求分析、编码实现、测试调试、文档编写和项目验收五个阶段,时间跨度约为11周。 适合人群:具备一定编程基础,特别是对JavaScript有一定了解的学生或初学者。 使用场景及目标:①巩固JavaScript基础知识,包括变量、函数、对象、数组、循环等;②理解并掌握DOM操作方法;③学习如何处理用户事件和实现交互效果;④掌握动画原理和实现方式;⑤培养解决实际问题的能力和逻辑思维。 其他说明:此课程设计不仅注重代码编写,还强调需求分析和方案设计,建议学习者在实践中结合这些内容,调试代码并不断优化游戏体验。此外,文档还提出了未来的改进方向,如添加更多游戏模式、实现多人对战、增加音效和动画效果等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值