写了好几年页面,才发现自己连 title 都没用明白

我有一支技术全面、经验丰富的小型团队,专注高效交付中等规模外包项目,有需要外包项目的可以联系我

你有没有过这种窘迫瞬间:

用了一手机好多年,有天无聊乱点设置,突然发现—— 原来它早就有你梦寐以求的功能,只是一直藏在角落,你从来没点进去看。

上周我就经历了同样的尴尬,只不过主角不是手机,是——HTML 的属性

更具体一点: 我以为 title 这个属性,就是“鼠标放上去弹个小提示”这么简单。 结果一查规范,才发现:

这货干的事,比我想象的复杂多了。

我写 HTML 超过六年,自以为基础扎实。 直到那天我才意识到: 自己这几年一直在用 同样的几个属性、同样的几种写法, 完全错过了它们“隐藏的第二职业”。

今天就带你翻一翻这些“老熟人”, 看看它们背后那些你从来没正眼瞧过的能力。

那天,我差点被一个手风琴菜单气到重构整站

场景是这样的: 我要给一个网站写 FAQ 区域,用一组 <details> 做折叠。

客户的要求很简单:

“我只想让用户一次只能展开一个问题, 也就是说,点击新的,旧的要自动收起来。”

我心想:小菜一碟。 惯性思路:“写点 JavaScript 管状态就行。”

然后就是熟悉的一套流程:

  • 绑事件监听
  • 管当前展开项
  • 处理重复点击
  • 测试一些边界情况
  • 调试到开始怀疑人生

正当我在 VSCode 前面念念有词的时候,我刷到了这一段写法:

<details name="faqs">
  <summary>Question 1</summary>
  Answer goes here.
</details>
<details name="faqs">
  <summary>Question 2</summary>
  Another answer.
</details>

等等——name 属性?出现在 <details> 上?

我半信半疑地试了一下,结果浏览器非常淡定地告诉我:

“是的亲,你给我加上同一个 name, 我就会自动帮你做到 ‘同组里一次只能展开一个’。”

一个属性。 零行 JavaScript。 需求完美满足。

那一刻我有点恍惚:

原来这些年,很多我自以为“必须靠逻辑来扛”的东西, 其实 HTML 自己早就会。


那些你以为“用熟了”的属性,其实一直在隐藏功能

下面这些属性,你肯定都见过:

nametitlevaluemultipledisabledtarget ……

但它们在不同标签里, 居然一个个都开启了“隐藏职业技能”。


1. name 不只是电台 DJ 在用的“分组按钮”

我们早就习惯了在 radio 上这么写:

<input type="radio" name="gender">
<input type="radio" name="gender">

同一个 name,就是一组互斥选项。

但你知道吗?在 <details> 上加 name,也能分组。

写成这样:

<details name="faqs">
  <summary>Question 1</summary>
  Answer goes here.
</details>
<details name="faqs">
  <summary>Question 2</summary>
  Another answer.
</details>

同一组 name 的 <details>, 浏览器会自动帮你做到:

  • 打开新的
  • 旧的那一个自动收起

也就是说,你想要的“手风琴效果”, 根本用不着写那堆“当前激活项”“关闭其他全部”的 JavaScript。

知道之前:为了管理折叠状态,我能写出 40 行 JS。

知道之后:复制粘贴同一个属性名三次,完事。

2. title 居然有三重身份,不只是个小气泡提示

大部分时候,我们在任意标签上加 title, 唯一效果就是鼠标悬停出现一个 tooltip。

<button title="点我一下试试">点我</button>

这没什么问题。 但真正精彩的地方在这里——

① 当它遇上带 pattern 的 <input>

在这种场景里:

<input 
  type="text" 
  pattern="[A-Za-z]{3,}" 
  title="Please enter at least 3 letters"
/>

title 不再只是“悬浮提示”。

当用户输入不符合 pattern 的格式时, 浏览器会直接把 title 的内容当成错误提示文案弹出来。https://wxa.wxs.qq.com/tmpl/op/base_tmpl.html

你不用自己写一大堆校验逻辑、挂一堆 blur 事件, 浏览器就帮你完成了“格式提示 + 错误信息文案”的一套流程。

② 当它跟 <abbr>(缩略词)在一起

写缩写时,我们常这样写:

<abbr title="Hypertext Markup Language">HTML</abbr>

这里的规范非常严格:

<abbr> 上的 title只能写完整的全称。 不要写解释、注释、顺手吐槽, 就是干干净净的“HTML 的完整展开”。

为什么? 因为屏幕阅读器和辅助设备, 会依赖这个 title 来读出真实含义。 你乱写一堆,等于在无障碍层面“扔烟雾弹”。

③ 当它跟 <dfn>(定义)勾搭在一起

<dfn> 用来标记一个“被定义的术语”。

在这种情况下:

  • dfn 元素里可以显示缩写或短名
  • 但它的 title 属性,必须写出完整定义

我就是在调试“读屏软件为什么不按我预期读缩写”的时候, 才顺藤摸瓜查到这些规范。

那一刻我才意识到: 这么多年,我几乎把 title 当成“随便写写的小注释”, 完全没有意识到它在语义上是有严格约束的。

3. value 可以让有序列表“一键穿越”

你可能知道 <ol> 可以自动编号:

<ol>
  <li>第一项</li>
  <li>第二项</li>
</ol>

但你未必用过这个写法:

<ol>
  <li>First item</li>
  <li>Second item</li>
  <li value="37">Suddenly thirty-seven</li>
  <li>Thirty-eight (it continues from there)</li>
</ol>

<li value="37"> 会直接告诉浏览器:

“从这行开始,编号是 37。”

后面的项会在这个基础上继续往上加。

最妙的是:

  • 不仅阿拉伯数字可用
  • 罗马数字、字母编号这些样式也都能配合使用

我曾用这个技巧写过一个“TOP 10 同事雷人行为榜”, 前几条编号正常, 然后直接跳到 47. 写——

“在办公室微波炉里热鱼。”

莫名其妙地非常有喜感。

4. multiple 不止是“多文件上传专用”,居然能管邮箱

multiple 出现在 <input type="file"> 上,你肯定不陌生:

<input type="file" multiple>

允许用户一次选多个文件,这很合理。

但当你写成这样——

<input type="email" multiple>

事情就有趣了。

在这里,multiple 的含义变成:

“允许用户输入多个邮箱地址,用逗号隔开。”

更关键的是:

  • 浏览器会分别校验每一个邮箱的格式
  • 你不用自己写一大坨正则去 split + trim + validate

我曾经一本正经花了一个下午,写了几十行自定义校验逻辑:

  • 拆分字符串
  • 去除空格
  • 校验每个邮箱
  • 提示哪一个错了

后来才发现:

人家 HTML 早就帮我把这事想好了。

之前:60 行 regex + 校验 + 错误提示处理。

现在:在 input 上多加一个单词:multiple


5. datetime 在 <ins> / <del> 上,就是自带版本记录

<ins> 和 <del> 这两个标签, 本来就是用来标记新增内容删除内容的。

但当你给它们补上 datetime 属性之后——

<p>
  The meeting is at 
  <del datetime="2024-01-15">3pm</del>
  <ins datetime="2024-01-15">4pm</ins>
</p>

你就多了一层能力:

用机器可读的方式,记录“这行内容是在什么时候被修改的”。

这东西特别适合用在:

  • 更新日志页面(changelog)
  • 协议、条款、隐私说明那种需要体现“变更历史”的文档
  • 长期维护的帮助中心文章

有点像 Word 里的“修订模式”, 但整个过程是语义化的, 机器和人都看得懂。


6. disabled 一口气搞瘫整个 <fieldset>

你大概习惯给某个输入框加:

<input type="text" disabled>

单个禁用,这没问题。

但要是你有一大块区域,在某些条件下都不能改, 比如“没有权限的用户不能编辑这一整组字段”, 你干嘛要一个个去写?

其实你可以这样:

<fieldset disabled>
  <legend>Locked Section</legend>
  <input type="text" name="field1">
  <input type="text" name="field2">
  <input type="text" name="field3">
</fieldset>

当 <fieldset> 自身被加上 disabled

里面所有表单控件,都会自动进入禁用状态。

不用逐个写 disabled, 也不用在 JS 里循环 20 次去挨个改属性。

当你有一大片表单要根据角色权限统一“只读”或“锁定”时, 这就是最优解。


7. target="_blank" 不止能开新标签页链接,还能开“新标签页表单”

链接上用 target="_blank",谁都知道是“新标签页打开”:

<a href="/download" target="_blank">下载</a>

但你试过把它用在 <form> 上吗?

<form action="/submit" method="post" target="_blank">
  <!-- form fields -->
</form>

效果是——

表单提交之后,响应会在新标签页打开, 当前页面保持不动。

这在这些场景下非常好用:

  • “提交后在新标签页展示收据/凭条”
  • “导出报表,结果文件由新标签页触发下载”
  • “提交数据后跳转到一个专门的打印页面”

我之前为了解决这个需求, 写过一套 window.open() 的逻辑, 还顺手踩了一地“浏览器拦截弹窗”的坑。

后来才发现:

一句 target="_blank",其实就足够优雅。


我终于看懂的真相:不是 HTML 太简单,而是我们学得太浅

这一连串发现之后,我突然意识到:

我犯的错误,是“一次性把 HTML 当成已经学完的东西”。

就好像你拿到一把瑞士军刀, 用了好多年,一直只用那一把主刀划东西, 从来没把它折开看过里面还有螺丝刀、剪刀、小锯子。

HTML 也是这样。

那些我以为已经用烂的属性:

  • name
  • title
  • value
  • multiple
  • disabled
  • target

其实都是会变身的角色

它们在不同标签上, 有不同含义、不同行为,甚至引导着无障碍体验和语义结构。

而我们太习惯于:

“反正能跑就行,剩下的交给 JavaScript。”

于是写了一堆其实不用存在的代码。


你现在就能做的一件小事(但可能会删掉几十行废代码)

不需要一次性把这些全背下来。

我建议你现在只做一件事:

从上面挑一个你印象最深的属性, 打开你的项目,在代码里搜它。

然后认真看看:

  • 你是不是永远只用它“一种用法”?
  • 有没有地方可以改成:靠 HTML 自己的行为, 少写一半 JS?

我当时就是这么干的——

最后在项目里找到了 14 处, 是我以前手写了 JavaScript 去实现, 但其实浏览器原生就能做好的地方。

那天下午我删掉了 200 多行代码。 没有任何功能损失, 只有维护成本的下降和代码可读性的上升。


HTML 并没有“突然变强”。

真正变化的是—— 我们什么时候,愿意承认自己当初 只是学了“能跑起来的那一部分”, 而不是这门语言的全部。

你的代码,不一定要写得有多聪明。 它只需要:

先把现成能用的工具,真正用明白。全栈AI·探索:涵盖动效、React Hooks、Vue 技巧、LLM 应用、Python 脚本等专栏,案例驱动实战学习,点击二维码了解更多详情。

声明:来自JavaScript 每日一练,仅代表创作者观点。链接:https://eyangzhen.com/4444.html

JavaScript 每日一练的头像JavaScript 每日一练

相关推荐

关注我们
关注我们
购买服务
购买服务
返回顶部