Styling raw XML directly with CSS stylesheets is a clean, lightweight approach for rendering structured data in browsers. However, targeting XML attributes that include a namespace prefix—such as xml:id—can be tricky because standard CSS attribute selectors don't treat colons as plain characters.

If you've tried foo[xml:id='bar'] or escaping the colon with foo[xml\:id='bar'] and found that it does nothing, here is an explanation of why that happens and how to fix it.

Why Doesn't xml\:id Work?

In XML, xml:id represents an attribute in the predefined XML namespace (http://www.w3.org/XML/1998/namespace). CSS does not treat the colon (:) as a regular attribute name delimiter; instead, CSS uses the pipe character (|) for namespace separation.

Depending on your requirements, there are two primary solutions to target xml:id in modern browsers.

Solution 1: Use the Standard ID Selector (Recommended)

Because the xml:id specification explicitly marks the attribute as a unique document identifier, compliant XML parsers automatically recognize it as the element's ID. Therefore, you can target it directly using the standard CSS ID selector (#):

foo#bar::after {
  content: " more stuff";
}

/* Or simply target by ID */
#bar::after {
  content: " more stuff";
}

Note: It is best practice to use the modern double-colon pseudo-element syntax (::after) rather than the legacy single-colon syntax (:after).

Solution 2: Declare the XML Namespace in CSS

If you prefer or require an explicit attribute selector, you must declare the XML namespace using the @namespace rule and use the pipe syntax (|) instead of a colon:

@namespace xml url(http://www.w3.org/XML/1998/namespace);

foo[xml|id='bar']::after {
  content: " more stuff";
}

Solution 3: Use the Universal Namespace Wildcard

If you do not want to declare the namespace explicitly at the top of your stylesheet, you can use the wildcard namespace selector (*|):

foo[*|id='bar']::after {
  content: " more stuff";
}

This rule matches any id attribute on a <foo> element, regardless of its namespace.

Complete Working Example

Here is how your XML and CSS files should be structured together:

Document: foo.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="foo.css"?>
<foo xml:id="bar">stuff</foo>

Stylesheet: foo.css

@namespace xml url(http://www.w3.org/XML/1998/namespace);

/* Both of these selectors will now work reliably */
#bar::after {
  content: " more stuff";
}

foo[xml|id='bar'] {
  display: block;
  font-weight: bold;
}

Summary

  • Do not use colons or escaped colons (xml\:id) for namespaced XML attributes in CSS.
  • Use standard ID selectors like #bar for quick and universal matching.
  • Use @namespace xml url(http://www.w3.org/XML/1998/namespace); combined with [xml|id='bar'] for strict attribute matching.