How to use CSS attribute selector for an SVG element with namespaced attribute href?
Demo Fiddle
Firstly, in order to use xlink
slectors, you need to to declare the xlink
namespace at the top of your stylesheet according to the spec:
@namespace xlink 'http://www.w3.org/1999/xlink';
Then, you can use the following attribute selector with a namespace prefix:
svg image[xlink|href*="temp"] {
outline: 3px solid red;
}
The attribute name in an attribute selector is given as a CSS
qualified name: a namespace prefix that has been previously declared
may be prepended to the attribute name separated by the namespace
separator "vertical bar" (|). In keeping with the Namespaces in the
XML recommendation
Do CSS namespace attribute selectors work with XHTML/HTML elements?
They do. You've just set up either your markup or your CSS rules incorrectly.
Your attribute selectors are looking for elements with href
attributes (in the respective namespaces), but your <p>
elements have xref
attributes, not href
attributes, so they don't match.
Your <xyz:p>
and <xyz>
elements on the other hand all have href
attributes, so those are the ones that end up matching your attribute selectors instead.
Is it possible to use HTML's .querySelector() to select by xlink attribute in an SVG?
Query selector can handle namespaces, but it gets tricky because
The syntax for specifying namespaces in CSS selectors is different from html;
The querySelector API doesn't have any method for assigning a namespace prefix (like
xlink
) to an actual namespace (like"http://www.w3.org/1999/xlink"
).
On the first point, the relevant part of the CSS specs allows you to specify no namespace (the default), a specific namespace, or any namespace:
@namespace foo "http://www.example.com";
[foo|att=val] { color: blue }
[*|att] { color: yellow }
[|att] { color: green }
[att] { color: green }
The first rule will match only elements with the attribute
att
in the "http://www.example.com" namespace with the value "val".The second rule will match only elements with the attribute
att
regardless of the namespace of the attribute (including no namespace).The last two rules are equivalent and will match only elements with the attribute
att
where the attribute is not in a namespace.
See this fiddle, paying attention to the fill styles (default, hover, and active):
https://jsfiddle.net/eg43L/
The Selectors API adopts the CSS selector syntax, but has no equivalent to the @namespace
rule for defining a namespace. As a result, selectors with namespaces are not valid but the wildcard namespace token is valid:
If the group of selectors include namespace prefixes that need to be resolved, the implementation must raise a SYNTAX_ERR exception ([DOM-LEVEL-3-CORE], section 1.4).
This specification does not provide support for resolving arbitrary namespace prefixes. However, support for a namespace prefix resolution mechanism may be considered for inclusion in a future version of this specification.
A namespace prefix needs to be resolved if the namespace component is neither empty (e.g.
|div
), representing the null namespace, or an asterisk (e.g.*|div
), representing any namespace. Since the asterisk or empty namespace prefix do not need to be resolved, implementations that support the namespace syntax in Selectors must support these.
(bold added)
Check out the fiddle again, this time paying attention to the console output. The command document.querySelector('[*|href="#url"]')
returns the element you want.
One final warning: MDN tells me that IE8- do not support CSS namespaces, so this might not work for them.
Update 2015-01-31:
As @Netsi1964 pointed out in the comments, this doesn't work for custom namespaced attributes in HTML 5 documents, since HTML doesn't support XML namespaces. (It would work in a stand-alone SVG or other XML document including XHTML.)
When the HTML5 parser encounters an attribute like data:myAttribute="value"
it treats that as a single string for the attribute name, including the :
. To make things more confusing, it auto-lowercases the string.
To get querySelector
to select these attributes, you have to include the data:
as part of the attribute string. However, since the :
has special meaning in CSS selectors, you need to escape it with a \
character. And since you need the \
to get passed through as part of the selector, you need to escape it in your JavaScript.
The successful call therefore looks like:
document.querySelector('[data\\:myattribute="value"]');
To make things a little more logical, I would recommend using all lower-case for your attribute names, since the HTML 5 parser will convert them anyway. Blink/Webkit browser will auto-lowercase selectors you pass querySelector
, but that's actually a very problematic bug (in means you can never select SVG elements with mixed-case tag names).
But does the same solution work for xlink:href
? No! The HTML 5 parser recognizes xlink:href
in SVG markup, and correctly parses it as a namespaced attribute.
Here's the updated fiddle with additional tests. Again, look at the console output to see the results. Tested in Chrome 40, Firefox 35, and IE 11; the only difference in behavior is that Chrome matches the mixed-case selector.
Selecting an element by its attribute when it has a colon in its name
I've never used Chartist, but judging by the ct:
namespace prefix, it appears to be an extension to SVG markup. So you're no longer really dealing with HTML here; you're dealing with XML, because SVG is an XML-based markup language.
Escaping the colon or otherwise specifying it as part of the attribute name doesn't work because the ct:
no longer becomes part of the attribute name when it's treated like a namespace prefix (which is what it is). In a regular HTML document, an attribute name like ct:series-name
would indeed include the prefix, because namespace prefixes only have special meaning in XML, not in HTML.
Anyway, the web inspector shows the following XML for your svg
start tag:
<svg class="ct-chart-bar" xmlns:ct="http://gionkunz.github.com/chartist-js/ct" width="100%" height="100%" style="width: 100%; height: 100%;">
What you need to do is reflect this XML namespace in your CSS using a @namespace rule
:
@namespace ct 'http://gionkunz.github.com/chartist-js/ct';
And, rather than escaping the colon, use a pipe to indicate a namespace prefix:
[ct|series-name='second'] .ct-bar {
stroke: black;
stroke-width: 20px;
stroke-linecap: round;
}
And it should work as expected.
Selecting elements with specific namespaced attributes
Use XPath, specifying the namespace for the g
elements. Since your root element declares the xmlns:svg
to be the same as the new default namespace (xmlns
) you can use svg
as your prefix:
require 'nokogiri'
doc = Nokogiri.XML(IO.read('contents.xml'))
layers = doc.xpath('//svg:g[@inkscape:groupmode="layer"]')
p layers.map{ |layer| layer['id'] }
#=> ["layer1", "g2818"]
Decoded, the above XPath says:
//
- At any level of the documentsvg:g
- …findg
elements with a namespace matching thesvg
namespace[…]
- …but only if the contents of this are met@inkscape:groupmode
- …there is an attribute (@
) namedgroupmode
with a namespace matchinginkscape
="layer"
- and the intrinsic value of this attribute is the textlayer
.
Alternatively, if you're just trying to read this file (and not manipulate and re-save it) you can use the gross-but-simplifying hack of removing all namespaces. In this case, your original code works simply:
doc.remove_namespaces!
p doc.css('g[groupmode="layer"]').map{ |g| g['id'] }
#=> ["layer1", "g2818"]
How to select XML element by xlink:href attribute with CSS?
Using CSS attribute selectors, you'd need to escape the colon :
by a leading backslash\
, as follows:
description[xlink\:href="http://book.com/images/HPotter.gif"] {
background-color: gold;
}
<?xml version="1.0" encoding="UTF-8"?>
<bookstore xmlns:xlink="http://www.w3.org/1999/xlink">
<book title="Harry Potter">
<description
xlink:type="simple"
xlink:href="http://book.com/images/HPotter.gif"
xlink:show="new"> ... </description>
</book>
<book title="XQuery Kick Start">
<description
xlink:type="simple"
xlink:href="http://book.com/images/XQuery.gif"
xlink:show="new"> ... </description>
</book>
</bookstore>
WORKING DEMO.
Related Topics
Css: Set Color for Selected Row in a Table
How to Change Height of Ui-Grid Row
Pure CSS Drop Down Menu - Unable to Keep Top <Li> Highlighted When Hovering Over Sub-Menu
Make Hexagon Shape with Border, Rounded Corners and Transparent Background
What Does 14Px/26Px Font Size in CSS Do
Sass: How to Remove /*# Sourcemappingurl Comment
How to Make a Verticallayout Scrollable Using Vaadin
How to Scroll Through a Div Without the Scrollbars Showing
Internet Explorer Creates Horizontal Scrollbar for Vertical Scrollbar's Width
CSS Resize Property - Change Resize Icon Properties