使用指针事件属性管理 SVG 交互

已发表: 2022-03-10
快速总结↬让我们看一下如何使用pointer-events属性来塑造SVG 图像的交互性——即控制文档的哪些部分可以接收点击、触摸或点击。

尝试单击或点击下面的 SVG 图像。 如果您将指针放在正确的位置(阴影路径),那么您应该在新的浏览器选项卡中打开 Smashing Magazine 的主页。 如果您尝试单击一些空白区域,您可能会感到非常困惑。

请参阅 CodePen 上 Tiffany Brown (@webinista) 的 Pen Amethyst。

请参阅 CodePen 上 Tiffany Brown (@webinista) 的 Pen Amethyst。

这是我在最近的一个包含 SVG 图像中的链接的项目中面临的困境。 有时当我单击图像时,链接有效。 其他时候没有。 令人困惑,对吧?

我转向 SVG 规范以了解更多关于可能发生的事情以及 SVG 是否提供修复的信息。 答案: pointer-events

跳跃后更多! 继续往下看↓

不要与 DOM(文档对象模型)指针事件混淆, pointer-events既是CSS属性又是SVG元素属性。 有了它,我们可以管理 SVG 文档或元素的哪些部分可以接收来自指针设备(如鼠标、触控板或手指)的事件。

关于术语的说明:“指针事件”也是与设备无关的、用于用户输入的 Web 平台功能的名称。 然而,在本文中——出于pointer-events属性的目的——短语“指针事件”也包括鼠标和触摸事件。

开箱即用:SVG 的“形状模型”

将 CSS 与 HTML 结合使用会在 HTML 上强加一个盒子布局模型。 在盒子布局模型中,每个元素都会围绕其内容生成一个矩形。 该矩形可能是内联、内联级、原子内联级或块,但它仍然是一个具有四个直角和四个边的矩形。 当我们向元素添加链接或事件侦听器时,交互区域与矩形的尺寸相匹配。

注意向交互元素添加clip-path会改变其交互边界。 换句话说,如果您将六边形clip-path路径添加到a元素,则只有剪辑路径中的点是可点击的。 同样,添加倾斜变换会将矩形变成菱形。

SVG 没有盒子布局模型。 您会看到,当 HTML 文档包含 SVG 文档时,在 CSS 布局中,根 SVG 元素遵循盒子布局模型。 它的子元素没有。 因此,大多数与 CSS 布局相关的属性不适用于 SVG。

因此,SVG 拥有我称之为“形状模型”的东西。 当我们向 SVG 文档或元素添加链接或事件侦听器时,交互区域不一定是矩形。 SVG 元素确实有一个边界框。 边界框被定义为:与该元素的用户坐标系的轴对齐的最紧密的矩形,完全包围它及其后代。 但最初,SVG 文档的哪些部分是交互式的,取决于哪些部分是可见的和/或绘制的

绘制与可见元素

SVG 元素可以“填充”,但也可以“抚摸”。 填充是指形状的内部。 笔画是指它的轮廓。

“填充”和“描边”一起是绘制操作,将元素渲染到屏幕或页面(也称为画布)。 当我们谈论绘制元素时,我们的意思是元素具有填充和/或描边。 通常,这意味着该元素也是可见的。

但是,可以在不可见的情况下绘制 SVG 元素。 如果visible属性值或 CSS 属性被hiddendisplaynone ,则会发生这种情况。 元素在那里并占据理论空间。 我们只是看不到它(辅助技术可能无法检测到它)。

也许更令人困惑的是,一个元素也可以是可见的——也就是说,有一个计算visibilityvisible性值——而不被绘制。 当元素同时缺少描边和填充时,就会发生这种情况。

注意具有 alpha 透明度的颜色值(例如rgba(0,0,0,0) )不会影响元素是否被绘制或可见。 换句话说,如果一个元素有一个 alpha 透明填充或描边,即使看不到它也会被绘制。

了解元素何时被绘制、可见或两者都不被绘制对于理解每个pointer-events值的影响至关重要。

全有或无或介于两者之间:价值观

pointer-events既是 CSS 属性又是 SVG 元素属性。 它的初始值为auto ,这意味着只有绘制的和可见的部分会接收指针事件。 大多数其他值可以分为两组:

  1. 要求元素可见的值; 和
  2. 没有的值。

paintedfillstrokeall属于后一类。 它们依赖于可见性的对应物—— visiblePaintedvisibleFillvisibleStrokevisible —— 属于前者。

SVG 2.0 规范还定义了bounding-box值。 当pointer-events的值为bounding-box时,元素周围的矩形区域也可以接收到指针事件。 在撰写本文时,只有 Chrome 65+ 支持bounding-box值。

none也是一个有效值。 它防止元素及其子元素接收任何指针事件。 pointer-events CSS 属性也可以用于 HTML 元素。 但是当与 HTML 一起使用时,只有autonone是有效值。

由于pointer-events值的演示比解释更好,让我们看一些演示。

在这里,我们有一个应用了填充和描边的圆圈。 它既是的又是可见的。 整个圈子都可以接收到指针事件,但是圈子外面的区域不能。

查看 Tiffany Brown (@webinista) 在 CodePen 上用 SVG 绘制的 Pen Visible 对比。

查看 Tiffany Brown (@webinista) 在 CodePen 上用 SVG 绘制的 Pen Visible 对比。

禁用填充,使其值为none 。 现在,如果您尝试悬停、单击或点击圆圈的内部,则不会发生任何事情。 但是如果你对笔画区域做同样的事情,指针事件仍然会被调度。 将fill值更改为none意味着该区域可见,但未绘制

让我们对标记做一个小改动。 我们将添加pointer-events="visible"到我们的circle元素,同时保持fill=none

请参阅 Tiffany Brown (@webinista) 在 CodePen 上的 Pen How 添加指针事件:所有都会影响交互性。

请参阅 Tiffany Brown (@webinista) 在 CodePen 上的 Pen How 添加指针事件:所有都会影响交互性。

现在被笔画包围的未绘制区域可以接收指针事件。

增加 SVG 图像的可点击区域

让我们回到本文开头的那张图。 我们的“紫水晶”是一个path元素,而不是一组多边形,每个多边形都有一个strokefill 。 这意味着我们不能只添加pointer-events="all"就结束了。

相反,我们需要扩大点击区域。 让我们使用我们所知道的关于绘制和可见元素的知识。 在下面的示例中,我在图像标记中添加了一个矩形。

请参阅 Tiffany Brown (@webinista) 在 CodePen 上增加 SVG 图像的点击区域的 Pen。

请参阅 Tiffany Brown (@webinista) 在 CodePen 上增加 SVG 图像的点击区域的 Pen。

即使这个矩形是看不见的,它在技术上仍然是可见的(即visibility: visible )。 然而,它没有填充意味着它没有被绘制。 我们的图像看起来一样。 事实上,它的工作原理仍然相同——单击空白仍然不会触发导航操作。 我们仍然需要为我们a元素添加一个pointer-events属性。 使用visibleall值将在这里工作。

请参阅 Tiffany Brown (@webinista) 在 CodePen 上增加 SVG 图像的点击区域的 Pen。

请参阅 Tiffany Brown (@webinista) 在 CodePen 上增加 SVG 图像的点击区域的 Pen。

现在整个图像可以接收指针事件。

使用bounding-box将消除对幻像元素的需要。 边界框内的所有点都将接收指针事件,包括路径所包围的空白区域。 但同样: pointer-events="bounding-box"没有得到广泛支持。 在此之前,我们可以使用未绘制的元素。

在混合 SVG 和 HTML 时使用pointer-events

pointer-events另一种情况:在 HTML 按钮中使用 SVG。

请参阅 Tiffany Brown (@webinista) 在 CodePen 上的 Pen Ovxmmy。

请参阅 Tiffany Brown (@webinista) 在 CodePen 上的 Pen Ovxmmy。

在大多数浏览器中——Firefox 和 Internet Explorer 11 是例外—— event.target的值将是一个 SVG 元素,而不是我们的 HTML 按钮。 让我们将pointer-events="none"添加到打开的 SVG 标记中。

请参阅 Tiffany Brown (@webinista) 在 CodePen 上的 Pen How pointer-events: none can be used with SVG and HTML。

请参阅 Tiffany Brown (@webinista) 在 CodePen 上的 Pen How pointer-events: none can be used with SVG and HTML。

现在,当用户单击或点击我们的按钮时, event.target将引用我们的button

精通 DOM 和 JavaScript 的人会注意到,使用function关键字而不是箭头函数和this而不是event.target可以解决这个问题。 但是,使用pointer-events="none" (或 CSS 中的pointer-events: none; )意味着您不必将特定的 JavaScript 怪癖提交到内存中。

结论

SVG 支持与 HTML 相同的交互方式。 我们可以使用它来创建响应点击或点击的图表。 我们可以创建不符合 CSS 和 HTML 框模型的链接区域。 通过添加pointer-events ,我们可以改进 SVG 文档响应用户交互的方式。

浏览器对 SVG pointer-events的支持非常强大。 每个支持 SVG 的浏览器都支持 SVG 文档和元素的属性。 当与 HTML 元素一起使用时,支持的健壮性稍差。 它在 Internet Explorer 10 或其前身或任何版本的 Opera Mini 中均不可用。

在这篇文章中,我们刚刚触及了pointer-events的表面。 如需更深入的技术处理,请通读 SVG 规范。 MDN(Mozilla 开发者网络)Web Docs 为pointer-events提供了更多对 Web 开发者友好的文档,并附有示例。