开发者工具中的 CSS 网格工具

Changhao Han
Changhao Han

为什么要开发 CSS 网格工具?

CSS 网格是一款功能强大的 CSS 布局系统,可让 Web 开发者构建复杂的二维布局,并设置有关网格中每个子项的尺寸、对齐方式和排序方式的规则。CSS Grid 是在 Flexbox 流行起来之后推出的,二者相辅相成,可帮助开发者实现更好的响应式设计,而无需使用复杂的对齐调整或 JavaScript 辅助布局。

作为一种相对较新的布局系统,CSS 网格也难以正确使用。其语法非常灵活(只需搜索网格备忘单即可),有多种方法可以实现相同的布局,而灵活的尺寸和隐式轨道使得更难推断布局是否正常运行。因此,我们决定在开发者工具中提供专用的 CSS 网格工具,以便开发者更好地了解其 CSS 代码的运作方式,以及如何获得正确的布局。

工具设计

Chrome 和 Edge 的联合成果

CSS 网格工具吸引了 Chrome DevTools 和 Edge DevTools 团队的注意力。我们从一开始就决定合作。我们分享了两个团队的产品、工程和设计资源,并每周进行协调,以实现这一目标。

功能摘要

CSS 网格工具有三个主要功能:

  1. 特定于网格的持久性叠加层,有助于提供尺寸和排序信息
  2. DOM 树中的标记,用于突出显示 CSS 网格容器并切换网格叠加层
  3. 边栏窗格,可让开发者自定义 DOM 叠加层的显示方式(例如更改规则的颜色和宽度)
  4. 样式窗格中的 CSS 网格编辑器

接下来,我们来深入了解一下这些功能。

网格持久性叠加层

在 DevTools 中,叠加层是一款强大的工具,可提供单个元素的布局和样式信息:

ALT_TEXT_HERE

这些额外信息会叠加在感兴趣的元素上。以前,当您在打开开发者工具的情况下将鼠标悬停在网格上时,叠加层会显示其盒模型信息,但会将内容突出显示限制在网格项,而不说明为何如此。我们希望为 CSS 网格叠加层添加两个主要部分:

  • 我们希望显示有关网格的更多实用信息,例如创作者维度和间隔
  • 我们希望使叠加层保持固定,以便同时查看多个网格,并在更改元素样式时看到叠加层更新网格信息

我们来看看是如何实现这两点的。

作者设定的尺寸与计算尺寸

调试 CSS 网格的一个难点是,定义网格轨道大小的方法有很多。例如,您可以将像素值、百分比值、分数、重复函数和 minmax 函数组合使用,以创建多种轨道大小:

.grid-cards {
    display: grid;
    width: 200px;
    height: 300px;
    grid-template-rows: 20% 0.3fr 100px minmax(100px, auto);
    grid-template-columns: repeat(3, minmax(200px, 1fr));
}

不过,很难将这些编写的轨道大小映射到浏览器为我们计算的计算轨道大小。为了解决这一问题,我们在叠加层上并排放置这两项信息:

ALT_TEXT_HERE

英文句点前面的字符串是作者提供的值,英文句点后面的字符串表示实际计算的值。

以前,DevTools 无法获取创作者值。从理论上讲,我们可以自行解析 DevTools 中的作者指定值,并根据 CSS Grid 规范对其进行计算。这需要涉及许多复杂的场景,而且本质上只是在重复 Blink 的工作。因此,在 Blink 的样式团队的帮助下,我们从样式引擎中获得了一个新的 API,该 API 会公开“级联值”级联值是 CSS 属性在 CSS 级联后最终有效的值。这是样式引擎编译所有样式表后,但在实际计算任何值(例如百分比、分数等)之前的胜出值。

我们现在使用此 API 在网格叠加层中显示创作者值

持久性叠加层

在 CSS Grid 工具出现之前,DevTools 中的叠加层非常简单:您只需将鼠标悬停在 DevTools 的 DOM 树窗格或直接在被检查的网页中某个元素上,就会看到描述此元素的叠加层。当您移开鼠标时,叠加层会消失。对于网格叠加层,我们希望做一些不同的事情:可以同时突出显示多个网格,并且网格叠加层可以保持开启状态,同时常规的悬停叠加层仍可正常运行。

例如:

ALT_TEXT_HERE

不过,DevTools 中的叠加层在设计时并未考虑这种多元素持久化机制(它是在多年前创建的)。因此,我们不得不重构叠加层设计才能使其正常运行。我们在现有的突出显示工具套件添加了一个新的 GridHighlightTool,该工具后来演变为一个全局 PersistentTool,用于同时突出显示所有持久叠加层。对于每种类型的永久性叠加层(网格、Flex 等),我们都会在永久性工具中保留相应的配置字段。每当叠加层突出显示器检查要绘制的内容时,它还会包含这些配置。

为了让 DevTools 能够控制需要突出显示的内容,我们为网格持久叠加层创建了一个新的 CDP 命令:

# Highlight multiple elements with the CSS Grid overlay.
command setShowGridOverlays
  parameters
    # An array of node identifiers and descriptors for the highlight appearance.
    array of GridNodeHighlightConfig gridNodeHighlightConfigs

其中每个 GridNodeHighlightConfig 都包含有关要绘制哪个节点以及如何绘制该节点的信息。这样一来,我们就可以添加多项持久机制,而不会破坏当前的悬停行为。

实时网格标记

为了帮助开发者轻松切换网格叠加层,我们决定在 DOM 树中的网格容器旁边添加小标记。这些标记还可以帮助开发者在 DOM 结构中识别 Grid 容器。

ALT_TEXT_HERE

DOM 树的更改

由于 Grid 徽章并不是我们希望在 DOM 树中显示的唯一徽章,因此我们希望尽可能简化徽章添加流程。ElementsTreeElement 是负责在 DevTools 中创建和管理各个 DOM 树元素的类,该类已更新为包含用于配置标记的多个新公共方法。如果某个元素有多个徽章,系统会按徽章类别对其进行排序,如果徽章属于同一类别,则按名称的字母顺序排序。可用类别包括 SecurityLayout 等,Grid 属于 Layout 类别。

此外,我们从一开始就内置了无障碍功能支持。每个交互式标记都必须提供默认 aria-label 和有效 aria-label,而只读标记则使用其标记名称作为 aria-label

我们是如何获取实时样式更新的?

许多 DOM 更改都会实时反映在 DevTools DOM 树中。例如,新添加的节点会立即显示在 DOM 树中,移除的类名称也会立即消失。我们希望网格徽章状态也能反映相同的最新信息。不过,事实证明,这很难实现,因为当 DOM 树中显示的元素收到计算样式更新时,开发者工具无法收到通知。目前,要了解某个元素何时成为或不再成为 Grid 容器,唯一的方法是不断向浏览器查询每个元素的最新样式信息。这将会耗资巨大

为了让前端更轻松地了解元素的样式何时更新,我们添加了用于轮询样式更新的新 CDP 方法。如需获取 DOM 节点的样式更新,我们首先要告诉浏览器要跟踪哪些 CSS 声明。对于网格标记,我们会要求浏览器跟踪以下内容:

{
  "display": "grid",
  "display": "inline-grid",
}

然后,我们会发送轮询请求,当“元素”面板中的 DOM 节点有跟踪的样式更新时,浏览器会向 DevTools 发送更新后的节点列表,并解析现有的轮询请求。每当 DevTools 想要再次收到样式更新通知时,都可以发送此轮询请求,而不是从每个节点不断轮询后端。DevTools 还可以通过向浏览器发送新列表来更改要跟踪的 CSS 声明。

“布局”窗格

虽然 DOM 树标记有助于发现 CSS 网格,但有时我们希望查看特定网页中的所有 CSS 网格的列表,并轻松切换其持久叠加层,以调试其布局。因此,我们决定创建一个专门用于布局工具的侧边栏窗格。这样,我们就有了专门的空间来收集所有 Grid 容器,并配置 Grid 叠加层的所有选项。我们还可以在此 Layout 窗格中放置未来的大量布局工具(例如 Flexbox容器查询)。

根据计算出的样式查找元素

为了在 Layout 窗格中显示 CSS Grid 容器列表,我们需要按计算出的样式查找 DOM 节点。事实证明,这也不简单,因为在 DevTools 打开时,DevTools 并不知道所有 DOM 节点。相反,开发者工具只知道一小部分节点(通常位于 DOM 层次结构的顶层),仅用于启动开发者工具 DOM 树。出于性能方面的原因,系统仅会在收到进一步请求时提取其他节点。这意味着,我们需要一个新的 CDP 命令来收集网页中的所有节点,并按计算样式对其进行过滤:

# Finds nodes with a given computed style in a subtree.
experimental command getNodesForSubtreeByStyle
  parameters
    # Node ID pointing to the root of a subtree.
    NodeId nodeId
    # The style to filter nodes by (includes nodes if any of properties matches).
    array of CSSComputedStyleProperty computedStyles
    # Whether or not iframes and shadow roots in the same target should be traversed when returning the
    # results (default is false).
    optional boolean pierce
  returns
    # Resulting nodes.
    array of NodeId nodeIds

这样,DevTools 前端便可以获取网页中的 CSS Grid 容器列表(可能会穿透 iframe 和阴影根),并在“布局”窗格中渲染这些容器。

总结

CSS 网格工具是首批支持 Web 平台功能的开发者工具设计工具项目之一。它在 DevTools 中首次推出了许多基本工具,例如持久性叠加层、DOM 树标记和布局窗格,为 Chrome DevTools 中日后推出的布局工具(例如 Flexbox 和容器查询)奠定了基础。它还为 Grid 和 Flexbox 编辑器奠定了基础,让开发者能够以互动方式更改 Grid 和 Flexbox 对齐方式。我们日后会详细介绍这些问题。

下载预览渠道

不妨考虑将 Chrome Canary 版开发者版Beta 版用作默认开发浏览器。通过这些预览版渠道,您可以使用最新的 DevTools 功能、测试尖端的 Web 平台 API,并帮助您在用户发现问题之前发现网站上的问题!

与 Chrome DevTools 团队联系

您可以使用以下选项讨论与 DevTools 相关的新功能、更新或任何其他内容。