Managing SVG Interaction With The Pointer Events Property
Let’s take a look at how to shape the interactivity of SVG images — that is, control which parts of the document can receive clicks, touches, or taps — using the pointer-events
property.
Try clicking or tapping the SVG image below. If you put your pointer in the right place (the shaded path) then you should have Smashing Magazine’s homepage open in a new browser tab. If you tried to click on some white space, you might be really confused instead.
This is the dilemma I faced during a recent project that included links within SVG images. Sometimes when I clicked the image, the link worked. Other times it didn’t. Confusing, right?
I turned to the SVG specification to learn more about what might be happening and whether SVG offers a fix. The answer: pointer-events
.
Not to be confused with DOM (Document Object Model) pointer events, pointer-events
is both a CSS property and an SVG element attribute. With it, we can manage which parts of an SVG document or element can receive events from a pointing device such as a mouse, trackpad, or finger.
A note about terminology: "pointer events" is also the name of a device-agnostic, web platform feature for user input. However, in this article — and for the purposes of the pointer-events
property — the phrase "pointer events" also includes mouse and touch events.
Outside Of The Box: SVG’s “Shape Model”
Using CSS with HTML imposes a box layout model on HTML. In the box layout model, every element generates a rectangle around its contents. That rectangle may be inline, inline-level, atomic inline-level, or block, but it’s still a rectangle with four right angles and four edges. When we add a link or an event listener to an element, the interactive area matches the dimensions of the rectangle.
Note: Adding a clip-path
to an interactive element alters its interactive bounds. In other words, if you add a hexagonal clip-path
path to an a
element, only the points within the clipping path will be clickable. Similarly, adding a skew transformation will turn rectangles into rhomboids.
SVG does not have a box layout model. You see, when an SVG document is contained by an HTML document, within a CSS layout, the root SVG element adheres to the box layout model. Its child elements do not. As a result, most CSS layout-related properties don’t apply to SVG.
So instead, SVG has what I’ll call a ‘shape model’. When we add a link or an event listener to an SVG document or element, the interactive area will not necessarily be a rectangle. SVG elements do have a bounding box. The bounding box is defined as: the tightest fitting rectangle aligned with the axes of that element’s user coordinate system that entirely encloses it and its descendants.
But initially, which parts of an SVG document are interactive depends on which parts are visible and/or painted.
Painted Vs. Visible Elements
SVG elements can be “filled” but they can also be “stroked”. Fill refers to the interior of a shape. Stroke refers to its outline.
Together, “fill” and “stroke” are painting operations that render elements to the screen or page (also known as the canvas). When we talk about painted elements, we mean that the element has a fill and/or a stroke. Usually, this means the element is also visible.
However, an SVG element can be painted without being visible. This can happen if the visible
attribute value or CSS property is hidden
or when display
is none
. The element is there and occupies theoretical space. We just can’t see it (and assistive technology may not detect it).
Perhaps more confusingly, an element can also be visible — that is, have a computed visibility
value of visible
— without being painted. This happens when elements lack both a stroke and a fill.
Note: Color values with alpha transparency (e.g. rgba(0,0,0,0)
) do not affect whether an element is painted or visible. In other words, if an element has an alpha transparent fill or stroke, it’s painted even if it can’t be seen.
Knowing when an element is painted, visible, or neither is crucial to understanding the impact of each pointer-events
value.
All Or None Or Something In Between: The Values
pointer-events
is both a CSS property and an SVG element attribute. Its initial value is auto
, which means that only the painted and visible portions will receive pointer events. Most other values can be split into two groups:
- Values that require an element to be visible; and
- Values that do not.
painted
, fill
, stroke
, and all
fall into the latter category. Their visibility-dependent counterparts — visiblePainted
, visibleFill
, visibleStroke
and visible
— fall into the former.
The SVG 2.0 specification also defines a bounding-box
value. When the value of pointer-events
is bounding-box
, the rectangular area around the element can also receive pointer events. As of this writing, only Chrome 65+ supports the bounding-box
value.
none
is also a valid value. It prevents the element and its children from receiving any pointer events. The pointer-events
CSS property can be used with HTML elements too. But when used with HTML, only auto
and none
are valid values.
Since pointer-events
values are better demonstrated than explained, let’s look at some demos.
Here we have a circle with a fill and a stroke applied. It’s both painted and visible. The entire circle can receive pointer events, but the area outside of the circle cannot.
Disable the fill, so that its value is none
. Now if you try to hover, click, or tap the interior of the circle, nothing happens. But if you do the same for the stroke area, pointer events are still dispatched. Changing the fill
value to none
means that this area visible, but not painted.
Let’s make a small change to our markup. We’ll add pointer-events="visible"
to our circle
element, while keeping fill=none
.
Now the unpainted area encircled by the stroke can receive pointer events.
Augmenting The Clickable Area Of An SVG Image
Let’s return to the image from the beginning of this article. Our “amethyst” is a path
element, as opposed to a group of polygons each with a stroke
and fill
. That means we can’t just add pointer-events="all"
and call it a day.
Instead, we need to augment the click area. Let’s use what we know about painted and visible elements. In the example below, I’ve added a rectangle to our image markup.
Even though this rectangle is unseen, it’s still technically visible (i.e. visibility: visible
). Its lack of a fill, however, means that it is not painted. Our image looks the same. Indeed it still works the same — clicking white space still doesn’t trigger a navigation operation. We still need to add a pointer-events
attribute to our a
element. Using the visible
or all
values will work here.
Now the entire image can receive pointer events.
Using bounding-box
would eliminate the need for a phantom element. All points within the bounding box would receive pointer events, including the white space enclosed by the path. But again: pointer-events="bounding-box"
isn’t widely supported. Until it is, we can use unpainted elements.
Using pointer-events
When Mixing SVG And HTML
Another case where pointer-events
may be helpful: using SVG inside of an HTML button.
In most browsers — Firefox and Internet Explorer 11 are exceptions here — the value of event.target
will be an SVG element instead of our HTML button. Let’s add pointer-events="none"
to our opening SVG tag.
Now when users click or tap our button, the event.target
will refer to our button
.
Those well-versed in the DOM and JavaScript will note that using the function
keyword instead of an arrow function and this
instead of event.target
fixes this problem. Using pointer-events="none"
(or pointer-events: none;
in your CSS), however, means that you don’t have to commit that particular JavaScript quirk to memory.
Conclusion
SVG supports the same kind of interactivity we’re used to with HTML. We can use it to create charts that respond to clicks or taps. We can create linked areas that don’t adhere to the CSS and HTML box model. And with the addition of pointer-events
, we can improve the way our SVG documents behave in response to user interaction.
Browser support for SVG pointer-events
is robust. Every browser that supports SVG supports the property for SVG documents and elements. When used with HTML elements, support is slightly less robust. It isn’t available in Internet Explorer 10 or its predecessors, or any version of Opera Mini.
We’ve just scratched the surface of pointer-events
in this piece. For a more in-depth, technical treatment, read through the SVG Specification. MDN (Mozilla Developer Network) Web Docs offers more web developer-friendly documentation for pointer-events
, complete with examples.
Further Reading
- CSS Scroll Snapping Aligned With Global Page Layout: A Full-Width Slider Case Study
- New CSS Viewport Units Do Not Solve The Classic Scrollbar Problem
- Better Context Menus With Safe Triangles
- Modern Technology And The Future Of Language Translation