设置溢出:在 table 上滚动显示:flex

Setting overflow: scroll on a table with display: flex

我有一个 table 和 display: flex 属性,其单元格将垂直居中。当单元格多于 table 可以显示时,overflow: scroll 属性 不会考虑最上面的单元格。

在下面的示例代码中,滚动在字母 K 处停止,而本应一直滚动到字母 A。这是什么原因造成的?

#container {
  height: 180px;
  display: flex;
  flex-flow: row;
  align-items: stretch;
  border: 1px dashed gray;
}

table {
  display: flex;
  flex-flow: row;
  align-items: center;
  margin: 10px;
  overflow: scroll;
  border: 1px dashed blue;
}

td {
  height: 10px;
  width: 100px;
  border: 1px solid red;
}

#container div {
  flex: 1;
  margin: 10px;
  border: 1px dashed red;
}
<div id="container">
  <table>
    <tr><td>A</td></tr>
    <tr><td>B</td></tr>
    <tr><td>C</td></tr>
    <tr><td>D</td></tr>
    <tr><td>E</td></tr>
    <tr><td>F</td></tr>
    <tr><td>G</td></tr>
    <tr><td>H</td></tr>
    <tr><td>I</td></tr>
    <tr><td>J</td></tr>
    <tr><td>K</td></tr>
    <tr><td>L</td></tr>
    <tr><td>M</td></tr>
    <tr><td>N</td></tr>
    <tr><td>O</td></tr>
    <tr><td>P</td></tr>
    <tr><td>Q</td></tr>
    <tr><td>R</td></tr>
    <tr><td>S</td></tr>
    <tr><td>T</td></tr>
    <tr><td>U</td></tr>
    <tr><td>V</td></tr>
    <tr><td>W</td></tr>
    <tr><td>X</td></tr>
    <tr><td>Y</td></tr>
    <tr><td>Z</td></tr>
  </table>
  <table>
    <tr><td>A</td></tr>
    <tr><td>B</td></tr>
    <tr><td>C</td></tr>
  </table>
  <div></div>
</div>

根据 HTML spec,浏览器必须将 <tr> 元素包装在 <tbody> 元素中,如果没有的话:

<tbody> 的高度将是所有行的高度。但是,<table> 的高度可以更小。这在 table 布局中不是问题,因为 table 的高度将被视为最小高度。

但是,<table> 现在参与了 flex 布局,而不是 table 布局。由于 <tbody> 是一个 table-row-group 元素,其父元素既不是 table 也不是 inline-table(它是 flex),anonymous table 生成了父代。

所以现在我们有一个 <table>,它是一个带有单个 flex 行的 flex 容器,它包含一个 flex 项目(匿名 table)。

flex 行的高度将是 flex 容器的高度 (spec):

If the flex container is single-line and has a definite cross size, the cross size of the flex line is the flex container’s inner cross size.

然后你使用align-items: center。这将垂直对齐弹性线中间的匿名 table(连同 <tbody>),即使它溢出上方或下方。

问题是滚动条允许滚动看到下面溢出的内容,但不能看到上面溢出的内容。

因此,我建议 aligning with auto margins:

而不是 align-items: center

Prior to alignment via justify-content and align-self, any positive free space is distributed to auto margins in that dimension.

注意区别:自动边距仅分配 免费 space,不分配负数。

因此,我们只需要使用

来设置弹性项目的样式
margin: auto 0; /* Push to the center (vertically) */

但是有一个问题:正如上面所解释的,flex item是一个匿名生成的元素,所以我们不能select它与CSS selectors.

要解决这个问题,我们可以将 display: block 添加到 <tbody>。然后,它不会被包裹在任何匿名 table 元素中,因此它将是一个 flex 项目并且对齐会起作用。

请注意,这不会破坏 table,因为 <tr> 的一堆 table-row 将生成一个匿名的 table 父级,但是现在在 <tbody>:

因此您可以使用此代码:

tbody {
  display: block; /* Disable tabular layout, and make <tbody> a flex item */
  margin: auto 0; /* Push to the center (vertically) */
}

#container {
  height: 180px;
  display: flex;
  flex-flow: row;
  align-items: stretch;
  border: 1px dashed gray;
}
table {
  display: flex;
  flex-flow: row;
  margin: 10px;
  overflow: scroll;
  border: 1px dashed blue;
}
tbody {
  display: block; /* Disable tabular layout, and make <tbody> a flex item */
  margin: auto 0; /* Push to the center (vertically) */
}
td {
  height: 10px;
  width: 100px;
  border: 1px solid red;
}
#container div {
  flex: 1;
  margin: 10px;
  border: 1px dashed red;
}
<div id="container">
  <table>
    <tbody>
      <tr><td>A</td></tr>
      <tr><td>B</td></tr>
      <tr><td>C</td></tr>
      <tr><td>D</td></tr>
      <tr><td>E</td></tr>
      <tr><td>F</td></tr>
      <tr><td>G</td></tr>
      <tr><td>H</td></tr>
      <tr><td>I</td></tr>
      <tr><td>J</td></tr>
      <tr><td>K</td></tr>
      <tr><td>L</td></tr>
      <tr><td>M</td></tr>
      <tr><td>N</td></tr>
      <tr><td>O</td></tr>
      <tr><td>P</td></tr>
      <tr><td>Q</td></tr>
      <tr><td>R</td></tr>
      <tr><td>S</td></tr>
      <tr><td>T</td></tr>
      <tr><td>U</td></tr>
      <tr><td>V</td></tr>
      <tr><td>W</td></tr>
      <tr><td>X</td></tr>
      <tr><td>Y</td></tr>
      <tr><td>Z</td></tr>
    </tbody>
  </table>
  <table>
    <tbody>
      <tr><td>A</td></tr>
      <tr><td>B</td></tr>
      <tr><td>C</td></tr>
    </tbody>
  </table>
  <div></div>
</div>

请访问 - https://jsfiddle.net/3y80zqzc/1/

您将观察到 tbody 新添加的 class。 边距参数 是最重要的,它确保内容的垂直中间位置。

margin: auto, 0; /*this is for vertically middle position*/
margin: 0, auto; /*this is for horizontally center position*/

您还可以查看 HTML 代码

<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<style>
#container {
  height: 180px;
  display: flex;
  flex-flow: row;
  align-items: stretch;
  border: 1px dashed gray;
}

table {
  display: flex;
  flex-flow: row;
  align-items: center;
  margin: 10px;
  overflow: scroll;
  border: 1px dashed blue;
}

td {
  height: 10px;
  width: 100px;
  border: 1px solid red;
}

#container div {
  flex: 1;
  margin: 10px;
  border: 1px dashed red;
}
tbody {
  display: block;
  margin: auto 0;
}
</style>
</head>
<body>
<div id="container">
  <table>
    <tr><td>A</td></tr>
    <tr><td>B</td></tr>
    <tr><td>C</td></tr>
    <tr><td>D</td></tr>
    <tr><td>E</td></tr>
    <tr><td>F</td></tr>
    <tr><td>G</td></tr>
    <tr><td>H</td></tr>
    <tr><td>I</td></tr>
    <tr><td>J</td></tr>
    <tr><td>K</td></tr>
    <tr><td>L</td></tr>
    <tr><td>M</td></tr>
    <tr><td>N</td></tr>
    <tr><td>O</td></tr>
    <tr><td>P</td></tr>
    <tr><td>Q</td></tr>
    <tr><td>R</td></tr>
    <tr><td>S</td></tr>
    <tr><td>T</td></tr>
    <tr><td>U</td></tr>
    <tr><td>V</td></tr>
    <tr><td>W</td></tr>
    <tr><td>X</td></tr>
    <tr><td>Y</td></tr>
    <tr><td>Z</td></tr>
  </table>
  <table>
    <tr><td>A</td></tr>
    <tr><td>B</td></tr>
    <tr><td>C</td></tr>
  </table>
  <div></div>
</div>
</body>
</html>