【问题标题】:What are some good work arounds to deal with the "Visiblility: Collapse" bug in Mozilla Firefox?处理 Mozilla Firefox 中的“可见性:折叠”错误有哪些好的解决方法?
【发布时间】:2022-01-07 09:31:57
【问题描述】:

处理 Mozilla Firefox 中的“可见性:折叠”错误有哪些好的解决方法?

上下文:

我在 cmets 的朋友告诉我有一个旧的 Firefox 错误导致 "visibility: collapse" CSS 属性像 “可见性:隐藏” CSS 属性。这会导致表格完全变大,所有可见列都向左移动,额外的空间向右移动。

对于较大的表,这种不良行为更加严重。

我只是希望能够切换表格列的可见性并让它在 Chrome、Edge 和 Firefox 上看起来相同,这导致了我的问题:处理“可见性:折叠”有哪些好的解决方法" Mozilla Firefox 中的错误?

代码:

这是小提琴:

https://jsfiddle.net/jado66/pgyLm86e/18/

这是小提琴中的代码:

<html lang="en">
<head>
    <meta charset="utf-8">
    <style>
        th{
            border-bottom: 1px solid grey;
        }
        td{
            text-align: center;
        }
        col{
            border: 1px solid grey;
            width: 55px;
        }
    </style>
</head>
<body>
    <div style="text-align: center;">
        <table style="margin: auto; border: 1px solid black; border-spacing: 0; border-collapse: collapse;">
            <colgroup>
                <col id = "col_1">
                <col id = "col_2">
                <col id = "col_3">
                <col id = "col_4" style="visibility: collapse">
                <col id = "col_5" style="visibility: collapse">
                <col id = "col_6">
            </colgroup>
            <tr>
                <th>Col 1</th>
                <th>Col 2</th>
                <th>Col 3</th>
                <th>Col 4</th>
                <th>Col 5</th>
                <th>Col 6</th>
            </tr>
            <tr>
                <td>1.1</td>
                <td>1.2</td>
                <td>1.3</td>
                <td>1.4</td>
                <td>1.5</td>
                <td>1.6</td>
            </tr>
        </table>
    </div>
</div> 
</body>
</html>

【问题讨论】:

  • 从技术上讲,visibility 属性正在工作;否则,将显示第 4 列和第 5 列的值。 工作的是让表格边框缩小以考虑隐藏列。
  • 可能与18年前关闭的this ancient bug有关。
  • 是的,我在写那个错误@Richard Deeming,显然还在那里,好吧。显然该错误与列有关而不与列组有关,现在它倒置了,与列组有关而不与列有关,所以您必须找到另一种方法,因为我不知道是否有方法保持表格的动态宽度结构如下。
  • 找到它:819045 - table element borders draw incorrectly when col has visibility: collapse - 仍然开放,上次更新是 5 年前。
  • 表格布局长期以来一直在浏览器制造商中享有盛誉,就像一袋松动的手榴弹。最好单独留下。然而,Chromium 引入了 TablesNG,这是一种新的实现,据说对所有涉及的规则都有更详尽的文档。希望这将反馈到 CSS 表格标准中,并且在适当的时候,我们不仅会修复此类长期存在的错误,还会对 CSS 中非常被忽视的部分进行一些有用的扩展。

标签: html css firefox


【解决方案1】:

如果我们在开发者工具中观察,我们会看到 colgroup 溢出。因此,如果我们在 table 上剪辑溢出,它会剪辑一些额外的部分。如果我们稍微增加折叠列的宽度,它就会完美地剪辑:

var c4, c5;

function toggle() {
  c4.classList.toggle('collapsed');
  c5.classList.toggle('collapsed');
}

function init() {
  c4 = document.querySelector('#col_4');
  c5 = c4.nextElementSibling;
}
:root {
  --col-width: 55px;
}

th {
  border-bottom: 1px solid grey;
}

td {
  text-align: center;
}

col {
  border: 1px solid grey;
  width: var(--col-width);
}

/* clip the overflow */
table {
  overflow: clip;
}

.collapsed {
  visibility: collapse;
  /* need to increase width slightly to make it work */
  /* some how addition doesn't work */
  width: calc(var(--col-width) * 1.2);
}
<html lang="en">

<body onload="init()">
 <p>View this in Firefox browser</p>
  <div style="text-align: center;">
    <table style="margin: 0 auto;border: 1px solid black; border-spacing: 0; border-collapse: collapse;">
      <colgroup>
        <col id="col_1">
        <col id="col_2">
        <col id="col_3">
        <col id="col_4" class="collapsed">
        <col id="col_5" class="collapsed">
        <col id="col_6">
      </colgroup>
      <tr>
        <th>Col 1</th>
        <th>Col 2</th>
        <th>Col 3</th>
        <th>Col 4</th>
        <th>Col 5</th>
        <th>Col 6</th>
      </tr>
      <tr>
        <td>1.1</td>
        <td>1.2</td>
        <td>1.3</td>
        <td>1.4</td>
        <td>1.5</td>
        <td>1.6</td>
      </tr>
    </table>
  </div>

  <div style="width: min-content; background-color: wheat; margin: 0 auto;;">mid</div>
  <button onclick="toggle()">Toggle collapse</button>
</body>

</html>

但这不会使内容居中。折叠的col 仍然有助于宽度。 如果我们添加一个 div 包装器并设置它的宽度(表格宽度 - 折叠宽度),那么它可能会起作用:

var c4, c5;

function toggle() {
  c4.style.visibility = c5.style.visibility = window.getComputedStyle(c4).visibility === 'collapse' ? '' : 'collapse';
}

function init() {
  c4 = document.querySelector('#col_4');
  c5 = c4.nextElementSibling;
  resize();

  //observe style change
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutationRecord) {
      resize();
    });
  });
  observer.observe(c4, {
    attributes: true,
    attributeFilter: ['style']
  });
}

//subtract collapsed width from wrapper
function resize() {
  var colgroup = document.querySelector('colgroup');
  var actualWidth = colgroup.offsetWidth;
  var reducedWidth = 0;

  for (var i = 0, len = colgroup.childElementCount; i < len; ++i) {
    var col = colgroup.children[i];
    if (window.getComputedStyle(col).visibility == 'collapse') {
      reducedWidth += col.offsetWidth;
    }
  }
  console.log(actualWidth + ' reduced by ' + reducedWidth);
  var wrapper = document.querySelector('#wrapper');
  wrapper.style.width = (actualWidth - reducedWidth) + 'px';
}
th {
  border-bottom: 1px solid grey;
}

td {
  text-align: center;
}

col {
  border-right: 1px solid grey;
  width: 55px;
}


/* added styles */

col:last-child {
  border-right: none;
}

table {
  width: max-content;
  overflow-y: hidden;
}

#wrapper {
  border: 1px solid;
  width: max-content;
  overflow: hidden;
  margin: 0 auto;
}
<html lang="en">

<body onload="init()">
  <p>View this in Firefox browser.</p>
  <div id=wrapper style="text-align: center;">
    <table style="margin: auto; border-spacing: 0; border-collapse: collapse;">
      <colgroup>
        <col id="col_1">
        <col id="col_2">
        <col id="col_3">
        <col id="col_4" style="visibility: collapse">
        <col id="col_5" style="visibility: collapse">
        <col id="col_6">
      </colgroup>
      <tr>
        <th>Col 1</th>
        <th>Col 2</th>
        <th>Col 3</th>
        <th>Col 4</th>
        <th>Col 5</th>
        <th>Col 6</th>
      </tr>
      <tr>
        <td>1.1</td>
        <td>1.2</td>
        <td>1.3</td>
        <td>1.4444444</td>
        <td>1</td>
        <td>1.6</td>
      </tr>
    </table>
  </div>
  <div style="width: min-content; background-color: wheat; margin: 0 auto;;">mid</div>
  <button onclick="toggle()">Toggle collapse</button>
</body>

</html>

有了这个,我们使用包装器 div 隐藏折叠的部分。

如果要水平滚动表格,则需要为滚动添加一个包装器:

<html lang="en">

<head>
  <meta charset="utf-8">
  <script>
    var c4, c5;

    function toggle() {
      c4.style.visibility = c5.style.visibility = window.getComputedStyle(c4).visibility === 'collapse' ? '' : 'collapse';
    }

    function init() {
      c4 = document.querySelector('#col_4');
      c5 = c4.nextElementSibling;
      resize();

      //observe style change
      var observer = new MutationObserver(function (mutations) {
        mutations.forEach(function (mutationRecord) {
          resize();
        });
      });
      observer.observe(c4, {
        attributes: true,
        attributeFilter: ['style']
      });
    }

    //subtract collapsed width from wrapper
    function resize() {
      var colgroup = document.querySelector('colgroup');
      var actualWidth = colgroup.offsetWidth;
      var reducedWidth = 0;

      for (var i = 0, len = colgroup.childElementCount; i < len; ++i) {
        var col = colgroup.children[i];
        if (window.getComputedStyle(col).visibility == 'collapse') {
          reducedWidth += col.offsetWidth;
        }
      }
      console.log(actualWidth + ' reduced by ' + reducedWidth);
      var wrapper = document.querySelector('#wrapper');
      wrapper.style.width = (actualWidth - reducedWidth) + 'px';
    }
  </script>
  <style>
    th {
      border-bottom: 1px solid grey;
    }

    td {
      text-align: center;
    }

    col {
      border-right: 1px solid grey;
      width: 55px;
    }


    /* added styles */

    col:last-child {
      border-right: none;
    }

    table {
      width: max-content;
      overflow-y: hidden;
    }

    #wrapper {
      border: 1px solid;
      width: fit-content;
      overflow: hidden;
      margin: 0 auto;
    }

    #scrollMe {
      width: 300px;
      overflow-x: auto;
      margin: 0 auto;
      border: 1px solid lime
    }

  </style>

  </style>
</head>

<body onload="init()">
  <p>View this in Firefox browser.</p>
  <div id="scrollMe">
    <div id=wrapper style="text-align: center;">
      <table style="margin: auto; border-spacing: 0; border-collapse: collapse;">
        <colgroup>
          <col id="col_1">
          <col id="col_2">
          <col id="col_3">
          <col id="col_4" style="visibility: collapse">
          <col id="col_5" style="visibility: collapse">
          <col id="col_6">
        </colgroup>
        <tr>
          <th>Col 1</th>
          <th>Col 2</th>
          <th>Col 3</th>
          <th>Col 4</th>
          <th>Col 5</th>
          <th>Col 6</th>
        </tr>
        <tr>
          <td>1.1</td>
          <td>1.2</td>
          <td>1.3</td>
          <td>1.4444444</td>
          <td>1</td>
          <td>1.6</td>
        </tr>
      </table>
    </div>
  </div>
  <div style="width: min-content; background-color: wheat; margin: 0 auto;;">mid</div>
  <button onclick="toggle()">Toggle collapse</button>
</body>

</html>


注意:这些只是解决方法。

【讨论】:

  • 我刚刚注意到这在可变列宽下效果不佳。如果您添加更多列并更改宽度,则很容易看出这是如何中断的。 jsfiddle.net/jado66/w673pbge/1
  • 我认为最安全的选择是更改每个受影响的单元格。如何将赏金转移到@herrstrietzel?
  • 你可以在这个问题上打赏,奖励给他。我认为你应该保留它。你也辛苦了!
【解决方案2】:

正如 @Richard Deeming 所指出的,此渲染问题与 border-collapse: collapse; 属性有关。

如果你可以不用它并且居中也可以忽略 - 从表中删除 border-collapse: collapse; 属性可能是一种有效的折衷方案。

function hideColumn(columns) {
  columns.forEach(function(num, i) {
    columns[i] = "#col_" + columns[i];
  });
  let selectors = columns.join(", ");
  // reset previously hidden
  let hidden = document.querySelectorAll(".collapsed-col");
  hidden.forEach(function(el) {
    el.classList.remove("collapsed-col");
  });
  // hide cells by class
  let cells = document.querySelectorAll(selectors);
  cells.forEach(function(item, i) {
    item.classList.add("collapsed-col");
  });
}


// test input
let inputHideColumns = document.querySelector(".inputHideColumns");
inputHideColumns.addEventListener("change", function(e) {
  let value = e.target.value.replaceAll(", ", ",");
  let columns = value.split(",");
  hideColumn(columns);
});
.collapsed-col {
  visibility: collapse;
}

table {
  border-spacing: 0;
  /*
  border-collapse: collapse;
  margin: auto; 
  */
  border: 1px solid black;
  table-layout: fixed;
}

th {
  border-bottom: 1px solid grey;
}

td {
  text-align: center;
}
<body>
  <div style="text-align: center;">
    <table>
      <colgroup>
        <col id="col_1">
        <col id="col_2">
        <col id="col_3">
        <col id="col_4" class="collapsed-col">
        <col id="col_5" class="collapsed-col">
        <col id="col_6">

      </colgroup>
      <tr>
        <th>Col 1</th>
        <th>Col 2</th>
        <th>Col 3</th>
        <th>Col 4</th>
        <th>Col 5</th>
        <th>Col 6</th>
      </tr>
      <tr>
        <td>1.1</td>
        <td>1.2</td>
        <td>1.3</td>
        <td>1.4</td>
        <td>1.5</td>
        <td>1.6</td>
      </tr>
      <tr>
        <td>2.1</td>
        <td>2.2</td>
        <td>2.3</td>
        <td>2.4</td>
        <td>2.5</td>
        <td>2.6</td>
      </tr>
    </table>
  </div>

  <p>
    <label>hide columns (comma seperated)</label>
    <input class="input inputHideColumns" type="text" placeholder="hide columns (comma seperated)" value="5,4">
  </p>

  </div>

另一种方法可能是根据列对每个 th/td 应用“collapsed-col”类。

这种方法需要您的 thtd 元素具有专用的列类,例如 col_1col_2 等。

function indexColumns(table) {
  let rows = table.querySelectorAll("tr");
  rows.forEach(function (row, r) {
    let cols = row.querySelectorAll("th, td");
    cols.forEach(function (col, c) {
      col.classList.add("tr_" + r);
      col.classList.add("col_" + (c + 1));
    });
  });
}

function hideColumn(columns) {
  columns.forEach(function (num, i) {
    columns[i] = ".col_" + columns[i];
  });
  let selectors = columns.join(", ");
  // reset previously hidden
  let hidden = document.querySelectorAll(".collapsed-col");
  hidden.forEach(function (el) {
    el.classList.remove("collapsed-col");
  });
  // hide cells by class
  let cells = document.querySelectorAll(selectors);
  cells.forEach(function (item, i) {
    item.classList.add("collapsed-col");
  });
}

// index th/td elements by setting class 
let table = document.querySelector('table');
indexColumns(table);
hideColumn([4, 5]);

// test input
let inputHideColumns = document.querySelector(".inputHideColumns");
inputHideColumns.addEventListener("change", function (e) {
  let value = e.target.value.replaceAll(", ", ",");
  let columns = value.split(",");
  hideColumn(columns);
});
.layout {
  width: 50%;
  margin: 0 auto;
}

table {
  border-spacing: 0;
  border-collapse: collapse;
  margin: auto;
  border: 1px solid black;
}

th {
  border-bottom: 1px solid grey;
}

td {
  text-align: center;
}


.collapsed-col {
  display: none;
}
<body>
  <div class="layout">
    <div class="table-wrap">
      <table>
        <thead>
          <tr>
            <th>Col 1</th>
            <th>Col 2</th>
            <th>Col 3</th>
            <th>Col 4</th>
            <th>Col 5</th>
            <th>Col 6</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>1.1</td>
            <td>1.2</td>
            <td>1.3</td>
            <td>1.4</td>
            <td>1.5</td>
            <td>1.6</td>
          </tr>
          <tr>
            <td>2.1</td>
            <td>2.2</td>
            <td>2.3</td>
            <td>2.4</td>
            <td>2.5</td>
            <td>2.6</td>
          </tr>
        </tbody>

      </table>
    </div>
    <p>
      <label>hide columns (comma seperated)</label>
      <input class="input inputHideColumns" type="text" placeholder="hide columns (comma seperated)" value="5,4">
    </p>
  </div>

【讨论】:

  • 我希望我能接受这两个答案!
  • 在对两个答案进行额外测试后,我选择接受这个答案。这个答案更具可扩展性,并且适用于不同大小的列。希望我也能给你赏金。
  • 这个解决方案不依赖于 或 也让我感到欣慰
猜你喜欢
  • 1970-01-01
  • 2010-11-05
  • 2014-09-07
  • 1970-01-01
  • 2010-10-23
  • 2014-07-22
  • 2017-01-15
  • 2013-02-13
  • 2011-09-12
相关资源
最近更新 更多