各大浏览器厂商这次罕见地联手搞事情,Interop 2026计划直接把一堆还在“实验室”阶段的CSS新功能给踢进了现实。以前看到锚点定位、滚动驱动动画这些炫酷玩意儿,第一反应总是“兼容性咋样”,现在好了,Chrome、Safari、Firefox三大阵营齐步走,意味着这些特性很快就能在生产环境里放心用。这篇东西就是给还在观望的小伙伴们,盘一盘这些新玩意儿到底怎么上手,实操的时候又容易在哪个环节翻车。
锚点定位,管你DOM结构乱成狗
以前想做个跟随按钮的提示框,总得用JavaScript算位置,或者把元素硬塞进目标元素里面当子元素,否则根本没法对齐。现在有了anchor-positioning,相当于给元素装了个“吸铁石”,想贴谁就贴谁。
基础玩法
用anchor-name给目标元素起个代号,然后用position-anchor在需要跟随的元素上绑定这个代号,最后用inset-area指定贴靠的位置。
/* 给按钮起个名 */
button {
anchor-name: --submit-btn;
}
/* 提示框贴过去 */
.tooltip {
position: fixed;
position-anchor: --submit-btn;
inset-area: block-start;
margin-bottom: 8px;
}要是提示框跑到屏幕外头去了咋整?这时候就得靠position-try-fallbacks来救场。比如顶部空间不够,就自动弹到右边。
.tooltip {
position: fixed;
position-anchor: --submit-btn;
inset-area: block-start;
position-try-fallbacks: --flip-to-right;
}
@position-try --flip-to-right {
inset-area: inline-start;
margin-inline-end: 8px;
}写这段样式的时候,得记住锚点元素和跟随元素不需要在DOM树里有啥血缘关系,哪怕一个在天上一个在水里,只要在同一个渲染上下文里就能贴上去。但千万别忘了给跟随元素加position: fixed或position: absolute,否则定位属性压根不生效。
升级玩法
要是碰上更复杂的场景,比如一个锚点元素要挂好几个不同的跟随物,或者跟随物的位置需要根据内容多少动态调整,anchor()函数就派上用场了。
.menu {
position: fixed;
anchor-name: --main-menu;
}
.dropdown {
position: fixed;
left: anchor(--main-menu right);
top: anchor(--main-menu bottom);
margin-top: 4px;
}这里anchor(--main-menu right)直接读取了锚点元素的右侧坐标,比inset-area更精细。不过得注意,用anchor()取值的时候,如果锚点元素还没渲染出来或者被隐藏了,取到的值可能是auto,导致跟随元素飞走。所以最好确保锚点元素在页面里是稳稳当当可见的。
滚动驱动动画,进度条自己会动
以前页面滚动和动画进度之间没啥直接关系,想做那种“滚动越多,进度条越满”的效果,得用JavaScript监听滚动事件,还要考虑性能,动不动就卡成PPT。现在浏览器原生支持animation-timeline: scroll(),动画进度直接绑定滚动进度,丝滑得一批。
基础版
一个最典型的场景,页面顶部放个进度条,随着滚动条往下走,进度条从左到右填满。
<div id="progress"></div>#progress {
height: 4px;
background-color: #07c;
transform-origin: 0% 50%;
animation: fill-progress linear forwards;
animation-timeline: scroll();
}
@keyframes fill-progress {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}这里scroll()默认用的是最近的滚动容器,一般是整个页面。如果页面里有多个滚动区域,想针对某个特定的容器做动画,可以给scroll()传参数。
.sidebar {
overflow-y: auto;
}
.sidebar-progress {
animation-timeline: scroll(nearest);
}写滚动驱动动画的时候,有个坑特别容易踩:动画的animation-duration写多少都没影响,因为动画的整个生命周期被滚动范围覆盖了。但animation-timing-function还是能派上用场的,比如用ease-out让进度条快到顶的时候走得慢一点。
带缓动版
光填满进度条不够带劲,想做个元素随着滚动淡入淡出,或者让某个卡片在滚动到视野中央时“弹”一下,这就得配合view()时间线了。view()关注的是元素本身进入视口的进度。
.card {
animation: fade-in linear forwards;
animation-timeline: view();
}
@keyframes fade-in {
0% {
opacity: 0;
transform: translateY(20px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}这么一写,.card元素刚进入视口的时候透明度为0,完全进入后透明度变成1,整个过程完全由滚动控制,不用写一行JavaScript。但是得留个心眼,如果动画里动了transform,可能会和页面本身的滚动条产生层叠问题,最好确保动画元素的z-index别乱飞,或者用will-change提前告知浏览器。
高亮伪类,选中的文字也能美颜
::selection大家都熟,但这次Interop 2026带来了一整套高亮伪类家族,连浏览器搜索命中的文字、拼写错误的单词都能单独给样式了。
搜索高亮定制
默认浏览器Ctrl+F搜出来的黄色高亮,很多时候跟网站设计格格不入。现在用::search-text可以直接把样式拉回到设计体系里。
::search-text {
background-color: #ffd966;
color: #2d2d2d;
text-decoration: underline;
text-decoration-thickness: 2px;
}更骚的操作是配合:current伪类,给当前选中的那个搜索结果再加一层特效。
::search-text:current {
background-color: #ffb347;
font-weight: bold;
}用这套高亮伪类的时候,得注意它们本质上属于伪元素,能设置的样式有限制,比如不能改padding、margin这些盒模型属性,只能改颜色、背景、文字修饰这类文本外观。要是硬加border,大概率不会生效。
语法高亮另一种思路
::spelling-error和::grammar-error默认只在可编辑区域生效,比如<div contenteditable="true">。想搞个富文本编辑器里的拼写错误标红,直接安排上。
[contenteditable]::spelling-error {
text-decoration: red wavy underline;
}这样用户输入错词的时候,底下就会飘红波浪线,体验跟Word差不多。但得提醒一下,这种样式依赖浏览器内置的拼写检查引擎,不同操作系统底层的字典不一样,中文支持可能看天,所以最好别拿它当唯一校验手段。
自定义高亮API,JS划词神器
::highlight()是JavaScript Custom Highlight API和CSS之间的桥梁,想实现那种划词笔记、多人协作时不同颜色标记的功能,靠它就对了。
const highlightRange = new Range();
highlightRange.selectNodeContents(document.getElementById('target-text'));
const highlight = new Highlight(highlightRange);
CSS.highlights.set('my-highlight', highlight);::highlight(my-highlight) {
background-color: #c0e0ff;
color: #000;
}这么一搞,任何选中的文本范围都能被高亮,而且性能爆棚,因为是浏览器原生渲染层干的活,比用span包一层的方式不知道高到哪里去了。但这里有个关键细节:高亮范围可以跨多个DOM节点,甚至跨元素,但如果高亮范围覆盖的元素内容后来被JS动态改变了,高亮可能自动消失,得重新计算并设置Range。
这些新特性扎堆出来,对新手来说最头疼的其实不是语法本身,而是“到底该不该现在就用”。看一眼Interop 2026的仪表盘,像锚点定位、滚动驱动动画、高级attr()这些已经在多个浏览器稳定版本里跑通了,完全可以在个人项目或者对兼容性要求没那么严格的场景里开箱试玩。要是碰上必须在老古董浏览器里跑的项目,拿这些特性当渐进增强也挺香,毕竟不支持的浏览器顶多是看不到那些花哨效果,基础功能又没坏。
