table的寬高屬性不支持小數渲染 - 奇葩

概述

事情發生在半個月前,當時正在開發一個Table組件。Table的body使用div做爲單元格渲染出來的,header部分使用原生table標籤渲染的,結果寬度適應的時候,header 和body 老是沒法同步對齊,有幾個像素的偏差。
最後發現了是瀏覽器渲染table相關元素的時候,不支持小數渲染。css

分析緣由

先寫個demohtml

<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小數渲染偏差chrome

其實只要是浮點數,直接都會被截斷,因此設置 100px的效果和設置100.1px、100.5px、100.9px都是同樣的。瀏覽器

這就真的不能忍了,直接求助網絡,發現相關資料很是少,官網也沒有相關說明,查到很多緣由,好比:網絡

  1. 瀏覽器最小渲染單位。
    這個明顯很沒有說服力,雖然瀏覽器確認存在最小渲染單位,可是沒法解釋 div 能渲染出浮點數,而table不行。
  2. stackoverflow有談論這個

根本緣由究竟是什麼,我也沒完全搞懂。
不過,不管什麼緣由,必須先得拿出一套解決方案,工期不能誤呀!spa

解決方案

本身琢磨了一個兼容方案,當時也是靈機一動,想到了一個處理方式。code

想法很是簡單,就是單元格寬度先向下取整,平均分配,這樣實際累計的寬度 確定比 理想的小一點,而後把差出來的再按照索引進行分配,這樣雖然有的單元格寬了1px,可是不影響視覺效果。htm

想到這個方案以後,發現這個解決方式和以前處理的如何保證 一組數據百分比之和爲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 ]