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

引言

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

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

一、需求说明

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

有如下初始代码:

  • 一个自适应的表格
  • 每个单元格的宽度固定 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; 目的是为了留一个内容最多的块, 来将 trtd 撑开, 如果不这么做就会出现下面这种情况:

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

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

第二个方案就是给 tabletrtd 设置一个明确的高度即 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. 修改 tddivbox-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>

完美实现(最终效果):

七、参考

相关推荐
阿成学长_Cain7 分钟前
Linux talk 命令详解:经典终端实时聊天工具,无需图形界面即可对话
linux·运维·前端
lichenyang45319 分钟前
从零开始写 HarmonyOS Web 容器:先让 ArkWeb 加载本地 H5
前端
kyriewen26 分钟前
一个看不见的撇号,让Claude Code追踪了中国开发者三个月
前端·ai编程·claude
莫生灬灬31 分钟前
DY联系人聊天Web面板支持获取联系人/聊天记录/发送消息
前端·chrome·websocket·c#
郑州光合科技余经理39 分钟前
海外外卖平台源码改造实战——多语言核心代码实现
java·开发语言·前端·后端·mysql·架构·php
一tiao咸鱼1 小时前
前端转 agent # 02 - FastAPI 框架入门与原理
前端·python
wanghowie1 小时前
LangGraph4j 落地(二)— ReAct 多步工具与 trace 扩展
前端·react.js·前端框架
大家的林语冰1 小时前
Rust 再次打败 Go,Astro 7 首发,什么叫“万物皆可锈化“!
前端·javascript·性能优化
lichenyang4531 小时前
H5 如何调用 ArkTS:JavaScriptProxy、requestId 和 Promise 回调
前端
lichenyang4531 小时前
我在 HarmonyOS 上写了一个轻量级小程序运行时:从 Web 容器到 JSBridge
前端