想把一个元素盖到另一个元素上面,传统玩法非得把两个元素在HTML里写成父子关系,还得让儿子紧挨着老子。这波操作在动态页面里经常翻车,比如弹窗、提示框这些组件,非得打乱源码结构才能对齐。最近折腾CSS锚点定位发现,这玩意儿直接无视源码顺序,想贴谁就贴谁,简直绝绝子。
传统定位的坑
拿十个div来举个栗子,编号1到10。现在要让10号div盖在2号div上面。传统方法必须把10号div塞进2号div的肚子里,变成父子嵌套。
<div>1</div>
<div class="parent">
2
<div class="child">10</div>
</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>然后给父级设position: relative,子级设position: absolute,再用inset-block-start: 0和inset-inline-start: 0把子级钉在父级左上角。宽度设width: 100%就能完全覆盖父级。
.parent {
position: relative;
}
.child {
position: absolute;
inset-block-start: 0;
inset-inline-start: 0;
width: 100%;
}这里有个隐藏的大坑:如果父级没有设置position为非static值,子级的绝对定位就会跑偏到更外层的容器。而且源码顺序被硬生生改掉了,10号div原本该在最后,现在夹在中间,维护的时候找得眼瞎。动态添加内容时,这种结构变动还会触发整个布局重排,性能掉一地。
锚点定位登场
锚点定位这波黑科技完全不care源码顺序。还是那十个div,这次保持原样,10号div老老实实待在最后。
<div>1</div>
<div class="anchor">2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div class="target">10</div>先给2号div起个锚点名字,用anchor-name属性,值必须是--开头的虚线标识符,比如--myAnchor。
.anchor {
anchor-name: --myAnchor;
}然后在10号div里通过position-anchor绑定这个锚点,值必须跟anchor-name完全一致。
.target {
position-anchor: --myAnchor;
}接下来用position-area把10号div怼到2号div的正中央。position-area: center会让目标元素居中覆盖在锚点上面。
.target {
position-anchor: --myAnchor;
position-area: center;
}如果想让10号div完全把2号div糊得严严实实,尺寸也得匹配。用anchor-size()函数动态获取锚点的宽高,anchor-size(width)拿到宽度,anchor-size(height)拿到高度。
.target {
position-anchor: --myAnchor;
position-area: center;
width: anchor-size(width);
height: anchor-size(height);
}代码实战对比
下面这张表把两种方案的差异扒得明明白白。
| 对比项 | 传统定位 | 锚点定位 |
|---|---|---|
| 源码顺序 | 必须嵌套 | 任意位置 |
| 定位方式 | relative+absolute | anchor-name+position-anchor |
| 覆盖父级 | width:100% | anchor-size(width) |
| 浏览器支持 | 全兼容 | Chrome最新版 |
实际操作的时候得盯着一个关键点:锚点名字必须是虚线标识符,写个--center或者--btn都行,但千万别漏掉开头的两个短横线。position-area除了center还能玩出花来,比如top left把目标贴到锚点左上角,bottom right贴右下角。想完全覆盖锚点区域,用position-area: center配合anchor-size()就能完美复刻传统定位的效果。
手机端和旧版浏览器暂时别上锚点定位,目前只有Chrome默认支持,其他浏览器得开实验性标志。生产环境用之前先做特性检测,或者搭配@supports写降级方案。
