【问题标题】:How to highlight CSS grid cells?如何突出显示 CSS 网格单元格?
【发布时间】:2020-03-31 00:25:30
【问题描述】:

考虑一个 CSS 网格,其中行可以具有可变高度:

.grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-column-gap: 16px;
  grid-row-gap: 8px;
}

.first {
  grid-column: 1 / 3;
  background-color: #ccc;
}

.second {
  grid-column: 5 / 6;
  grid-row: 2 / 5;
  background-color: #ccc;
  height: 120px;
}
<div class="grid">
  <div class="first">First</div>
  <div class="second">Second</div>
</div>

当鼠标悬停在 DevTools 中的网格元素上时,Chrome 会像这样可视化网格:

如何使用 CSS(或 JavaScript,如果需要)实现类似的网格叠加效果?

注意事项:

  1. 应突出显示所有网格单元格,即使网格项不占用它们。
  2. 网格单元格可以具有可变高度(在上面的示例中,第一行高度小于其余行)。

【问题讨论】:

  • @Michael_B 该解决方案似乎不支持可变行高。
  • 对。这不是一个简单的请求,因为 Dev Tool 网格覆盖突出显示了网格的 结构。 CSS 不处理抽象;它为实际元素设置样式。

标签: html css css-grid


【解决方案1】:

使用 JS 的一个想法是读取 grid-template-columnsgrid-template-rows 的计算值,以便在已填充占位符元素的网格之上创建另一个网格。

这是一个基本示例。您应该更新悬停时的值,因为getComputedStyle 将返回像素值:

var grid = document.querySelector('.grid');
var overlay = document.createElement("div");
overlay.className = 'overlay';
overlay.style.gridTemplateRows = window.getComputedStyle(grid, null).getPropertyValue("grid-template-rows");
overlay.style.gridTemplateColumns = window.getComputedStyle(grid, null).getPropertyValue("grid-template-columns");
grid.appendChild(overlay);

/* Get the number of items*/
var Nc = overlay.style.gridTemplateColumns.split(" ").length;
var Nr = overlay.style.gridTemplateRows.split(" ").length;
/* Create placeholder items*/
for (var i = 0; i < Nc * Nr; i++) {
  var d = document.createElement("div");
  overlay.appendChild(d);
}

/* Update the values on hover*/
grid.addEventListener('mouseover', function() {
  overlay.style.gridTemplateRows = window.getComputedStyle(grid, null).getPropertyValue("grid-template-rows");
  overlay.style.gridTemplateColumns = window.getComputedStyle(grid, null).getPropertyValue("grid-template-columns");
})
.grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-column-gap: 16px;
  grid-row-gap: 8px;
  position: relative;
  overflow:hidden;
}

.first {
  grid-column: 1 / 3;
  background-color: #ccc;
}

.second {
  grid-column: 5 / 6;
  grid-row: 2 / 5;
  background-color: #ccc;
  height: 120px;
}

.overlay {
  position: absolute;
  display: grid;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  grid-gap: inherit;
  opacity: 0;
  pointer-events: none;
}

.overlay>* {
  border: 1px dotted;
  background: rgba(0, 125, 0, 0.4);
}

.grid:hover .overlay {
  opacity: 1;
}
<div class="grid">
  <div class="first">First</div>
  <div class="second">Second</div>
</div>

【讨论】:

  • 谢谢!您能否解释一下“您应该在悬停时更新值,因为 getComputedStyle 将返回像素值”是什么意思?
  • @MishaMoroshko getComputedStyle 将根据屏幕大小返回实际值。例如,如果您使用1fr 定义模板,您将不会得到1fr,但考虑到您的1fr 的像素值实际屏幕大小,因此如果您更改屏幕大小,则需要再次获取新值。您可以检查元素以查看模板是使用像素值定义的。我说您需要在悬停时更改此设置,但您也可以在屏幕调整大小时进行更改,但在悬停时更好,因此您仅在需要时才进行计算。
  • 假设行数和列数不会改变,我们可以给覆盖网格项一个grid-row和一个grid-column,而不是在网格上设置grid-template-rowsgrid-template-columns。这样你就不需要重新计算窗口大小了,对吧?
  • @MishaMoroshko 不,如果您有正确数量的项目,则不需要设置 grid-row/column,因为它们会自动放置以填充所有网格单元格。您将始终需要获取 grid-template-* 的值,但如果您知道可以使用的模板 inherit 。示例:jsfiddle.net/Ltavbncr/2 .. 在这里我考虑到您将模板列定义为具有 8 个元素的事实,因此我可以继承它并且不需要计算它,但我需要为行执行它,因为它是动态的并且基于在你的元素上
  • 谢谢,有道理!小问题:overflow: hidden 在网格上的重要性是什么?
【解决方案2】:

为每个网格单元创建元素:

const grid = document.getElementsByClassName("grid")[0];

const rows = 4;
const cols = 8;

for (let r = 1; r <= rows; r++) {
    for (let c = 1; c <= cols; c++) {
        const h = document.createElement("div");
        h.classList.add("highlight");
        h.style.gridRow = r;
        h.style.gridColumn = c;
        grid.appendChild(h);
    }
}

(这也可以在服务器端完成)

并设置它们的样式:

.highlight {
  z-index: 1;
  border: 1px dashed blue;
  background: #0000FF44;
}

仅在悬停时显示它们:

.highlight {
    display: none;
}

.grid:hover > .highlight {
    display: block;
}

【讨论】:

  • 这种方法如何与现有的网格项目一起使用?
  • 它会忽略它们。网格显示允许单个“单元格”中的多个元素而不会相互干扰。它们相互重叠。这就是z-index 的用途:确定绘制顺序。