概述

事情发生在半个月前,当时正在开发一个Table组件。Table的body使用div作为单元格渲染出来的,header部分使用原生table标签渲染的,结果宽度适应的时候,header 和body 总是无法同步对齐,有几个像素的误差。
最后发现了是浏览器渲染table相关元素的时候,不支持小数渲染。

分析原因

先写个demo

<div class="stage">
    <table class="table">
    <tr>
        <td>Content</td>
    </tr>
    </table>
</div>

<style>
* {
    padding: 0;
    margin: 0;
}
.stage {
    width: 100.5px;
    height: 100px;
    background-color: red;
}

.table {
    width: 100.5px;
    background-color: blue;
}
</style>

chrome浏览器效果如下:
table小数渲染误差

其实只要是浮点数,直接都会被截断,所以设置 100px的效果和设置100.1px、100.5px、100.9px都是一样的。

这就真的不能忍了,直接求助网络,发现相关资料非常少,官网也没有相关说明,查到不少原因,比如:

  1. 浏览器最小渲染单位。
    这个明显很没有说服力,虽然浏览器确认存在最小渲染单位,但是无法解释 div 能渲染出浮点数,而table不行。
  2. stackoverflow有谈论这个

根本原因到底是什么,我也没彻底搞懂。
不过,无论什么原因,必须先得拿出一套解决方案,工期不能误呀!

解决方案

自己琢磨了一个兼容方案,当时也是灵机一动,想到了一个处理方式。

想法非常简单,就是单元格宽度先向下取整,平均分配,这样实际累计的宽度 肯定比 理想的小一点,然后把差出来的再按照索引进行分配,这样虽然有的单元格宽了1px,但是不影响视觉效果。

想到这个方案之后,发现这个解决方式和之前处理的如何保证 一组数据百分比之和为100%是一样的。

/**
 * @param {*} baseWidth 期望宽度
 * @param {*} cols 列数
 * @returns 每列宽度的集合
 */
function adjustWidth(baseWidth, cols) {
  const cellWidth = Math.floor(baseWidth / cols); // 计算基准单元格width
  const offset = baseWidth - cellWidth * cols; // 偏差值
  const results = new Array(cols).fill(cellWidth);
  // 如果有冗余,再次分配
  for (let i = 0; i < offset; i++) {
    results[i] = cellWidth + 1;
  }
  return results;
}
adjustWidth(1000, 3); // [ 334, 333, 333 ]

donglegend
910 声望82 粉丝

长安的风何时才能吹到边梁?


引用和评论

0 条评论