CSS table-layout 属性揭秘

本文正在参加「金石计划」

起因

在使用 antd 的组件 Table,使用嵌套表格时,希望能做到内外表格宽度能够对齐,于是设想将内外表格的宽度保持一致,结果发现对于 table 元素而言,设置单元格的宽度并不容易。

这和今天要说的table-layout属性有什么联系呢?

table-layout 表格布局算法

CSS table-layout 属性揭秘

图片来源

可以看到表格布局主要就两种:

  • auto 自动表格布局
  • fixed 固定表格布局

table-layout 默认值就是auto,也就是自动布局,并且只对tableinline-table元素起作用。

布局会影响表格中单元格宽度的渲染,当表格按照指定的布局方式渲染以后,只有了解其中的布局原理,才能知道如何更细粒度的控制表格布局。

以下面这个例子详细了解这个属性:

<html>
<head>
  <title>Table</title>
  <style>
    table {
       border-collapse: collapse;
    }
    tr td,
    tr th {
      border: 1px solid #000;
    }
  </style>
</head>
<body>
  <table>
    <thead>
      <tr>
        <th>name</th>
        <th>age</th>
        <th>sex</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Mary</td>
        <td>20</td>
        <td>male</td>
      </tr>
      <tr>
        <td>June</td>
        <td>15</td>
        <td>male</td>
      </tr>
      <tr>
        <td>Seven</td>
        <td>24</td>
        <td>female</td>
      </tr>
    </tbody>
  </table>
</body>
</html>

自动表格布局

首先自动表格布局table-layout: auto会根据浏览器用户代理,自行实现布局,此时表格的宽度就是所有列宽的和,而且为了确定最终的布局,用户代理会多次访问表格的内容,所以auto布局的效率是比较低的。

auto布局的表格默认长这样,

CSS table-layout 属性揭秘

乍一看,单元格的宽度好像是由其内容所决定的。可以尝试将某个单元格的内容增加:

CSS table-layout 属性揭秘

第一列单元格的宽度也变大了,是不是就说明了auto布局下,单元格的宽度由其内容决定的呢?

现在将第一行第一列的单元格设置一个宽度:

tr:first-child td:first-child {
  width: 50px;
}

CSS table-layout 属性揭秘

这个宽度并没有起作用。但是如果将宽度增加到超过 显示的194px,则该宽度设置就生效了:

CSS table-layout 属性揭秘

所以实际上,auto布局的宽度是由单元格的最小内容宽度所决定,所谓最小内容宽度就是width值为auto时的宽度,如果设置的width大于最小内容宽度,则单元格的宽度才会由width值决定。

那有没有办法强制设置一个小于最小内容宽度的宽度呢?

有。可以使用max-width来设置,还是上面的代码,修改一下:

tr:first-child td:first-child {
  max-width: 50px;
}

CSS table-layout 属性揭秘

成功将第一个单元格宽度设置成了50像素,并且发生了溢出。但是如果将max-width属性设置大于上面说的最小内容宽度,那么表格宽度始终会表现为最小内容宽度

tr:first-child td:first-child {
  max-width: 200px;
}

CSS table-layout 属性揭秘

和上面是一样的。同理,min-width属性应该也是一样的效果:当min-width的值大于194.99像素时,宽度才会被设置为min-width的值,否则就还是最小内容宽度

回到上面溢出的情况,对于溢出,通常的做法要么就是裁剪掉溢出的部分,要么进行换行。可能你会想到white-space属性,但是这里却无法换行,因为white-space属性是针对存在空白符的情况进行换行,这里连续字符换行可以使用work-break: break-all,这也是 antd 中 Table 组件换行配置的属性。

CSS table-layout 属性揭秘

width属性作为盒模型的一部分,paddingborder同样也是盒模型的一部分,但是border却受单元格宽度的约束:

tr:first-child td:first-child {
  padding: 0 50px;
  border-right: 20px solid red;
}

CSS table-layout 属性揭秘

border虽然发生了“溢出”,但是单元格的宽度还是并没有受到其影响,并且这里border的溢出也无法使用overflow来截掉。

最后,如果给 table 元素设置具体的宽度,则宽度会被均分给每一列:

table {
    width: 300px;
}
tr:first-child td:first-child {
  width: 250px;
}

CSS table-layout 属性揭秘

这里设置的250px的单元格并没有生效,但是如果将width属性换成min-widthmax-width,则结果又不一样了:

CSS table-layout 属性揭秘

min-width会打破 table 元素的width设置,但是max-width属性却不会:

CSS table-layout 属性揭秘

可以看到 table 的宽度还是和设置的一样,单元格宽度也发生了变化,但是长度并不是设置的最大宽度50,而是浏览器自动进行了宽度调整。

与此相比较,固定布局table-layout: fixed要简单不少。

固定表格布局

来一个最简单的例子:

table {
  table-layout: fixed;
  border-collapse: collapse;
}

CSS table-layout 属性揭秘

auto布局是一致的,先给 table 元素添加一个宽度:

table {
  table-layout: fixed;
  border-collapse: collapse;
  width: 300px;
}

CSS table-layout 属性揭秘

这里变成了等宽布局,也就是每列是均分300的宽度的。注意到这里给第一个单元格添加了几个单词,表格会自动换行,但是对于连续的字母却不会换行,要想换行的话,还需要work-break属性。

回到上面的CSS,再给单元给添加一个宽度:

tr:first-child td {
  width: 250px;
}

CSS table-layout 属性揭秘

并没有变化?再修改一下:

/* 注意这里单元格的宽度设置在表头上,而不是tbody */
tr:first-child th {
  width: 250px;
}

CSS table-layout 属性揭秘

单元格的设置生效了!

这是 CSS 规范 table-layout 中提到的:当所有列相加得到的宽度,与 table 本身设置的宽度作对比,会取较大值作为表格的最终宽度。这里各列设置的宽度之和已经是大于300,所以最终的宽度应该是 250 * 3。

注意,这里的单元格宽度是由第一行中的单元格所决定,所以上面的例子中,宽度是设置在th元素上,如果设置到td元素上,则该宽度不会起作用。这也是和auto布局一个重要的区别:fixed布局决定单元格宽度的只有第一行,当第一行各列的宽度决定以后,表格就开始进行渲染了,所以布局的速度会更快。

修改一下上面的 CSS:

tr:first-child th:first-child {
  width: 250px;
}

CSS table-layout 属性揭秘

这里就是规范中说到另外一点:表格布局为固定布局时,各列的宽度会由宽度不为auto的值所决定,意思就是第一个单元格的宽度就是设置好的250,剩下的宽度都是默认的auto。如果指定了 table 的宽度,则auto值的列会均分剩下的宽度。

CSS table-layout 属性揭秘

可以看到最后两列宽度为auto的单元格的宽度是一样的。

对于固定布局来说,是否可以使用上面提到的min-widthmax-width呢?这里就直接说答案了,那就是这两个属性在固定布局中并不能改变单元格的宽度,它们就相当于width: auto

至此,对于table-layout的两个属性值,应该会有一个更深的了解。

总结

那么对于开发者来说,使用 table 布局,只需要关注以下两点:

  • 如果对单元格的宽度没有要求,直接使用默认布局就可以了。如果需要在自动布局的情况下,设置单元格的宽度,可以使用min-width结合max-width去实现。

  • 如果单元格的宽度有要求,可以将布局变成固定布局table-layout: fixed,将宽度设置在表头单元格上就能指定各行的宽度了。

参考资料

1.CSS规范之表格宽度算法

原文链接:https://juejin.cn/post/7220775341727318071 作者:qiugu

(0)
上一篇 2023年4月12日 上午10:58
下一篇 2023年4月12日 上午11:09

相关推荐

发表回复

登录后才能评论