价格卡片必须用语义化而非,每个需含标题、aria-label属性、包裹的价格数字及type明确的,移动端显隐仅靠css媒体查询实现。

价格卡片布局必须用语义化 <section></section> 而不是 <div>
<p>搜索引擎和屏幕阅读器会把 <code><section></section> 当作独立内容区块识别,而一堆 <div> 堆出来的价格表对 SEO 和无障碍几乎没帮助。实际写的时候别图省事全用 <code><div> 包着 <code><h3></h3> 和 <p></p> 就完事。
正确结构示例:
<section aria-label="基础版订阅方案"><h3>基础版</h3>
<p><strong>¥99</strong>/月</p>
<ul>
<li>最多 3 个用户</li>
<li>基础 API 访问权限</li>
</ul>
<button>立即订阅</button>
</section>
-
aria-label是给屏幕阅读器用的,不能省;没它,读屏软件只会说“section”,不知道这是哪个档位 - 每个
<section></section>必须含一个<h3></h3>或更高级标题,否则语义断裂 - 按钮必须用原生
<button></button>,别用<div onclick> —— 后者无法键盘聚焦、不触发 <code>Enter回车事件价格数字要用
<strong></strong>包裹,别靠 CSS 加粗视觉加粗只是表象,
<strong></strong>才代表语义上的强调。部分读屏软件会放慢语速或加重语气读出<strong></strong>内容,这对价格这种关键信息很关键。- 错误写法:
<span style="font-weight:bold">¥199</span> - 正确写法:
<strong>¥199</strong> - 如果要区分货币符号和金额(比如让 ¥ 更小),用
<span></span>套内部,但外层仍需<strong></strong>:<strong><span class="currency">¥</span>199</strong>
“立即订阅”按钮必须带
type="button"或明确type="submit"纯 HTML 页面没有 JS 时,
<button></button>默认是type="submit",点一下会尝试提交表单——哪怕页面里根本没<form></form>,某些老浏览器也会刷新页面或报错。- 如果按钮只是跳转(比如去 Stripe 支付页),写成:
<button type="button" onclick="location.href='https://buy.example.com/basic'">立即订阅</button> - 如果后续会加表单(比如填邮箱再跳转),先预留
<form></form>结构,按钮用type="submit",并确保有action属性 - 千万别漏
type属性——这是最常被忽略、却导致点击无响应或意外刷新的坑
移动端折叠逻辑只能靠 CSS
@media,别幻想用 HTML 做条件渲染纯 HTML 没变量、没 if 判断,所谓“移动端只显示一个价格卡”只能靠 CSS 控制显隐。有人试图用
<picture></picture>或多个<meta name="viewport">混淆概念,都没用。- 推荐做法:所有价格卡默认显示,用媒体查询隐藏非主推档位:
@media (max-width: 768px) { section:not(:first-of-type) { display: none; } } - 别用
visibility: hidden—— 它仍占布局空间,且读屏软件可能仍会读出隐藏内容 - 如果想让移动端用户能手动切换档位,就得加真实交互(比如用
<details><summary></summary></details>),但这已超出“纯 HTML”范畴,需要确认是否真要零 JS
纯 HTML 的边界很清晰:它能表达结构、语义和静态样式响应,但没法做状态切换、异步加载或用户偏好记忆。别在交付前一刻才意识到“这个下拉切换套餐的功能,HTML 真搞不定”。
- 错误写法:











