﻿---
title: HTML Table Overflow Issues
date: 2026-01-15
excerpt: Discover a simple CSS technique to keep HTML tables within their containers by controlling layout and text wrapping.
tags:
  - CSS
  - JavaScript
  - UIUX
---

**「Blog CSS 样式修缮」**  Part Ⅱ，记录一些常见的博客样式问题及其解决方案。

1.  [[page_scroll|Fix Markdown Footnote Jump Overlap with CSS scroll-margin-top]]
2. [[html-tables-overflow|Fix HTML Tables from Becoming Too Wide]]

## Problem

在移动端或侧边栏等窄屏场景下，屏幕空间非常有限。

默认情况下，当单元格内包含不可换行的长内容（如 URL 链接、长代码）时，表格会忽略父容器的宽度限制，强制撑大容器，导致出现意外的横向滚动条。

## CSS Tricks 🎪

下面的示例中，会将表格放置在一个宽度仅为 `150px` 的`.page`容器内，表格内容为一个长 URL 链接（约170px宽），以展示不同布局下的表现。应用的 CSS 如下：

```css
.page {
  width: 150px;
  border: solid 2px var(--mauve);
  margin: 1em auto;
  table {
    font-size: 1em;
    width: 100%;
    th, td {
      padding: 1em;
    }
  }
}
```

<style>
.page {
  width: 150px;
  border: solid 2px var(--mauve);
  margin: 1em auto;
  color: var(--text);
  table {
    font-size: 1em;
    width: 100%;
    th, td {
        padding: 1em;
    }
  }
}
</style>

### Auto Layout & Word Break

首先展示的是默认的自动布局，即`{css} table { table-layout: auto }`。浏览器会根据内容自动调整列宽[^1]。对于该`2*1`表格来说，列宽由第二行的`https://gallery.vluv.space`决定，约为`170px`，因此表格宽度直接溢出父容器。

<div class="page">
    <table data-nowrap="true">
        <tr>
            <th>Gallery Link</th>
        </tr>
        <tr>
            <td>https://gallery.vluv.space</td>
        </tr>
    </table>
</div>

一个简单的wordaround，设置`word-break`[^2]为 `break-all`，这样URL链接虽然作为一整个单词，但也会进行换行处理，避免撑大表格宽度。

Ok，将表格标签改为`{html} <table style="word-break: break-all" data-nowrap="true">`，效果如下:

<div class="page">
    <table style="word-break: break-all" data-nowrap="true">
        <tr>
            <th>Gallery Link</th>
        </tr>
        <tr>
            <td>https://gallery.vluv.space</td>
        </tr>
    </table>
</div>

但是，如果将`.page`容器宽度进一步缩小到`40px`，同时把字体大小调大到`2em`，那么表格依然会溢出容器宽度;不过这种场景也不多见，一个可能的例子是：在手机端查看一个列数非常多的表格

<div class="page" style="width: 40px; font-size: 2em">
    <table style="word-break: break-all" data-nowrap="true">
        <tr>
            <th>G</th>
        </tr>
    </table>
</div>

### Fixed Layout?

对于table溢出容器的问题，StackOverflow 上的经典方案是为表格设置 `{css} table-layout: fixed` ，同时设置 `width: 100%`（即父容器宽度）

使用 `table-layout: fixed` 后，表格严格遵循 `width: 100%`（即父容器宽度）

<div class="page" style="border-color: var(--mauve);">
    <table style="table-layout: fixed" data-nowrap="true">
        <tr>
            <th>Gallery Link</th>
        </tr>
        <tr>
            <td>https://gallery.vluv.space</td>
        </tr>
    </table>
</div>

但这个方案的效果，我认为与`auto + word-break: all`类似，参考下面的效果，单个字符依然无法在`40px`宽度内完整显示，表格依然溢出容器宽度。

<div class="page" style="width: 40px; font-size: 2em; border-color: var(--mauve);">
    <table style="table-layout: fixed; word-break: break-all" data-nowrap="true">
        <tr>
            <th>G</th>
        </tr>
    </table>
</div>

此外，如果没为各列指定宽度，`table-layout: fixed` 会使各列等宽，要得到更协调的布局，那么就得费心为各列指定宽度，这在实际应用中并不方便。

> In the fixed table layout algorithm, the width of each column is determined in this priority:
>
> 1. A column element (`<col>`) with explicit width.
> 2. A cell in the **first row** with explicit width.
> 3. Otherwise, the shared remaining horizontal space.

<div style="width: 400px; max-width: 80%; border: 1px dashed var(--mauve); padding: 10px; margin: 1em auto;">
  <p style="margin: 0 0 5px; font-weight: bold;">1. table-layout: fixed</p>
  <table style="width: 100%; table-layout: fixed; border-collapse: collapse;">
    <tr>
      <td style="border: 1px solid var(--blue); padding: 4px;">1</td>
      <td style="border: 1px solid var(--blue); padding: 4px;">User</td>
      <td style="border: 1px solid var(--blue); padding: 4px;">这是一段非常长的描述文本，在Fixed模式下会被强制压缩到和序号列一样宽。</td>
    </tr>
  </table>

  <p style="margin: 15px 0 5px; font-weight: bold;">2. table-layout: auto</p>
  <table style="width: 100%; table-layout: auto; border-collapse: collapse;">
    <tr>
      <td style="border: 1px solid var(--green); padding: 4px;">1</td>
      <td style="border: 1px solid var(--green); padding: 4px;">User</td>
      <td style="border: 1px solid var(--green); padding: 4px;">这是一段非常长的描述文本，在Auto模式下会自动占据剩余的绝大部分空间。</td>
    </tr>
  </table>
</div>

### JavaScript Solution

前面用默认布局配置 `all-break` 可以防止溢出，但在某些场景下（例如展示代码片段、URL），强制换行看起来并不美观。

前面提到表格撑大容器，出现横向滚动条。在滚动查看表格时，容器内的其他内容（标题、按钮、文字）也会跟着一起向左滚动，影响阅读体验。

解决办法也比较简单：为表格单独包一层容器，当表格宽度超出该容器时，容器出现横向滚动条即可。

```js
document.querySelectorAll(".content table").forEach((table) => {
  if (table.hasAttribute("data-nowrap") || table.parentElement.classList.contains('table-wrapper')) {
    return;
  }
  // if width exceeds container, wrap it
  const wrapper = document.createElement("div");
  Object.assign(wrapper.style, {
    width: "100%",
    overflowX: "auto",
  });
  table.parentNode.insertBefore(wrapper, table);
  wrapper.appendChild(table);
});
```

<div style="display: flex; justify-content: space-between; align-items: flex-start; width: 400px; max-width: 80%; margin: 1em auto;">
  <div style="flex: 1;">
    <div class="page" style="border-color: var(--yellow);">
        <table>
            <tr>
                <th>Gallery Link</th>
            </tr>
            <tr>
                <td>https://gallery.vluv.space</td>
            </tr>
        </table>
    </div>
  </div>
  <div style="flex: 1;">
    <div class="page" style="width: 40px; font-size: 2em; border-color: var(--yellow);">
    <table>
        <tr>
            <th>G</th>
        </tr>
    </table>
    </div>
  </div>
</div>

[^1]: The automatic table layout algorithm is used. The widths of the table and its cells are adjusted to fit the content. Most browsers use this algorithm by default.
[^2]: The word-break CSS property sets whether line breaks appear wherever the text would otherwise overflow its content box. [word-break - CSS | MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/word-break)