智慧云商 發表於 2026-2-5 12:30:00

这 5 个冷门的 HTML 标签,能让你少写 100 行 JS

<h1 data-id="heading-0">🧑‍💻 写在开头</h1>
<p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<div>
<div>
<p>大家好!😁。</p>
<p>Code Review 的时候,我最怕看到什么?</p>
<p>不是复杂的算法,也不是什么正则。而是<strong>明明一个 HTML 标签就能搞定的事,有人非要写几百行 JS + CSS 去重新发明轮子</strong> 。</p>
<p>前几天,我看到一个新同学为了写一个折叠面板(Accordion),引入了一个重型的第三方库,还写了一堆 <code>useState</code>、<code>onClick</code> 和动画逻辑。</p>
<p>我默默地把他的代码全删了,换成了 3 行 <code>&lt;details&gt;</code>。他看我的眼神,仿佛在看一个外星人🤣。</p>
<p>在 2025 年的今天,浏览器原生 HTML 的能力早已今非昔比。很多我们习惯用 JS 去模拟的交互,现在不仅有原生支持,而且<strong>性能更好、兼容性更强、无障碍(a11y)更完善</strong>。</p>
<p>今天,我就来盘点 5 个被严重低估的HTML标签👇。</p>
<hr>
<h3 data-id="heading-0"><strong><code>&lt;details&gt;</code> &amp; <code>&lt;summary&gt;</code>:折叠组件</strong></h3>
<p>你是不是还在写这样的 React 代码?</p>
</div>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// JS 模拟版
const = useState(false);
return (
&lt;div className="accordion"&gt;
    &lt;div className="header" onClick={() =&gt; setIsOpen(!isOpen)}&gt;
      点击展开 {isOpen ? '⬆️' : '⬇️'}
    &lt;/div&gt;
    {isOpen &amp;&amp; &lt;div className="content"&gt;...&lt;/div&gt;}
&lt;/div&gt;
);</pre>
</div>
<p>为了这个功能,你还得写 CSS 动画,还得处理键盘事件(Tab 键能不能选到?回车能不能展开?等等)。</p>
<p>HTML 原生写法:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;details&gt;
&lt;summary&gt;点击展开&lt;/summary&gt;
&lt;div class="content"&gt;
    这里是展开后的内容,原生支持 Ctrl+F 页内搜索!
&lt;/div&gt;
&lt;/details&gt;</pre>
</div>
<div>
<div>
<ul>
<li><strong>没有任何JS</strong>:自带点击展开/收起交互。</li>
<li><strong>无障碍(a11y)满分</strong>:屏幕阅读器能完美识别,Tab 键、回车键原生支持。</li>
<li><strong>页内搜索</strong>:这是 JS 模拟版最大的痛点。如果内容被 JS 隐藏了(<code>display: none</code>),浏览器的 Ctrl+F 往往搜不到。但 <code>&lt;details&gt;</code> 里的内容,即使折叠,浏览器也能搜到并自动展开!</li>
</ul>
</div>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202602/2149129-20260205122746560-1735954136.png" alt="ScreenShot_2026-02-05_122617_090" loading="lazy"></p>
<p>&nbsp;配合 CSS 👇</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">details {
border: 1px solid #ccc;
border-radius: 6px;
padding: 8px;
}

summary {
cursor: pointer;
font-weight: bold;
}

/* 包住内容,让它能动画高度 */
details &gt; .content {
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height .45s ease, opacity .3s ease;
}

/* details 处于 open 状态时 */
details &gt; .content {
max-height: 200px; /* 你内容高度大概多少设多少,足够大即可 */
opacity: 1;
}</pre>
</div>
<div>
<div>
<p>依然可以做动画。</p>
<hr>
<h3 data-id="heading-1"><strong><code>&lt;dialog&gt;</code>:弹窗组件</strong></h3>
<p>写模态框(Modal)是前端最大的坑之一。你需要考虑:</p>
<ul>
<li><code>z-index</code> 层级会不会被遮挡?</li>
<li>点击遮罩层关闭?</li>
<li><strong>Focus Trap(焦点锁定)</strong> :打开弹窗后,Tab 键不能跑到底层页面去。</li>
<li>按下 <code>Esc</code> 键关闭?</li>
</ul>
<p>为了解决这些,我们通常会引入 <code>Antd Modal</code> 或者 <code>React Portal</code>。但在轻量级场景下,原生 <code>&lt;dialog&gt;</code> 才是神🫅。</p>
<p><strong>HTML 原生</strong></p>
</div>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;dialog id="myModal"&gt;
&lt;form method="dialog"&gt;
    &lt;p&gt;这是一个原生模态框&lt;/p&gt;
    &lt;button&gt;关闭(自动)&lt;/button&gt;
&lt;/form&gt;
&lt;/dialog&gt;

&lt;button onclick="myModal.showModal()"&gt;打开弹窗⏏&lt;/button&gt;</pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202602/2149129-20260205122817799-460123885.png" alt="ScreenShot_2026-02-05_122626_722" loading="lazy"></p>
<ol>
<li>Top Layer(顶层特性)&nbsp;:浏览器会把它渲染在所有 DOM 的最上层,彻底无视父元素的&nbsp;<code>z-index</code>&nbsp;和&nbsp;<code>overflow: hidden</code>。</li>
<li>::backdrop 伪元素:直接用 CSS 定制遮罩层样式。</li>
</ol>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">/* 背景遮罩 */
dialog::backdrop {
    background: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(3px);
    transition: opacity .3s ease;
}</pre>
</div>
<div>
<div><ol start="3">
<li><strong>原生交互</strong>:自带 <code>Esc</code> 关闭,自带焦点管理,表单提交自动关闭。</li>
</ol><hr>
<h3 data-id="heading-2"><strong><code>&lt;datalist&gt;</code>:搜索自动补全</strong></h3>
<p>当产品经理要求做一个带搜索建议的输入框时,你的第一反应是不是:“快!引入 <code>Select2</code> 或者 <code>Antd AutoComplete</code>!😖</p>
<p>且慢。如果只是简单的建议列表,几 KB 的 JS 库都显得太重了。</p>
<p><strong>HTML 原生版:</strong></p>
</div>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;label&gt;选择你喜欢的框架:&lt;/label&gt;
&lt;input list="frameworks" /&gt;

&lt;datalist id="frameworks"&gt;
&lt;option value="React"&gt;
&lt;option value="Vue"&gt;
&lt;option value="Svelte"&gt;
&lt;option value="Angular"&gt;
&lt;option value="Solid"&gt;
&lt;/datalist&gt;</pre>
</div>
<div>
<div><ol>
<li><strong>模糊搜索</strong>:浏览器原生支持模糊匹配(打 u 会出来 Vue)。</li>
<li><strong>响应式</strong>:在手机上,它会调用系统原生的下拉选择 UI,体验比网页模拟的更顺滑。</li>
<li><strong>解耦</strong>:它只是一个建议列表,用户依然可以输入列表里没有的值(这点和 Select 不同)。</li>
</ol><hr>
<h3 data-id="heading-3"><strong><code>&lt;fieldset&gt;</code> &amp; <code>disabled</code>:一键禁用整个表单</strong></h3>
<p><strong>场景</strong>:用户点击提交按钮后,为了防止重复提交,我们需要<strong>禁用表单里的所有输入框</strong>。</p>
<p><strong>JS 笨办法:</strong></p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// 还要一个个去拿 DOM,或者维护一个 loading 状态传给所有组件
inputs.forEach(input =&gt; input.disabled = true);
buttons.forEach(btn =&gt; btn.disabled = true);</pre>
</div>
<strong>HTML 原生写法:</strong><br>
</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;form&gt;
&lt;fieldset disabled id="login-group"&gt;
    &lt;legend&gt;登录&lt;/legend&gt;
    &lt;input type="text" placeholder="用户名"&gt;
    &lt;input type="password" placeholder="密码"&gt;
    &lt;button&gt;提交&lt;/button&gt;
&lt;/fieldset&gt;
&lt;/form&gt;

&lt;script&gt;
// 一行代码搞定状态切换
document.getElementById('login-group').disabled = true;
&lt;/script&gt;</pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202602/2149129-20260205122923317-2041845230.png" alt="ScreenShot_2026-02-05_122634_940" loading="lazy"></p>
<p>&nbsp;</p>
<div>
<div>
<p>这是一个极好的<strong>分组</strong>思维。通过给 <code>&lt;fieldset&gt;</code> 设置 <code>disabled</code>,浏览器会自动禁用内部所有的 <code>&lt;input&gt;</code>, <code>&lt;select&gt;</code>, <code>&lt;button&gt;</code>。不用写循环,不用维护复杂的 State。</p>
<hr>
<h3 data-id="heading-4"><strong><code>&lt;input type="file" capture&gt;</code>:H5 调用手机相机</strong></h3>
<p><strong>场景</strong>:业务需要用户上传一张照片,可以是相册选的,也可以是<strong>当场拍的</strong>。</p>
<p>很多新手的反应是:是不是要接微信 JSSDK?是不是要写个 Bridge 调原生 App 能力?</p>
<p><strong>答案是不需要!</strong></p>
<p><strong>HTML 原生:</strong></p>
<div class="code-block-extension-header">
<div class="code-block-extension-headerLeft">
<div class="code-block-extension-foldBtn">
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;input type="file" capture="environment" accept="image/*"&gt;</pre>
</div>
<div>
<div>
<p>只要加上 capture 属性,在移动端(iOS/Android)点击上传时,系统会直接拉起相机,而不是让你去选文件。拍完照后,你拿到的就是一个标准的 File 对象。</p>
<p>不需要什么 JS SDK,实现原生级体验👍。</p>
<hr>
<p>我总是强调 <strong>最好的代码,是没有代码!</strong></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
</div>
<p><em><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></em></p><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/19578641
頁: [1]
查看完整版本: 这 5 个冷门的 HTML 标签,能让你少写 100 行 JS