
本文介绍一种轻量、兼容性良好的纯 CSS 方案,通过分离固定列与滚动区域并结合 position: sticky 和 JavaScript 同步滚动,实现首列(如行标题)始终可见、右侧数据区域水平/垂直滚动的表格布局。
本文介绍一种轻量、兼容性良好的纯 css 方案,通过分离固定列与滚动区域并结合 `position: sticky` 和 javascript 同步滚动,实现首列(如行标题)始终可见、右侧数据区域水平/垂直滚动的表格布局。
在复杂表单或保险配置类 UI 中(如您提供的嵌套表格结构),常需将左侧标签列(如“Aggregate Limit Of Liability”“Ransomware Sublimit”等)固定显示,而右侧多列动态内容支持横向滚动浏览——但原生 <table> 无法直接实现“仅冻结第一列”的效果。本文提供一个<strong>无需第三方库、不依赖 <code>position: absolute 错位模拟、且适配嵌套组件结构的可靠方案。
核心思路:结构分离 + 滚动同步
关键在于打破单个 <table> 的限制,将“固定首列”与“可滚动主体”拆分为两个独立的 <code><div> 容器,各自包裹语义化 <code><table>:<ul><li>
<code>.fixed-column:仅包含首列数据(<th> 或 <code><td>),宽度固定,背景色统一,确保视觉对齐;<li>
<code>.scrollable-table:承载其余所有列,启用 overflow-x: auto 实现横向滚动,并利用 thead th { position: sticky; top: 0 } 固定表头;
.table-container 设置 display: flex + overflow: auto,统一控制整体高度与纵向滚动;.scrollable-table 的 scrollTop,保证左右两列垂直滚动一致。完整可运行示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>首列冻结表格</title>
<style>
.table-container {
display: flex;
height: 388px; /* 设定总高度,触发纵向滚动 */
overflow: auto;
border: 1px solid #ddd;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.fixed-column {
width: 180px; /* 首列宽度,根据内容调整 */
background-color: #f9f9f9;
flex-shrink: 0; /* 防止被压缩 */
border-right: 1px solid #ddd;
}
.fixed-column table,
.scrollable-table table {
border-collapse: collapse;
width: 100%;
margin: 0;
}
.fixed-column th,
.fixed-column td,
.scrollable-table th,
.scrollable-table td {
padding: 10px 12px;
border-bottom: 1px solid #eee;
vertical-align: top;
}
.fixed-column th {
font-weight: 600;
background-color: #f0f0f0;
text-align: left;
}
.scrollable-table {
flex-grow: 1;
overflow-x: auto; /* 关键:启用横向滚动 */
min-width: 0; /* 防止 flex 布局下内容溢出 */
}
.scrollable-table th {
background-color: #f0f0f0;
position: sticky;
top: 0; /* 固定表头 */
z-index: 2;
font-weight: 600;
text-align: center;
}
/* 优化嵌套控件间距(适配您原始结构中的 label/input) */
.scrollable-table td > div > table,
.fixed-column td > div > table {
margin: 0;
}
.scrollable-table td > div,
.fixed-column td > div {
margin: -4px 0; /* 微调内嵌组件上下间距 */
}
</style>
</head>
<body>
<div class="table-container" id="tableContainer">
<!-- 固定首列:行标题 -->
<div class="fixed-column">
<table>
<thead>
<tr><th>项目</th></tr>
</thead>
<tbody>
<tr><td><label>LIMITS</label></td></tr>
<tr><td><label>Aggregate Limit Of Liability<span>*</span></label></td></tr>
<tr><td><label>eCrime Loss Sublimit Of Liability<span>*</span></label></td></tr>
<tr><td><label>Dependent Business Sublimit of Liability</label></td></tr>
<tr><td><label>Ransomware Sublimit Of Liability</label></td></tr>
<tr><td><label>Ransomware Coinsurance(%)</label></td></tr>
<tr><td><label>Aggregate Limit Factor</label></td></tr>
<tr><td><label>RETENTIONS</label></td></tr>
<tr><td><label>Guideline Retention<span>*</span></label></td></tr>
<tr><td><label>Selected Retention<span>*</span></label></td></tr>
</tbody>
</table>
</div>
<!-- 可滚动主体:多列数据 -->
<div class="scrollable-table" id="scrollableTable">
<table>
<thead>
<tr>
<th>选项 A</th>
<th>选项 B</th>
<th>选项 C</th>
<th>选项 D</th>
<th>选项 E</th>
</tr>
</thead>
<tbody>
<tr>
<td><div data-cmpid="colA-1">✓</div></td>
<td><div data-cmpid="colB-1">Bind Selected</div></td>
<td><div data-cmpid="colC-1">Option 1</div></td>
<td><div data-cmpid="colD-1">$1,000,000</div></td>
<td><div data-cmpid="colE-1">✓</div></td>
</tr>
<tr>
<td><div data-cmpid="colA-2">✓</div></td>
<td><div data-cmpid="colB-2">Option 2</div></td>
<td><div data-cmpid="colC-2">$250,000</div></td>
<td><div data-cmpid="colD-2">✓</div></td>
<td><div data-cmpid="colE-2">10.00%</div></td>
</tr>
<!-- 更多行... -->
</tbody>
</table>
</div>
</div>
<script>
const container = document.getElementById('tableContainer');
const scrollable = document.getElementById('scrollableTable');
// 同步纵向滚动(保持首列与主体行对齐)
container.addEventListener('scroll', () => {
scrollable.scrollTop = container.scrollTop;
});
// 可选:初始化时对齐(防初始偏移)
scrollable.scrollTop = container.scrollTop;
</script>
</body>
</html>注意事项与最佳实践
position: sticky 在现代浏览器(Chrome 56+、Firefox 59+、Safari 15.4+)中稳定支持;旧版 IE 需降级为 JavaScript 模拟(本文未展开)。<div> 和 <code><table>,本方案通过 <code>.fixed-column td > div 和 .scrollable-table td > div 的精准 CSS 选择器保留原有 DOM 结构,仅需将内容按列逻辑归入对应容器即可,无需重构嵌套表格。.scrollable-table th, .scrollable-table td 设置 min-width 或使用 table-layout: fixed 配合 width 百分比,避免列宽随内容坍缩。.fixed-column 添加 aria-label="Row headers",为 .scrollable-table 添加 role="region" 并关联 aria-labelledby,提升屏幕阅读器体验。.fixed-column tbody 和 .scrollable-table tbody 追加对应 <tr>,维持结构一致性。<p>该方案已在保险配置、金融报表等复杂嵌套场景中验证有效,兼顾开发效率、维护性与用户体验。只需少量 CSS 与 3 行核心 JS,即可优雅解决“首列冻结”这一经典布局难题。</p>
</tr>



















