CSS 自定义突出显示 API 入门

文本突出显示是一项可以在多个站点上检测到的功能,并且有多种用途。例如,浏览器突出显示使用搜索功能找到的元素,文本编辑器和工具(如概念或语法)突出显示拼写和语法错误。

 

文本突出显示可以增强用户体验,但将此功能添加到网站或应用程序可能很困难。幸运的是,由于 CSS 自定义突出显示 API,这将会变得容易得多,它允许我们轻松地为文本范围添加样式。在撰写本文时,如何快速更改浏览器中的字体大小?多个浏览器更改字体大小教程此功能仍处于工作草案中,因此可能会发生变化。

在本文中,我将概述 API 的功能以及要考虑的有关行为和可访问性的事项。我还将分享几个示例来说明 CSS 自定义突出显示 API 在各种用例中的使用。

了解基础知识

使用 CSS 自定义突出显示如何在Windows上下载和安装iTunes应用程序?iTunes图文使用教程 API 需要三个步骤:在样式表中创建样式、设置突出显示范围,然后将这些样式应用于范围。

在深入探讨这些步骤之前,我想重申一下,CSS 自定义突出显示 API 仍然是一个工作草案,这意味着它仍然会发生变化。此外,苹果的home键失灵了怎么办?修复iPad home按钮的多种方法此功能目前不适用于 Firefox,因此如果您的项目需要 Firefox,您现在不应该将其用于生产。

话虽如此,让我们从第一步开始。

创建高亮样式

这个 CSS 自定义突出显示 API 要求我们使用伪元素来设置我们需要的样式。W3C 工作草案将此伪元素定义为“如何在iPhone上导出iCloud日历?iCloud日历迁移方法包含在或部分包含在已注册自定义突出显示的所有范围内的文档部分”。::highlight()

我们需要为在大括号内创建的自定义突出显示添加一个名称,因此自定义突出显示的 CSS 声明应如下所示:

::highlight(sample-highlight) {
  background-color: rebeccapurple;
  color: whitesmoke;
}

您可能想知道样式规则中是否有可以应用于此突出显示的限制,答案是肯定的!我们可以使用的 CSS 规则非常有限。更准确地说,ie浏览器临时文件夹缓存的文件在哪里?详细图文教程我们只能使用以下规则,因为它们适用于伪元素:::selection

  • background-color

  • caret-color

  • color

  • cursor

  • fill

  • stroke

  • stroke-width

  • text-decoration

之所以选择这些规则,是因为浏览器可以有效地应用它们,而无需重新创建站点的布局或插入新的 DOM 元素(即,我们可以通过使用内联 HTML 标签包装元素来重新创建此功能,例如 )。span

要比较 CSS 自定义突出显示 API 与插入跨度的传统文本格式设置方法之间的性能差异,请参阅 Fernando Fiori 的此性能比较演示。

设置范围

创建样式后,下一步是使用 CSS 设置范围。首先,我们将使用构造函数定义我们的文本范围;这将允许我们选择文档的片段。此片段可以包含节点或文本节点的一部分。Range()

构造函数可以选择的元素类型很重要,因为这意味着要获取我们要使用的文本片段,我们需要使用返回其中一种元素的函数。Range()

让我们考虑以下文本示例:

<p>This example has <em>cursive</em> and <strong>bold</strong> text</p>

现在,让我们创建样式:

:root::highlight(example) {
  background-color: rebeccapurple;
  color: whitesmoke;
}

如果我们尝试使用该元素创建一个范围,则每个节点或文本片段都将是一个新范围。p

我们可以使用 and 方法来选择要突出显示的文本部分。range.setStart``range.setEnd

对于此示例文本,每个新元素都将是一个新范围,因此我们将提供以下内容:

此示例句子显示每个范围的开始位置。“此示例具有”位于位置 0,<em> 元素中的所有内容位于位置 1,“ 和 ” 位于位置 2,<strong> 元素内的所有内容位于位置 3,“text”位于位置 4。

假设我们想突出显示上面句子中的文本“草书和强”。在这种情况下,该方法应为 。您可能认为该方法应该是 ,但这并不完全正确!setStart1setEnd``3

如果我们将范围的开头设置为 ,API 将从元素的最开头开始选择它,如果我们将结束范围设置为 ,则选择将在第三个元素的开头结束。因此,要选择元素内的所有文本,此示例的属性应为 。13strongrange.setEnd4

and 方法接收两个参数:我们要使用的 DOM 元素和位置。下面是它在我们的代码中的外观:setStart``setEnd

const paragraph = document.querySelector("p")
​
const exampleRange = new Range();
exampleRange.setStart(paragraph, 1);
exampleRange.setEnd(paragraph, 4);

应用突出显示

现在我们有了想要的范围,是时候突出它了!为此,我们需要创建一个新的构造函数,它将接收我们的范围作为属性:Highlight()

const highlight = new Highlight(exampleRange)

接下来,我们需要调用该方法。它接收两个属性:我们在样式表中创建的类和我们之前创建的 new 类。这就是它在我们的代码中的样子:CSS.highlight.sethighlighthighlight

CSS.highlights.set("example", highlight);

但是,如果您需要清除您创建的突出显示怎么办?

只需调用该方法,突出显示将毫无问题地清除。CSS.highlights.clear()

创建和突出显示更复杂的范围

当我们想要选择完整的单词时,我们之前演示的用于创建突出显示范围的技术效果很好,但是当我们只需要选择单词的一部分时会发生什么?让我们回到我们的示例,这次让我们尝试只突出显示字母“old tex”。

首先,让我们为这个亮点创建我们的风格:

:root::highlight(partial) {
  background-color: goldenrod;
  color: black;
}

好的,现在我们如何避免选择整个片段?

我对这个问题的方法是仔细研究这个元素(在本例中是整个元素)是如何制作的。首先,我使用控制台更详细地检查了它,用于检查属性列表。然后我看了看房产,结果是这样的:pconsole.dir()childNodes

p元素的console.dir。该属性返回段落内元素的数组。在这种情况下,第二个和第四个元素显示为各自的元素标签,其他元素显示为文本。

我们要突出显示的文本“old tex”位于元素内部。要从此文本开始我们的范围,我们可以使用 ,但这会选择整个元素。那么,我们如何只选择元素的一部分呢?strong``paragraph.childNodes[3]

如前所述,将选择元素节点或文本节点。在我们的例子中,我们需要在这个元素内部检查返回文本节点的东西。Range

让我们回到我们的,因为它有一个我们可以使用的属性:console.dir()``firstChild

Console.dir 的强元素。此元素中的属性返回可在构造函数中使用的文本节点。

所以现在我们有. 将返回我们的字符串作为原型。paragraph.childNodes[3]firstChildText

要设置我们的起始位置,我们需要检查“old”中的“o”所在的位置。在这个例子中,它是第二个字符,所以如果我们把它分成一个数组,“o”将是 位置 .因此,当我们为范围设置方法时,它将如下所示:1``setStart

partialRange.setStart(paragraph.childNodes[3].firstChild, 1)

伟大!现在,让我们设置此范围的末尾。

我们要突出显示的最后一个字符“tex”位于 .正如您将在上面的属性列表中注意到的那样,最后一个元素具有 类型 ,因此不需要访问 的属性。childNodeschildNodestext``firstChild

接下来,我们需要检查在哪里结束我们的范围;我们将使用该方法,如下所示:setEnd

partialRange.setEnd(paragraph.childNodes[4], 4)

现在,我们所要做的就是创建亮点:

const partialHighlight = new Highlight(partialRange);
​
CSS.highlights.set("partial", partialHighlight)

以下是突出显示的外观:

我在同一 CodePen 中展示这两个示例是有原因的——重要的是要考虑当多个样式应用于同一字符串时,浏览器将如何优先呈现什么。

例如,“粗体”中的字符串“old”具有两种样式。将显示哪种样式将取决于我们决定调用该方法的位置。CSS.highlights.set

在本例中,我调用了首先添加样式的方法,然后调用添加样式的方法。因为这是 JavaScript,所以声明的最后一个方法将优先。因此,在这种情况下,“旧”字符串将应用样式。examplepartialpartial

最后,正如您可能认为的那样,该方法可能很难完全理解。当您开始考虑规模时,此方法可能会开始不足。我们将在本文后面查看一些示例,这些示例将其他方法用于更复杂的用例。但首先,我们需要考虑一个重要的考虑因素:可访问性。Range()

处理辅助功能限制

CSS 自定义突出显示 API 非常灵活,但是当您需要向屏幕阅读器等辅助技术公开突出显示时会发生什么情况?此 API 涵盖了这一点,但现在,它仅限于少数用例。

让我们从基础开始。使用构造函数创建突出显示时,有一个名为 的属性。此属性为突出显示提供语义含义,并定义它将如何向屏幕阅读器和其他辅助技术公开!Highlight()``type

我们可以使用的类型相当限于以下三种:

  • highlight:默认分配

  • spelling-error:用于突出显示拼写错误的内容

  • grammar-error:用于突出显示语法不正确的内容

如果您使用的突出显示具有这些类型之一,则绝对应该添加该类型。为此,只需像这样更改属性:

// Creating a highlight with a new range
const highlight = new Highlight(range)
​
// Changing the attribute type of this range
highlight.type = "spelling-error"

为什么只有这三种类型?根据 W3C 规范,这是因为这些被认为是此 API 最常见的用例:

之所以选择这组初始类型,是因为它们预计将成为突出显示 API 的流行用例,并且目前有一些现有的支持在平台辅助功能 API 中表达它们的语义。

该规范还提到“UA(用户代理)应该为辅助技术提供自定义突出显示”,现在它主要是这样做的。

在这里,我想再次强调,CSS 自定义突出显示 API 仍在进行中。我用NVDA和Chrome做了一些测试,发现它会在文本突出显示之前识别拼写或语法错误,但当文本类型为.highlight

为什么这很重要?好吧,如果此突出显示不仅仅是出于视觉目的,而是需要接触辅助技术,您可能需要考虑这项工作的另一种选择。我认为有效的一种解决方案是 ProgrammingTT 在此视频中演示的解决方案,其中突出显示的内容包装在元素中。<mark>

在撰写本文时,只有两种类型的突出显示向辅助技术公开,但添加更多突出显示类型的可能性是开放的,正如 W3C 所提到的:

辅助功能 API 目前无法表达其他预期突出显示 API 用例的特定语义。随着辅助功能 API 获得对表达突出显示 API 的其他流行用例的支持,以后可以添加更多类型。HighlightType

现在,话虽如此,让我们看看这个 API 的一些用例!

CSS 自定义突出显示 API 示例

为了更好地了解这个 API 可以做什么,让我们看一下 Microsoft Edge 团队对这个 API 的一些实现,以及我构建的一个示例。这些用例还将让我们看到处理文本范围的不同方法。

选择并突出显示 Web 文本

让我们从 Microsoft Edge 视频“使用 CSS 自定义突出显示 API 在 Web 上突出显示文本”中的示例开始。在此项目中,可以选择文本,突出显示它以将其存储在列表中,然后稍后检查它。存储的文本将使用 CSS 自定义突出显示 API 突出显示。

对于此示例,Patrick Brosset 使用该方法创建具有以下选择的范围:document.getSelection()

const selection = document.getSelection();
const range = selection.getRangeAt(0);

由于任何返回文本片段或节点片段的方法都是有效的,因此可以解决问题。接下来,Brosset 开始使用该方法添加范围,然后突出显示它们,如前所述。document.getSelection()``Highlight

由于此视频没有现场演示,我决定重新创建突出显示选择范围的功能。这与我们之前的示例非常相似,但有一个关键区别:这次我们可能需要突出显示多个范围。为此,让我们首先创建一些全局变量:

let SELECTION_TEXTS = []
let selectionHighlighter = new Highlight()

第一个变量是一个数组,它将存储我们要突出显示的每个范围,第二个变量创建该类的实例。Highlight()

我们为什么要在全球范围内处理这个问题?因为我们将使用此类的方法添加范围,而不是使用我们之前使用的语法。

现在,是时候创建我们的函数来突出显示这些文本范围了:

const textHighlight = () => {
  const selection = document.getSelection();
  const range = selection.getRangeAt(0)
  SELECTION_TEXTS.push(range)
​
  SELECTION_TEXTS.forEach((selection) => {
    selectionHighlighter.add(selection)
  })
  CSS.highlights.set("example", selectionHighlighter)
};

这与我们之前看到的有点不同。趣知笔记在向我们的 添加任何东西之前,我们必须首先将新范围添加到我们的数组中。然后,我们需要用方法迭代它,开始将选择范围添加到方法中。接下来,我们只需要像以前一样调用该方法。selectionHighlighterforEachselectionHighlighterHighlight. add()CSS.highlights.set()

但是,如果我们需要清除亮点会发生什么?为此,我们可以使用以下函数:

const clearHighlight = () => {
  selectionHighlighter.clear()
  SELECTION_TEXTS = []
  CSS.highlights.clear()
}

与 类似,我们可以用来删除全局变量中所有突出显示的元素。然后,我们只需要清除用于数组的全局变量,然后使用我们之前演示的方法。Highlight.add()Highlight.clear()CSS.highlights.clear()

要了解其工作原理,请查看此演示:

我选择这个例子是因为我想展示如何使用其他策略来选择所需的文本范围。在这种情况下,有效,但是当您需要创建更大规模的东西时会发生什么?这就是我们的第二个用例的用武之地!document.getSelection()

在页面组件中搜索

下一个演示,用于页面内搜索组件,也是由Microsoft Edge团队制作的。它演示了如何使用 a 来获取 DOM 元素(在本例中为元素)中的所有节点,趣知笔记网站地图从而在更大范围内创建文本节点。至于 CSS 自定义突出显示 API,我们需要所有文本节点,因此我们将使用该实例。TreeWalkermainNodeFilter.SHOW_TEXT

接下来,使用该方法检查每个节点,并将它们存储在变量中,结果如下:TreeWalkerTreeWalker.nextNode()allTextNodes

变量 allTextNodes 的控制台屏幕截图;包含 37 个元素的数组,所有这些元素都是文本类型。

这个过程为我们提供了一个文本元素数组;我们可以通过将其名称添加为 .然后,只需添加文本节点的范围,找到这些结果,然后像我们之前使用该方法所做的那样突出显示它们。这种方法说明了我们如何使用 a 来帮助我们在更大范围内可靠地检查文本节点。inputCSS.highlights.set()TreeWalker

此演示将极大地受益于辅助技术亮点的额外语义含义。请记住,此 API 只有三种类型,突出显示搜索结果不是其中之一!所以W3C,如果你看到这个,包括搜索结果的这种语义含义肯定会派上用场!

现在,让我们看一下我构建的示例;它有效地使用了可用的语义含义!

订购此短语应用

我的项目想法是创建一个应用程序,其中用户收到一个打乱的短语,然后需要提供正确排序的短语作为答案。用户将通过突出显示接收视觉反馈,具体取决于提交中的单词顺序是否正确。我选择这个例子是因为它可以利用突出显示语义类型(在本例中)来提高应用程序的可访问性!grammar-error

“订购此短语”应用的示例。这句话“嗨!我是丹妮尔,很高兴认识你!“顺序错误。有一个输入字段来提供正确的答案和一个“检查您的答案”按钮。

首先,我们需要创建我们的亮点类!如果我们只依靠背景颜色来突出显示正确和错误的答案,那么对于色盲用户来说,结果将很难区分。相反,我决定使用删除线(或)来表示不正确的答案:line-through

:root::highlight(wrong-highlight) {
  background-color: crimson;
  color: whitesmoke;
  text-decoration-line: line-through;
  text-decoration-thickness: 2px;  
}

:root::highlight(right-highlight) {
  background-color: forestgreen;
  color: whitesmoke;
}

如前所述,创建语义含义的关键是将属性添加到所需的突出显示类。在这种情况下,我只想强调那些以错误顺序出现的单词,因为这些单词会产生语法错误,所以这就是我在全局创建实例时所做的。由于要突出显示多个范围,因此我必须声明空数组,因此我决定也全局添加这些数组:type``Highlight()

let RIGHT_RANGES = [];
let WRONG_RANGES = [];

const rightHighlight = new Highlight();

const wrongHighlight = new Highlight();
wrongHighlight.type = "grammar-error";

经过多次验证以检查添加的单词是否与答案中的单词一致,是时候开始添加我们的范围了!我决定选择答案的容器(在本例中为 ),然后检查其每个子项。由于每个内部仅包含此元素,因此范围从 开始,到 结束于 。olli0``1

考虑到这一点,这是我使用的代码:

const answerListNodes = ANSWER_LIST.children;

// Selects the range of each <li> to start the highlighting process
answer.forEach((word, index) => {
  const wordRange = new Range();
  wordRange.setStart(answerListNodes[index], 0);
  wordRange.setEnd(answerListNodes[index], 1);

  if (word === RIGHT_ORDER[index]) {
    // If the answer is right
    RIGHT_RANGES.push(wordRange);
  } else {
    // If the answer is wrong
    WRONG_RANGES.push(wordRange);
  }
});

接下来,我们可以使用 and 数组将选定的范围添加到我们的实例中,然后使用该方法在屏幕上突出显示它们:RIGHT_RANGESWRONG_RANGESHighlight()``CSS.highlights.set()

// Highlights the answers in the right position
RIGHT_RANGES.forEach((element) => {
  rightHighlight.add(element);
});
​
CSS.highlights.set("right-highlight", rightHighlight);
​
// Highlights the answers in the right position
WRONG_RANGES.forEach((element) => {
  wrongHighlight.add(element);
});
​
CSS.highlights.set("wrong-highlight", wrongHighlight);

如果你想看看它是如何工作的,看看这个CodePen:

同样,我使用了这种方法,因为 CSS 自定义突出显示 API 提供了一个语义类型,非常适合此示例。

结语

CSS 自定义突出显示 API 是一项新功能,它为我们面临的一些与可用性和可访问性相关的问题提供了一些有趣的解决方案。与其他选项相比,它还提供卓越的性能。当您考虑如何选择范围时,此 API 可能有点棘手,但是一旦您弄清楚了这一点,该工具就会开辟一组全新的可能性!

这个 API 仍在处理中,目前缺乏全球支持,但我认为它有很大的潜力。我希望将来这个 API 将扩展其浏览器支持,并且还将支持更多可用于辅助技术的语义类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pxr007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值