XML Namespaces in CSS
XML namespaces are a frequent complication when switching from HTML to SVG. That’s true for CSS selectors, too.
Most of the time, you can ignore namespaces when writing your CSS selectors, but that just makes it all the more surprising when they cause a problem.
By default in XML, CSS tag-name selectors apply to elements defined in any namespace. Attribute selectors (like [attributeName]
or [name="value"]
), however, only apply to attributes in the default namespace—that is, attributes without a namespace prefix.
There are two cases in SVG where these defaults can be a problem:
-
when you want to distinguish between SVG and HTML elements with the same tag names (for example, the
<a>
link-anchor elements) -
when you want to select elements based on the value of a namespaced attribute (for example,
xlink:href
, or a custom attribute created by your graphics software)
To select an element tag or attribute defined in a specific namespace, you declare a namespace prefix with an @namespace
rule, then use it in your selector. The namespace is separated from the tag name with a |
(vertical bar or pipe) character; if there is no tag name in the selector, use a universal *
selector:
@namespace
svg
"http://www.w3.org/2000/svg"
;
a
{
/* These rules would apply to any `a` elements. */
text-decoration
:
underline
;
color
:
purple
;
}
svg
|
a
{
/* These rules would apply to SVG `a` elements,
but not HTML links. */
stroke
:
purple
;
}
svg
|*
{
/* These rules apply to all SVG-namespaced elements,
but not HTML elements. */
mix-blend-mode
:
multiply
;
}
The @namespace
rule can also be used with attribute selectors. The prefix and |
are applied before the attribute name.
@namespace
xl
"http://www.w3.org/1999/xlink"
;
/* Note that you can use any prefix you choose
in the CSS @namespace rule, it does not have to
match the one used in the markup. */
[
xl
|
href
]
{
/* These rules apply to elements (in any namespace)
with a namespaced `xlink:href` attribute. */
fill
:
orange
;
}
[
href
]
{
/* These rules only apply to elements
with no-namespace `href` attributes. */
fill
:
gold
;
}
[
xl
|
href
$
=
".pdf"
],
[
href
$
=
".pdf"
]
{
/* These rules apply to elements
with either type of `href` attribute,
if the attribute value ends in ".pdf" */
text-transform
:
uppercase
;
}
That last rule can be simplified, to indicate that you don’t care about the attribute namespace.
The *
(asterisk) character, when included before a |
pipe, works as a wildcard namespace prefix, matching any namespace:
[*|
href
$
=
".pdf"
]
{
/* These rules apply to elements with an `href`
attribute from any namespace, including `xlink`,
if the attribute value ends in ".pdf" */
text-transform
:
uppercase
;
}
Tip
Keep your code forward-compatible for the day when xlink
is no longer required, by using the [*|href]
syntax instead of a specific namespace prefix.
You can use namespaced attribute selectors to select custom attributes added by your graphics software, such as layer names. But, remember: The CSS namespace selectors will only work if the actual DOM elements correctly reflect the intended namespaces. If you copy your SVG code into a non-XML HTML document, these custom namespaces won’t be recognized.
If you use unrecognized namespace prefixes in your inline SVG markup, the HTML parser will include the prefix and the :
(colon) character in the attribute or tag name. If you really need to select these in CSS, use regular tag or attribute selectors based on the complete name, escaping the :
character (which has special meaning in CSS) by preceding it with a \
(backslash). For example, these styles are based on custom Inkscape attributes:
@namespace
ink
"http://www.inkscape.org/namespaces/inkscape"
;
[
inkscape
\
:groupmode
=
"layer"
],
[
ink
|
groupmode
=
"layer"
]
{
/* These rules apply to elements with the
inkscape:groupmode="layer" attribute,
in either XML or HTML documents. */
isolation
:
isolate
;
}
But it’s better to avoid trying to use unrecognized XML prefixes in an HTML document. Edit the code to add classes if you require them.
Recognized namespace prefixes, such as xlink
, are properly parsed in HTML documents. You need to use the CSS namespacing rules to select them, the same as in an SVG or XML document.
You can also declare a default namespace by omitting the prefix in the @namespace
rule. All selectors in that stylesheet will now only apply to elements in that namespace. You can cancel that out by specifically declaring another namespace, or by using the wildcard (*
) namespace prefix to modify a tag-name selector or a regular *
universal CSS selector:
@namespace
"http://www.w3.org/2000/svg"
;
@namespace
html
"http://www.w3.org/1999/xhtml"
;
a
{
/* These rules would apply to SVG links,
but not HTML links. */
stroke
:
pink
;
fill
:
currentColor
;
}
*|
a
{
/* These rules would apply to any `a` elements. */
text-decoration
:
underline
;
color
:
purple
;
}
html
|
a
{
/* These rules only apply to HTML `a` elements,
not SVG links */
text-shadow
:
pink
1px
1px
0
;
}
.special
{
/* These rules only apply to SVG-namespaced
elements with the class `special`. */
fill
:
url(#gradient)
;
}
*|*
.special
{
/* These rules apply to all elements
with the class `special`. */
font-family
:
fantasy
;
}
The default namespace declaration does not affect attribute selectors—they still apply to no-namespace attributes, unless a prefix is used.
You can’t use namespace prefixes in the querySelector()
and querySelectorAll()
methods, but you can use the *
wildcard. The primary use would be to select elements that have an xlink:href
attribute:
document
.
querySelectorAll
(
"a[*|href^='#']"
);
//returns a list of <a> elements
//that have href or xlink:href attributes
//whose values start with a `#` character
With the query-selector methods, there is no way to select SVG <a>
elements but not HTML <a>
elements, or vice versa.
Namespaces in CSS (and XML namespaces in general) are a rarely-used feature on the web today. You may sometimes find them useful to help you isolate your inline SVG styles from the rest of your document. But it is probably better to use unique classes to distinguish elements, so you don’t have conflicts if you later add other SVG to the page. The only namespaced selector we use in the book is [*|href]
(and its variants), to select elements with xlink:href
or href
attributes.