如何避免 "Flash of Unstyled Content" 在 CSS 表格中使用固定宽度的单元格?

How can I avoid a "Flash of Unstyled Content" using fixed-width cells in CSS Tables?

我的 Web GUI 布局部分由 CSS table 驱动。这主要是因为 I want the "cells" to have the same height under all situations 对齐没有任何令人头疼的问题。总体而言,这种方法非常成功。

但是,我确实遇到了一个问题,即 table 中的右侧单元格有时需要一些时间来呈现,导致左侧单元格短暂地占页面宽度的 100%。这会导致明显的 "flicker" 效果,虽然很小,但有点烦人。我决定修复它。

以下是我的页面如何工作的模糊表示:

#tbl      { display: table; width: 200px; border: 1px solid black; }
#tbl-row  { display: table-row; }
#tbl-col1,
#tbl-col2 { display: table-cell; }

#tbl-col1 { width: 50px; background-color: red; }
#tbl-col2 { background-color: blue; }
<div id="tbl">
    <div id="tbl-row">
        <div id="tbl-col1">LHS</div>
        <div id="tbl-col2">RHS</div>
    </div>
</div>

一切都很好,直到您使用开发人员工具给 #tbl-col2 一个 display: none 指令,[我希望准确] 模拟浏览器渲染引擎在 [=18] 之间时刻的状态=] 已经渲染,#tbl-col2 正在渲染。

请注意 #tbl-col1 立即占据了 table 宽度的 100%,尽管我给它设置了宽度。我有点理解为什么会这样:毕竟,我已经 要求 浏览器使 div 的行为类似于 table。尽管如此,这里还是不受欢迎。

我试图通过插入 "spacer" 来解决这个问题,希望没有 width 它会扩展以填充右侧的所有 space 直到这样的时间右侧得到渲染:

#tbl      { display: table; width: 200px; border: 1px solid black; }
#tbl-row  { display: table-row; }
#tbl-col1,
#tbl-spc,
#tbl-col2 { display: table-cell; }

#tbl-col1 { width: 50px;  background-color: red; }
#tbl-col2 { width: 150px; background-color: blue; }
<div id="tbl">
    <div id="tbl-row">
        <div id="tbl-col1">LHS</div>
        <div id="tbl-spc"></div>
        <div id="tbl-col2">RHS</div>
    </div>
</div>

正如你再次隐藏 #tbl-col2 所看到的,它并没有造成任何差别:#tbl-col1 仍然占据了 table 的整个宽度,而不是我的 50px允许了。

假设我宁愿解决这个问题也不愿完全放弃 CSS 表格布局,我该怎么办?

或者我是否必须更换布局,或者更糟糕的是,采用 JavaScript 方法来解决 FoUC?

想试试这个 - JS Fiddle

.tbl{display:table;}
.fixed{width: 200px; border: 1px solid black; }
.tblRow { display: table-row; }
.tblCol{ display: table-cell; }
.col1 .tbl { width: 50px;  background-color: red; }
.col2 .tbl { width: 150px; background-color: blue; display:none; }

正如我在评论中所说,玩 table 宽度。所以就在这里。从样式行 .col2 .tbl { width: 150px; background-color: blue; display:none; } 中删除 display:none 以及您能看到的所有内容。这也许就是你想要的。

这是一个合理的解决方案吗?

#tbl      { display: table; width: 200px; border: 1px solid black; }
#tbl-row  { display: flex;  }
#tbl-col1,
#tbl-spc,
#tbl-col2 {
   flex:0;
   overflow:hidden
}

#tbl-col1 { flex-basis: 50px;  background-color: red; }
#tbl-col2 { flex-basis: 150px; background-color: blue; }
<div id="tbl">
    <div id="tbl-row">
        <div id="tbl-col1">LHS-LHS-LHS-LHS</div>
        <div id="tbl-spc"></div>
        <div id="tbl-col2">RHS</div>
    </div>
</div>

编辑:

here's a fiddle 带有前缀和回退

我在类似情况下(例如 html 电子邮件)喜欢做的是使用空单元格以这种方式预定义列宽:

.tbl {
    display: table;
    width: 200px;
    border: 1px solid black;
    color: #fff;
}
.tbl-row {
    display: table-row;
}
.tbl-cell {
    display: table-cell;
}
.tbl-col1 {
    width: 50px;
    background-color: red;
}
.tbl-col2 {
    background-color: blue;
}
<h3>Pre-define columns width by adding additional row</h3>

<div class="tbl">
    <div class="tbl-row tbl-format">
        <div class="tbl-cell tbl-col1"></div>
        <div class="tbl-cell tbl-col2"></div>
    </div>
    <div class="tbl-row">
        <div class="tbl-cell tbl-col1">LHS</div>
        <div class="tbl-cell tbl-col2">RHS</div>
    </div>
</div>

如果单元格内没有内容,该格式列是不可见的,但它仍然告诉浏览器 table 应该格式化的方式。

这是因为,默认情况下,tables 使用 automatic table layout

CSS 2.1 规范没有定义布局模式,但提出了一种(非规范的)算法,它反映了几种流行的 HTML 用户代理的行为。

根据该算法,

If the used width is greater than MIN, the extra width should be distributed over the columns.

但是,它没有解释如何分发它。事实上,您插入 "spacer" 元素的尝试在 Firefox 上完美运行,但在 Chrome.

上却不行

相反,您可能想尝试 fixed table mode,它在规范中正确定义(因此更可靠),通常速度更快,并且也能解决问题:

In the fixed table layout algorithm, the width of each column is determined as follows:

  1. A column element with a value other than auto for the width property sets the width for that column.
  2. Otherwise, a cell in the first row with a value other than auto for the width property determines the width for that column. If the cell spans more than one column, the width is divided over the columns.
  3. Any remaining columns equally divide the remaining horizontal table space (minus borders or cell spacing).

根据第 3 点,间隔元素将在最后一个单元格加载之前接收剩余的 150px。加载后将收到剩余的 0px。

所以你需要

#tbl { table-layout: fixed; }

.tbl {
  display: table;
  table-layout: fixed;
  width: 200px;
  border: 1px solid black;
}
.tbl-row {
  display: table-row;
}
.tbl-col1,
.tbl-spc,
.tbl-col2 {
  display: table-cell;
}
.tbl-col1 {
  width: 50px;
  background-color: red;
}
.tbl-col2 {
  width: 150px;
  background-color: blue;
}
.hide {
  display: none;
}
While parsing the first cell:
<div class="tbl">
  <div class="tbl-row">
    <div class="tbl-col1">LHS</div>
    <div class="tbl-spc hide"></div>
    <div class="tbl-col2 hide">RHS</div>
  </div>
</div>

While parsing the spacer:
<div class="tbl">
  <div class="tbl-row">
    <div class="tbl-col1">LHS</div>
    <div class="tbl-spc"></div>
    <div class="tbl-col2 hide">RHS</div>
  </div>
</div>

While parsing the second cell:
<div class="tbl">
  <div class="tbl-row">
    <div class="tbl-col1">LHS</div>
    <div class="tbl-spc"></div>
    <div class="tbl-col2">RHS</div>
  </div>
</div>

但是,仍然存在一个问题:第一个单元格解析完成后才会显示间隔符。

也就是说spacer必须先加载,但不能最先显示。遗憾的是,CSS table 布局不允许对单元格重新排序。但它可以通过从 HTML 中删除非语义间隔符并使用 ::after 伪元素来实现:

#tbl-row:after {
  content: '';
  display: table-cell;
}

.tbl {
  display: table;
  table-layout: fixed;
  width: 200px;
  border: 1px solid black;
}
.tbl-row {
  display: table-row;
}
.tbl-row:after {
  content: '';
  display: table-cell;
}
.tbl-col1,
.tbl-col2 {
  display: table-cell;
}
.tbl-col1 {
  width: 50px;
  background-color: red;
}
.tbl-col2 {
  width: 150px;
  background-color: blue;
}
.hide {
  display: none;
}
While parsing the first cell:
<div class="tbl">
  <div class="tbl-row">
    <div class="tbl-col1">LHS</div>
    <div class="tbl-col2 hide">RHS</div>
  </div>
</div>

While parsing the second cell:
<div class="tbl">
  <div class="tbl-row">
    <div class="tbl-col1">LHS</div>
    <div class="tbl-col2">RHS</div>
  </div>
</div>