table-layout: fixed 是唯一能稳住百分比列宽的解法,需配合 <col> 显式声明列宽、禁用 td 的 width 百分比,并通过 outline/box-shadow/伪元素替代 border 以规避 sub-pixel 分摊问题,同时兼顾 dpr 适配与打印兼容性。

table-layout: fixed + 是唯一能稳住百分比列宽的解法
表格设了 width: 100% 却总差 1px,不是你写错了,是浏览器在 border-collapse: separate(默认)下对 sub-pixel 宽度做了四舍五入分摊。Chrome 会把算出来的小数像素(比如 327.6px)按列均摊到边框或间隙里,Firefox 和 IE 不这么干,所以不显偏移。
靠 transform: translateX(-1px) 硬拉?文字会糊,缩放后失效,别试。
- 给
<table>加style="table-layout: fixed; width: 100%;" - 用
<col>显式声明列宽:<col width="20%"><col width="30%"><col width="50%"> - 删掉所有
td上的width百分比——table-layout: fixed下它无效,只认<col> - 需要响应式?用
min-width/max-width控制列极限,别再塞百分比
border-collapse: collapse 能消 1px 偏移,但代价不小
border-collapse: collapse 确实能根治视觉错位,但它会吞掉 border-spacing、无法单独控制某列边框、外边框也得跟着合并——如果你的设计要求“左侧有边框、右侧无边框”或者“表格外边框粗、内边框细”,这就直接废了。
真要保留分离边框又不想偏移?绕开 border 渲染本身:
立即学习“前端免费学习笔记(深入)”;
- 把
border全换成outline:不参与盒模型,不触发 sub-pixel 分摊 - 用
box-shadow: inset 0 0 0 1px #999替代右侧边框:不占布局空间,也不被分摊 - 给
td设padding: 0; margin: 0,再用::after绘制 1px 分隔线,完全跳过 border 计算逻辑
注意:打印时 outline 和 box-shadow 默认不生效,此时必须切回 collapse 模式。
移动端 dpr ≥ 2 时,1px 边框本质是物理像素映射问题
iPhone 6 的 devicePixelRatio 是 2,你写的 border: 1px solid #ccc 实际占 2 物理像素——这不是 bug,是浏览器按 dpr 正常映射的结果。想让它看起来像设计稿里的 1px,就得绕过这个映射。
最稳妥的伪元素方案(兼容性好、不模糊文字):
-
::after必须有content: ""、position: absolute、明确height(如下边框设height: 2px) -
transform-origin得对齐:下边框用0 0,上边框用0 100%,否则缩放后偏移 - 父容器不能设
overflow: hidden,否则压扁后的伪元素被裁掉 - 别对整个元素用
transform: scale(),否则内容全变形
示例(下边框):
.border-bottom::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 2px;
background: #ccc;
transform: scaleY(0.5);
transform-origin: 0 0;
}高 DPI 屏幕下还要额外校准 rem 和容器尺寸
即使修复了表格列宽和边框,125% 缩放笔记本上仍可能轻微抖动——这是 devicePixelRatio 插值导致的。此时光调 CSS 不够,得同步 JS 校准:
- 运行
document.documentElement.style.fontSize = 16 * window.devicePixelRatio + 'px',让rem对齐物理像素 - 把表格外层容器的
width从40%改为calc(40% * (1 / window.devicePixelRatio))(需 JS 动态注入) - 绝对禁用任何全局
transform: scale(),它会让表格内部文字、图标全部失真
真正麻烦的点不在写法本身,而在你得同时兼顾:表格列宽稳定性、边框视觉一致性、dpr 动态适配、打印输出兼容性——四个条件稍一松动,1px 就会重新露头。



















