Is there a CSS selector by class prefix?
Asked Answered
C

4

244

I want to apply a CSS rule to any element whose one of the classes matches specified prefix.

E.g. I want a rule that will apply to div that has class that starts with status- (A and C, but not B in following snippet):

<div id='A' class='foo-class status-important bar-class'></div>
<div id='B' class='foo-class bar-class'></div>
<div id='C' class='foo-class status-low-priority bar-class'></div>

Some sort of combination of:
div[class|=status] and div[class~=status-]

Is it doable under CSS 2.1? Is it doable under any CSS spec?

Note: I do know I can use jQuery to emulate that.

Culpa answered 26/7, 2010 at 20:22 Comment(0)
P
499

It's not doable with CSS2.1, but it is possible with CSS3 attribute substring-matching selectors (which are supported in IE7+):

div[class^="status-"], div[class*=" status-"]

Notice the space character in the second attribute selector. This picks up div elements whose class attribute meets either of these conditions:

  • [class^="status-"] — starts with "status-"

  • [class*=" status-"] — contains the substring "status-" occurring directly after a space character. Class names are separated by whitespace per the HTML spec, hence the significant space character. This checks any other classes after the first if multiple classes are specified, and adds a bonus of checking the first class in case the attribute value is space-padded (which can happen with some applications that output class attributes dynamically).

Naturally, this also works in jQuery, as demonstrated here.

The reason you need to combine two attribute selectors as described above is because an attribute selector such as [class*="status-"] will match the following element, which may be undesirable:

<div id='D' class='foo-class foo-status-bar bar-class'></div>

If you can ensure that such a scenario will never happen, then you are free to use such a selector for the sake of simplicity. However, the combination above is much more robust.

If you have control over the HTML source or the application generating the markup, it may be simpler to just make the status- prefix its own status class instead as Gumbo suggests.

Pulpy answered 21/12, 2011 at 10:42 Comment(10)
If for whatever strange reason you have a class called status- and you don't want to match that, the selector becomes even more complicated: div[class^="status-"]:not(.status-), div[class*=" status-"]:not(.status-) Plus you lose IE7/IE8 support. Thankfully, if your markup is sane, you won't need to exclude such a class.Pulpy
What is wrong with this: [class*=" anim-overlay-"] a:hover:after{...}. My CSS classes are anim-overlay-1, anim-overlay-2..... anim-overlay-8Walcott
@WebDevRon: You forgot the ^= part. If your class attribute is guaranteed to start with anim-overlay- then you probably don't need the *= part.Pulpy
Thank you. Another thing, can I use this .anim-overlay-*{...}?Walcott
@WebDevRon: Don't you think I would have proposed that in my answer if it was that simple, instead of the convoluted solution that you're looking at?Pulpy
@Daniel Compton: Thanks for the edit. I've been made aware in hindsight of how words like that can be condescending to someone for whom something might not be so obvious. I know some people really don't appreciate this sort of change, so I'm responding mostly to let you know that I do.Pulpy
As per the HTML specification link you provided, class names can be separated by any ASCII whitespace, including for example tabs and line breaks. So for example if the HTML document has class="fooTABstatus-important" or class="fooNEWLINEstatus-important", would the selector still match this class? Does the CSS specification say that a space in a selector will match any whitespace, or just the literal space character? If it only matches a literal space character, this selector is not guaranteed to always work.Atman
@Garret Wilson: Your intuition is correct; this selector does not account for other types of whitespace. It is extremely tedious and an enormous waste of bytes to repeat this selector for all possible whitespace characters, the rest of which you're almost never going to encounter more than once in your entire career or lifetime. If the application is known to output class attributes with newlines, tabs, form feeds or what have you, or any combination thereof, you will have to account for those. If it is known not to do so, then this is as robust as you will realistically need.Pulpy
OK, fine, but that's not what the answer says. In computer science there is a very big difference between something that works and something that works "most of the time". The answer makes it seem like it is a conforming CSS selector match rule, when it is not. In my opinion you can run into big trouble saying, "it worked with the data I tested it on, even though it doesn't cover spec variations". It's the same danger as parsing XML with regular expressions rather than an XML parser. At the very least, the answer needs the disclaimer that is a heuristic that does not cover all possibilities.Atman
@Garret Wilson: A fair compromise. Mind you, I'm familiar with what you said (even though I never took CS) and I have been more diligent in stating as many caveats as possible and more careful to add disclaimers to my answers in recent years - this was from almost 8 years ago and I tend not to have the energy to make more than minor changes to older answers unless it's super important. Used to be I left the most extreme edge cases out on purpose because I didn't want to turn 3 paragraphs into 10 with the rest ending up irrelevant to 90% of readers and 99% of real-world scenarios.Pulpy
A
24

CSS Attribute selectors will allow you to check attributes for a string. (in this case - a class-name)

https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors

(looks like it's actually at 'recommendation' status for 2.1 and 3)


Here's an outline of how I *think it works:

  • [ ] : is the container for complex selectors if you will...
  • class : 'class' is the attribute you are looking at in this case.
  • * : modifier(if any): in this case - "wildcard" indicates you're looking for ANY match.
  • test- : the value (assuming there is one) of the attribute - that contains the string "test-" (which could be anything)

So, for example:

[class*='test-'] {
  color: red;
}

You could be more specific if you have good reason, with the element too

ul[class*='test-'] > li { ... }

I've tried to find edge cases, but I see no need to use a combination of ^ and * - as * gets everything...

example: http://codepen.io/sheriffderek/pen/MaaBwp

http://caniuse.com/#feat=css-sel2

Everything above IE6 will happily obey. : )

note that:

[class] { ... }

Will select anything with a class...

Allowable answered 11/9, 2015 at 17:59 Comment(3)
[class*='test-'] will match elements such as <div class='foo-test-bar'>. That's the one edge case that requires combining ^ and * as described in my answer. And IE6 does not support attribute selectors.Pulpy
@Pulpy - thanks for clarifying! - I don't support < EI9 - and i would never write any classes that would step on each other - so for me this works. : )Allowable
It's funny when CSS Selectors return to Regex. Lol. I knew it wasn't a useless skill!Folio
T
5

This is not possible with CSS selectors. But you could use two classes instead of one, e.g. status and important instead of status-important.

Tricornered answered 26/7, 2010 at 20:23 Comment(1)
Good idea about separating it into its own class, but it is possible with CSS selectors. See my answer.Pulpy
B
2

You can't do this no. There is one attribute selector that matches exactly or partial until a - sign, but it wouldn't work here because you have multiple attributes. If the class name you are looking for would always be first, you could do this:

<html>
<head>
<title>Test Page</title>
<style type="text/css">
div[class|=status] { background-color:red; }
</style>
</head>
<body>
<div id='A' class='status-important bar-class'>A</div>
<div id='B' class='bar-class'>B</div>
<div id='C' class='status-low-priority bar-class'>C</div>

</body>
</html>

Note that this is just to point out which CSS attribute selector is the closest, it is not recommended to assume class names will always be in front since javascript could manipulate the attribute.

Betimes answered 26/7, 2010 at 20:30 Comment(2)
yeah, thought of that. It might become an issue when jQuery gets into picture, since it might insert a class at the front.Culpa
Yeah I'll edit my post to make it clear it clearly isn't a recommended way of doing it. If you have control over the class names then Gumbo's suggestion definitely would be the way to go (plus attribute selectors on older IE browsers is not supported).Betimes

© 2022 - 2024 — McMap. All rights reserved.