Using SVG with CSS3 and HTML5 — Supplementary Material

Example code and online extras for the O'Reilly Media book by Amelia Bellamy-Royds, Kurt Cagle, and Dudley Storey.

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:

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.