tab切换html结构应采用语义化包裹,配合data-tab属性关联面板,类名统一用tabs__前缀便于less嵌套;用[data-tab-active]控制显隐,aria-selected标记状态,确保可访问性与js状态同步。

Tab切换的HTML结构怎么组织才利于Less嵌套
直接用 <nav></nav> 包裹 <button></button> 或 <a></a> 是最稳妥的选择,避免用 <div> 模拟可点击元素——这会破坏语义、影响键盘焦点和屏幕阅读器。Less嵌套依赖清晰的父子层级,结构混乱会导致选择器冗长或失效。
<p>推荐结构:</p>
<pre class="brush:php;toolbar:false;"><nav class="tabs"><button class="tabs__item" data-tab="panel-1">首页</button>
<button class="tabs__item" data-tab="panel-2">详情</button>
</nav><div class="tabs__panels">
<section id="panel-1" class="tabs__panel">...</section><section id="panel-2" class="tabs__panel">...</section>
</div></pre>
<ul>
<li>类名统一加 <code>tabs__ 前缀,避免全局污染,也方便Less用 &__item 快速嵌套
:checked + 的伪类联动(需改用 <input type="radio">),实际业务中 JS 控制显隐更灵活、可访问性更好.tabs__item 上写 display: inline-block 等布局样式——应由 .tabs 容器统一控制,否则嵌套时容易误覆盖用 &:not(:first-child) 和 &:hover 实现分隔线与悬停态
纯 CSS 实现 Tab 项之间的竖线分隔,关键不是给每个项加边框,而是只给非首项加左侧边框。Less 的嵌套配合伪类能干净表达这个逻辑,且避免手动加 class。
典型写法:
.tabs {
display: flex;
&__item {
padding: 8px 16px;
border: none;
background: none;
cursor: pointer;
&:not(:first-child) {
border-left: 1px solid #e0e0e0;
}
&:hover:not(:disabled) {
background-color: #f5f5f5;
}
&[aria-selected="true"] {
font-weight: 600;
color: #1976d2;
border-bottom: 2px solid #1976d2;
}
}
}
-
:not(:first-child)必须写在&__item内部,否则编译后选择器变成.tabs :not(:first-child),失去“当前项非首项”的语义 -
aria-selected="true"是比.is-active更规范的状态标记,JS 切换时同步设置它,同时支持无障碍 - 不要用
transition: all,只对background-color和color做过渡,否则border-bottom动画会抖动
面板显隐控制:用属性选择器替代 .is-hidden 类
Less 本身不处理 DOM 状态,但可以预设好基于 [data-tab-active] 这类属性的选择器规则,让 JS 只需切换属性值,样式自动响应。这比反复增删 .is-hidden 类更轻量、更易维护。
示例:
.tabs__panels {
> .tabs__panel {
display: none;
// 默认隐藏所有
&[data-tab-active="false"] {
display: none;
}
// 显式显示当前激活项
&[data-tab-active="true"] {
display: block;
}
}
}
- 必须用
>子选择器限定范围,防止嵌套子面板意外被匹配 - 不用
visibility: hidden或opacity: 0——它们仍占布局流,Tab 面板内容可能有绝对定位元素,导致错位 - 如果面板需要动画入场,改用
max-height+overflow: hidden配合 transition,但需预设合理高度值,max-height: 0→max-height: 500px是常见折中
响应式断点里重置嵌套逻辑容易漏掉什么
当 Tab 在小屏下改为垂直堆叠时,display: flex 要改成 flex-direction: column,但很多人只改容器,忘了子项的 border-left 还在生效——结果出现难看的左侧竖线。
- 必须在媒体查询内重置
&__item的边框:@media (max-width: 768px) { .tabs__item { border-left: none; border-bottom: 1px solid #e0e0e0; } } - 不要把整个 Less 块复制进媒体查询,用
.tabs--vertical类配合& when (@screen-xs-max)混合宏更可控(需提前定义变量) - 移动端慎用
:hover效果——部分 Android 浏览器会触发伪悬停,建议加@supports (hover: hover)条件包裹
真正麻烦的不是写法,而是 JS 切换状态后,如何确保 aria-selected、tabindex、data-tab-active 三者同步更新——漏掉任意一个,都可能让键盘用户卡在不可聚焦的 Tab 项上。











