现象
探索地图页在桌面端一切正常;数据增长到 107 个节点后,360px 视口出现约 150px 的横向滚动。页面其余部分(星图画布、筛选 chips、节点列表)都做了换行与收缩处理,溢出元素探针却指向一个看似无辜的下拉框区域。
排查
用“从 document.documentElement.scrollWidth 反查最右子叶元素”的定位法,命中链落在路径起点/终点选择器上:
<section class="grid gap-4 lg:grid-cols-[...]">
<!-- 360px 下为单列 -->
<aside>
<select>
<option>一个很长的中文标题…</option>
<!-- 107 个选项 -->
</select>
</aside>
</section>
三个 CSS 事实叠加成了事故:
- 原生
select的固有宽度由最长 option 决定,且没有可靠的截断样式(text-overflow对下拉框本体不生效); - 网格的隐式轨道是
minmax(auto, 1fr)——auto的最小值就是子项的 min-content 宽度; - 子项(aside)未声明
min-width: 0,于是 select 的 498px min-content 一路向上传播,把本应 328px 的轨道撑到 498px。
lg 断点前它是单列,撑破的恰恰是最不该溢出的移动端。
修复
三处最小改动,缺一不可:
/* 轨道:显式允许收缩 */
.series-timeline {
grid-template-columns: minmax(0, 1fr);
}
<!-- 子项:切断 min-content 传播 -->
<aside class="min-w-0">
<!-- 控件:给自己一个可收缩的宽度 -->
<select class="w-full min-w-0 max-w-full">
…
</select>
</aside>
下拉弹层里 option 文本过长仍由浏览器原生处理(弹层可滚动/超出),但页面级布局不再被绑架。
泛化清单
同类“固有宽度炸弹”还有几个惯犯:<input size> 长默认值、nowrap 的胶囊标签、含长 URL 的 <code>、<img> 缺 max-width。防御是成对出现的:网格/flex 的每一层链路上,容器轨道用 minmax(0,1fr),子项配 min-width: 0,叶子控件自带 w-full max-w-full。只要链条断一层,min-content 就会穿过去。
验证方式
比“肉眼拖窗口”更可靠的是程序化审计:遍历 sitemap,在 360px 下测 scrollWidth - innerWidth,对超阈值页面反查“右侧越界且祖先无 overflow 裁剪”的最右叶元素——本项目把这一检查固化成了全量路由扫描,一轮就抓出了这个 select 和另外两处同源问题。