CSS 技巧:如何让 div 完美填充 td 高度

引言

一天哈比比突然冒出一个毫无理头的一个问题:

本文就该问题进行展开...

原文链接: 昆仑虚F2E

一、需求说明

大致需求如下, 当然这里做了些简化

有如下初始代码:

  • 一个自适应的表格
  • 每个单元格的宽度固定 200px
  • 每个单元格高度则是自适应
  • 每个单元格内是一个 div 标签, div 标签内包裹了一段文本, 文本内容不定

下面是初始代码(为了方便演示和美观, 代码中还加了些背景色、边距、圆角, 这些都是可以忽略):

html 复制代码
<table>
  <tr>
    <td width="400">
      <div>
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
      </div>
    </td>
    <td width="400">
      <div>
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
      </div>
    </td>
    <td width="400">
      <div>
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
      </div>
    </td>
  </tr>
</table>
<style>
  table {
    background: #f5f5f5;
  }
  
  td {
    background: #ffccc7;
  }

  table, tr, td {
    padding: 12px;
    border-radius: 4px;
  }

  td > div {
    padding: 12px;
    border-radius: 4px;
    background: #f4ffb8;
  }
</style>

上面代码的整体效果如下:

上面是哈比比目前的现状, 然后需求就是希望, 黄色部分也就是 div 标签能够高度撑满单元格(td), 也就是如下图所示:

二、关键问题

这里我第一反应就是, 既然 td 高度是对的(自适应)的那么 div 高度直接设置 100% 不就好了吗? 事实是这样的吗? 我们可以试下:

diff 复制代码
<table>
  ...
</table>
<style>
  td > div {
+   height: 100%; 
  }
</style>

实际效果肯定是没有用的, 要不然也就不会有这篇文章了 🐶🐶🐶

主要问题: 在 CSS 中如果父元素没有一个明确的高度, 子元素设置 100% 是无法生效的, 至于为啥就不能生效呢, 因为如果可以, 那么必然会进入死循环这里可以参考张鑫旭大大的文章《从 height:100% 不支持聊聊 CSS 中的 "死循环"》

三、方案一(定位)

通过定位来实现, 也是哈比比最初采用的一个方案:

  • td 设置相对定位即: position: relative;
  • td 下的子元素通过相对定位(position: absolute;)撑满
diff 复制代码
....
<style>
  ...
+ td {
+   position: relative;
+ }

+ td:not(:first-child) > div {
+   position: absolute;
+   inset: 0;
+ }
</style>

整体效果如下:

上面代码其实我并没有给所有 td 中的 div 设置 position: absolute; 目的是为了留一个内容最多的块, 来将 tr、 td 撑开, 如果不这么做就会出现下面这种情况:

所以, 严格来说该方案是不行的, 但是可能哈比比情况比较特殊, 他只有空值和有内容两种情况, 所以他完全可以通过判断内容是否为空来设置 position: absolute; 即可

四、方案二(递归设置 height 100%)

第二个方案就是给 table、tr、td 设置一个明确的高度即 100%, 这样的话 td 中的子元素 div 再设置高度 100% 就可以生效了

diff 复制代码
<style>
+ table, tr, td, td > div {
+   height: 100%;
  }
</style>

效果如下:

上面第一个单元格高度其实还是有点问题, 目前也没找到相关研究可以结束这个现象, 要想达到我们要的效果解决办法有两个:

  1. 移除代码中所有 padding, 有关代码和效果图如下:
diff 复制代码
<style>
  table, tr, td {
-   padding: 12px;
  }
  td > div {
-   padding: 12px;
  }
</style>
  1. 修改 td 中 div 的 box-sizing 属性为 border-box, 有关代码和效果图如下:
diff 复制代码
<style>
  ...
  td > div  {
+   box-sizing: border-box;
  }
</style>

五、方案三(利用 td 自增加特效, 推荐)

方案三是比较推荐的做法, 其利用了 td 自增加的一个特效, 那么何谓自增加呢? 假设我们给 td 设置可一个高度 1px 但是呢它实际高度实际上是会根据 tr 的高度进行自适应(自动增长), 那么在这种情况下我们给 td 下子元素 div 设置高度 100% 则会奏效, 因为这时的 td 高度是明确的

html 复制代码
<table>
  <tr>
    <td width="400">
      <div>
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
      </div>
    </td>
    <td width="400">
      <div>
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
      </div>
    </td>
    <td width="400">
      <div>
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
      </div>
    </td>
  </tr>
</table>
<style>
  table {
    background: #f5f5f5;
  }
  
  td {
    height: 1px; /* 关键代码 */
    background: #ffccc7;
  }

  table, tr, td {
    padding: 12px;
    border-radius: 4px;
  }

  td > div {
    height: 100%; /* 关键代码 */
    padding: 12px;
    border-radius: 4px;
    background: #f4ffb8;
  }
</style>

效果如下:

六、补充: td 下 div 内容顶对齐

几天后, 哈比比又来找我了 🐶🐶🐶

这次需求就比较简单了, 就是 td 中默认情况下子元素(p)都是居中呈现的, 现想要的就是能否居上(置顶)展示

这里初始代码和上面是一样的:

html 复制代码
<table>
  <tr>
    <td width="400">
      <div>
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
      </div>
    </td>
    <td width="400">
      <div>
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
      </div>
    </td>
    <td width="400">
      <div>
        路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面路由器管理页面
      </div>
    </td>
  </tr>
</table>
<style>
  table {
    background: #f5f5f5;
  }
  
  td {
    background: #ffccc7;
  }

  table, tr, td {
    padding: 12px;
    border-radius: 4px;
  }

  td > div {
    padding: 12px;
    border-radius: 4px;
    background: #f4ffb8;
  }
</style>

默认效果就是 div 都居中展示:

这里我第一反应是用 vertical-align 但是该属性在很多人印象中只针对 行内元素(或文本)才能生效, 但这里是 div 是 块元素 所以哈比比自然就忽略了该 vertical-align 属性

但实际上如果查阅文档会发现 vertical-align 实际用途有两个:

  1. 用来指定行内元素(inline)的垂直对齐方式
  2. 表格单元格(table-cell)元素的垂直对齐方式

所以这个问题就简单了, 一行 CSS 就解决了:

diff 复制代码
<style>
  ...
  td {
+   vertical-align: top;
  }
</style>

完美实现(最终效果):

七、参考


相关推荐
回眸&啤酒鸭2 小时前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户69371750013842 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员2 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端
小兔子2 小时前
Python 的 GIL 与 free-threading:3.13 之后「去 GIL」走到哪一步了
前端
IT_陈寒3 小时前
SpringBoot自动配置差点让我加班到凌晨
前端·人工智能·后端
袁哥大话安全3 小时前
巡隐WEBSHELL扫描软件
人工智能·安全·web
guslegend4 小时前
脚手架原理与本地调试:从 bin 软链接到 npm link
前端·npm·node.js·脚手架·前端工程化
小宋10214 小时前
A2UI从零实战:Agent安全生成交互界面与事件回传
javascript·人工智能·安全·交互
大包子4 小时前
structuredClone vs lodash.cloneDeep:核心差异与选型指南
javascript·vue.js
海码事务所4 小时前
Google Play 新个人开发者账号上架指南:12 人连续 14 天封闭测试怎么做?
前端