Selecting an element by its attribute when it has a colon in its name
Asked Answered
A

3

20

Consider the CSS selection I have here:

http://jsfiddle.net/dx8w6b64/

/* This works:
 #myChart .ct-series-b .ct-bar { 
 */


/* This does not (chromium, glnxa64) */
['ct\:series-name'='second'] .ct-bar {
  /* Colour of your points */
  stroke: black;
  /* Size of your points */
  stroke-width: 20px;
  /* Make your points appear as squares */
  stroke-linecap: round;
}

This is a sample chart using https://gionkunz.github.io/chartist-js/

I am trying to select the ct-bar elements:

enter image description here

The colon appears to be throwing off the selector. I have tried various escape approaches :, \3A with a space after, single and double quotes - no luck.

Amorete answered 24/12, 2015 at 2:6 Comment(10)
don't put the attribute in quotes at all, i.e. [ct\:series-name='second'] (not tested but I just read about this somewhere yesterday)Photokinesis
That's kinda odd. [ct\:series-name="second"] works here, but not here. In the DOM, the attribute is displayed as ct:series-name="second", but when you inspect the actual HTML, the attribute is series-name="second" (for me at least in the Chrome console).Keewatin
See #24629432 and #24391058Affective
@JoshCrozier: I am on Chrome v49... dev-m and it does display as ct:series-name="second" in the console but neither ct\:series-name nor ct|series-name works. Very interesting. (And your first fiddle works fine for me too)Harragan
Does nobody here know XML? That is very clearly a namespace prefix - and we're dealing with SVG, an XML-based markup language here, not HTML.Painting
@BoltClock: It took sometime to figure that out but I did eventually :DHarragan
Possible duplicate of How to use CSS attribute selector for an SVG element with namespaced attribute href?Pseudoscope
@Pseudoscope - Maybe for the core solution, but the answer shows here how to deduce the namespace url to use. So it goes beyond the one you linked.Amorete
But I marked the questions as duplicates, not the answers.Pseudoscope
For anyone interested in the JavaScript side of the question, see #23034783Touraco
P
10

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.

Painting answered 24/12, 2015 at 5:45 Comment(8)
Oh I see so that is the reason why \: doesn't work even after adding the namespace declaration.Harragan
Or easier, use a wildcard namespace (*|attr), no need to declare the namespaces. See https://mcmap.net/q/338383/-is-it-possible-to-use-html-39-s-queryselector-to-select-by-xlink-attribute-in-an-svgPseudoscope
@Kaiido: That's assuming the attribute names are unique enough to their respective namespaces that you don't actually need the namespace name to disambiguate (which is, you know, the whole point of namespaces).Painting
Well, that's an important notice to add if you want to include it as an edit, but, you know, you can't only select by the attribute, you also need the value to make a match. So the worthiest case is *|attr*="a_contained_value", where another named-space attribute will be exactly the same as the required attr, which I assume will represent less than 1% of any reader's case. Moreover, attribute selectors should be used with an other selector type (you probably don't want all your <img> tags to get the same width as the <audio> ones just because they contains the same src value.)Pseudoscope
I have a feeling you don't actually mean "can't" in your first sentence so much as "don't often", because [*|attr] is perfectly legal. Again, there is nothing stopping you from making assumptions about your markup if you can rely on them - just remember you made those assumptions once you start running into unforeseen problems.Painting
Did you ever felt onto such unforeseen problem ? Also, I almost always used it with querySelector where there is unfortunately no option to declare the namespaces...Pseudoscope
Pleae note that this namespace declaration have to be placed at the top of your css file. More precisely, as stated in this thread #24629432, a normal CSS rule must not precede any \@namespace rules, or the \@namespace rules are invalid. The CSS Namespaces Module Level 3 w3.org/TR/css3-namespace says that > Any \@namespace rules must follow all \@charset and \@import rules and precede all other non-ignored at-rules and style rules in a style sheet.Weston
@AlexLaforge: I remember answering that question. I remember the style rule appearing before the at-namespace rule not being there when I first answered it, then the asker realized it by looking at their own code, hence the edit.Painting
A
3

You shouldn't quote the attribute name, otherwise you are correctly escaping the colon.

[ct\:series-name='second'] 

See https://msdn.microsoft.com/en-us/library/ms762307(v=vs.85).aspx

Affective answered 24/12, 2015 at 2:14 Comment(4)
I remember trying that too. Like this: jsfiddle.net/whfactq2 ? Still doesn't appear to work :(Amorete
My bad, I usually test my answers, but I'm on my phone, have you seen the @namespace syntax? developer.mozilla.org/en-US/docs/Web/CSS/@namespaceAffective
That MSDN document appears to be a very old one - it refers to IE as "Microsoft® Internet Explorer", which was last used with IE6 before they started calling it "Windows® Internet Explorer" with IE7 in 2006. @namespace was introduced and implemented relatively recently - with IE first implementing it in version 9 in 2011, along with introducing support for application/xhtml+xml.Painting
@JuanMendes - thanks for the tip about \@namespace - didnt know enough to figure it out without Boltclock's answer.Amorete
H
3

It seems like the namespace selector would work only when the namespace is defined within the CSS itself in the below format:

@namespace <namespace-prefix>? [ <string> | <uri> ];

From Selectors Spec: emphasis is mine

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" (|).

An attribute selector with an attribute name containing a namespace prefix that has not been previously declared is an invalid selector.

Once we add the namespace definition for ct into the CSS, the namespace based selector works as expected. The namespace's URI was taken from the <svg> tag that was generated.

var data = {
  labels: ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9', 'W10'],
  series: [{
    name: 'first',
    data: [1, 2, 4, 8, 6, -2, -1, -4, -6, -2]
  }, {
    name: 'second',
    data: [3, 4, 2, 6, 3, 2, 1, 4, 6, 2]
  }]
};

var options = {
  high: 10,
  low: -10,
  onlyInteger: true
};

new Chartist.Bar('.ct-chart', data, options);
@namespace ct url(http://gionkunz.github.com/chartist-js/ct);
[ct|series-name="second"] .ct-bar {
  stroke: black !important; /* without important it doesn't seem to work in snippet but works in fiddle */
  stroke-width: 20px;
  stroke-linecap: round;
}
<script src="https://cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
<link href="https://cdn.jsdelivr.net/chartist.js/latest/chartist.min.css" rel="stylesheet" />
<div id="myChart" class="ct-chart" style="height:400px"></div>

Fiddle Demo.


Note: The below selector doesn't work even after the namespace definition is added. The reason for this is provided by BoltClock in his answer.

[ct\:series-name="second"] .ct-bar {}
Harragan answered 24/12, 2015 at 5:6 Comment(1)
Pleae note that this namespace declaration have to be placed at the top of your css file. More precisely, as stated in this thread #24629432, a normal CSS rule must not precede any \@namespace rules, or the \@namespace rules are invalid. The CSS Namespaces Module Level 3 w3.org/TR/css3-namespace says that > Any \@namespace rules must follow all \@charset and \@import rules and precede all other non-ignored at-rules and style rules in a style sheet.Weston

© 2022 - 2024 — McMap. All rights reserved.