网页内容藏起来了,搜索时咋办?,hidden=until-found这招挺好使

3,354字
14–21 分钟
in

有时候在网页上看到那些折叠起来的板块,比如常见问题解答或者那种点击才展开的说明文字,用浏览器的页面搜索功能(Ctrl+F)想找点东西,结果发现搜不到,是不是挺让人挠头的?以前碰到这种情况,八成是用了display: none或者visibility: hidden这类办法,直接把内容从可搜索的范围里“抹掉”了。现在有个新玩法叫hidden="until-found",给HTML元素加上这个属性,就能让藏起来的内容在页面搜索时被找到,匹配到关键词还会自动展开,这个设计确实挺妙。

目录

啥是until-found

hidden="until-found"是一个HTML属性,专门用来处理那种想暂时隐藏、但又希望搜索时能现身的元素。把它扔给一个元素,浏览器就懂了:这玩意儿先藏着,但用户用页面搜索功能找东西时,如果搜的关键词在里面,就自动亮出来。

<div hidden="until-found">
  <p>这里面可能藏着某个神秘配方,比如咖啡加盐能让甜味更突出。</p>
</div>

代码这么一写,正常情况下这块内容就是隐身的。但只要有人在页面上按下Ctrl+F,输入“咖啡”或者“甜味”,这个隐藏的盒子就会“唰”地一下展开,并把匹配到的文字高亮显示。

浏览器背后的操作

这个属性实际上是给浏览器传递了一个信号。在浏览器内部,它的效果类似于给元素偷偷加上了content-visibility: hidden样式。content-visibility这个属性本身就能控制元素是否渲染,hidden值就是让它不可见且不占布局空间。不过妙就妙在,hidden="until-found"在隐藏的同时,还留了一个“后门”,允许页面搜索功能把它临时“唤醒”,这跟直接写content-visibility: hidden还不完全是一回事。

跟老办法有啥不一样

以前想做个点击展开的效果,要么用JavaScript控制display属性,要么用<details>这个原生标签。<details>元素自带折叠功能,里面藏着的内容在没展开前,页面搜索也是找不到的。hidden="until-found”正好补上了这个缺口,它让隐藏的内容变得“可被搜寻”。

下面这个表格简单对比一下几种隐藏方式的搜索表现:

隐藏方式页面搜索能否搜到是否自动展开
display: none
visibility: hidden
details未展开
hidden=until-found

这样一来,像那种折叠起来的评论区、二次点击才显示的详细参数、或者悬浮菜单里的说明文字,都有机会被搜索功能命中,用户体验直接拉满。

基础玩法:直接上属性

最简单的用法就是直接把属性怼上去,不用写任何JavaScript,浏览器自己会处理搜索匹配和展开的行为。

操作流程

  1. 找到要隐藏的HTML元素。比如一个<div>或者<section>,里面放着想默认折叠的长篇内容。
  2. 在标签里加上属性。写成<div hidden="until-found">,注意拼写不能错,必须是until-found
  3. 保存文件,刷新页面。这时候应该看不到这块内容了。
  4. 在页面上按下Ctrl+F(Mac上是Cmd+F),输入隐藏在里面的某个词。
  5. 观察结果。页面应该会自动滚动到那个元素的位置,并且元素会展开,关键词高亮显示。

这里有一个挺容易踩坑的地方。如果给父元素加了hidden="until-found",但父元素自己还套了别的样式,比如用了overflow: hidden,那展开时可能会出现内容被切掉的情况。最好检查一下父级有没有限制高度的样式,保证内容展开后能完整显示。

进阶玩法:配合JS搞点事情

有些场景下,不能光靠浏览器自动展开,还得在内容出现后干点别的,比如埋个数据统计、或者改变一下页面布局。这时候可以监听beforematch事件。

这个事件会在浏览器即将因为搜索匹配而展开元素之前触发,时机刚刚好。

操作流程

  1. 在HTML里写好带属性的元素,并且给个id方便JS操作。
    html ¨K16K
  2. 写一段JavaScript监听事件
    javascript const secretBox = document.getElementById('secretBox'); secretBox.addEventListener('beforematch', function() { console.log('因为搜索命中了,马上要展开!'); // 在这儿可以干点私活,比如更新一下计数器 document.title = '发现隐藏内容'; });
  3. 测试流程。加载页面,用页面搜索功能搜“芝华塔尼欧”,控制台会先打印出日志,然后元素展开。

如果不用beforematch,只在展开后监听点击事件,那么通过搜索功能触发展开的情况就会被遗漏。另外,事件监听器需要在页面加载时就绑定好,不然属性还没生效,事件就先丢了。

兼容方案:让老浏览器也能用

目前Chrome和Firefox已经支持得不错,Safari还在追赶的路上,不过看Interop 2025的计划,全面支持也就是时间问题。但在那之前,如果想在所有浏览器上都有类似效果,就得想点招。

直接模拟hidden="until-found"的行为挺难,因为没法用content-visibility: hidden去复制那个“搜索可命中”的特性。Nathan Knowler捣鼓出一个办法,利用Shadow DOM来检测浏览器是否原生支持这个属性,如果不支持,就退而求其次,用别的隐藏方式,确保内容在视觉上不可见,但又不至于让用户完全找不到。

操作流程(使用polyfill思路)

  1. 引入一个封装好的polyfill脚本。这里不推荐具体库名,但思路是脚本会检测全局属性。
  2. 在HTML里正常使用属性。写上<div hidden="until-found">
  3. 脚本在后台干活。它会去检查浏览器是否认得until-found这个值。如果不认得,脚本会接管控制权,给元素应用一个特殊的隐藏样式,比如opacity: 0配合visibility: hidden,同时设置aria-hidden="true"保证可访问性。
  4. 手动模拟搜索行为。这种情况下,浏览器的原生页面搜索就帮不上忙了,需要在脚本里实现一个简易的搜索框,或者依赖前端框架的搜索功能来触发元素的显示。

这种方案有局限性,就是页面自带的Ctrl+F搜索在老浏览器上依然无法命中隐藏内容,需要依赖页面内自己实现的搜索控件。所以在使用polyfill时,得评估一下项目对老浏览器的要求到底有多高,如果Safari用户占比很小,其实直接让属性生效,在Safari上表现为完全不显示(也不可搜索)也能接受,毕竟内容本来就是要藏的。

样式上的小心机

当搜索命中后,浏览器会给匹配的关键词加高亮,这个高亮颜色通常是系统默认的。未来可能会引入::search-text伪元素,让开发者自定义这个高亮颜色。

::search-text {
  background-color: #ffcc00;
  color: #000000;
}

如果还想区分当前选中的匹配项和其他匹配项,可以结合:current伪类试试看。

::search-text:current {
  background-color: #ff6600;
}

设计样式的时候得留意对比度,高亮颜色太亮或者太暗都可能影响阅读。而且这个特性还在草案阶段,目前使用上存在不确定性,得做好降级准备,也就是设不设样式,浏览器都会用自己的默认高亮兜底。

搜索后留下的尾巴

一个挺有意思的现象,当通过搜索功能把隐藏内容“拽”出来后,就算关闭了搜索框,内容也不会自动缩回去。这跟<details>的行为不太一样,<details>手动折叠后内容就没了。hidden="until-found"一旦被搜索触发,似乎就默认“既然用户要找,肯定是有用,就留着吧”。

这个设计有它的道理,但也可能造成页面布局变化。比如一个页面里好几个隐藏块都被搜索触发展开了,页面一下子就变得老长。这时候要么接受这种变化,要么在合适的时机(比如用户点击某个按钮)主动把内容重新隐藏起来,但这又涉及到额外的状态管理。所以决定用这个属性之前,得先想清楚内容被搜索出来之后,是保持打开状态,还是需要提供一个“全部折叠”的选项,让用户自己控制。