What's the difference between targeting class by ".class" or "*[class~=box]" in css?

Viewed 241

Let's say I have an html element with a class of box: <p class="box alert">Content here</p>

Recently I learned about a way of targeting elements in CSS, so if I want to select any element with a class of box I could use this: *[class~=box] {border: 2px solid grey;}

And I'm wondering, isn't it literally the same as just targeting an element by a class name? Or I didn't get it correctly? .box {border: 2px solid grey;}

If it is the same, in which situations it is appropriate to use the second method rather than the first one?

4 Answers

An attribute selector is not really designed for classes, it is designed for other attributes in elements for example a[href*="google"], but yes you can style elements like this and that would be definitely considered an anti-pattern.

Although .classname and [class~="classname"] would style the same elements the CSS specificity of those selectors would be calculated differently - to be honest, I'm not exactly sure but *[class~="classname"] could win with .classname and it's something a person working with styles which had been written like that should be aware of.

For the sake of selecting, the selectors are indeed equivalent. The differences between them are both practical and historical.

Practical difference

From a practical point of view, the class selector is far more readable and straightforward. It is also far more efficient, since browsers treat classes differently than other attributes, for CSS and DOM queries. The attribute selector in general makes more sense for any other attribute that is not a class, when you wish to select by a single value out of "a whitespace-separated list of words, one of which is exactly value" (MDN spec).

For example, if you have a data attribute with several possible values to choose from like so:

<div data-colors="blue">
<div data-colors="yellow blue">
<div data-colors="red blue green">

The attribute selector [data-colors~=blue] would select all three elements, regardless of any other values in the attribute.

Historical difference

Historically, the class selector .box is part of the original CSS specification (.i.e "CSS 1"). This means this selector is supported by any browser past and present. On the other hand, the attribute selector [class~=box] is only part of the second iteration of the CSS specification (i.e. "CSS2") and is therefore not supported by every possible browser; though you would have to go back as far as Internet Explorer 6 to run into issues with this selector.

One important difference is the use of some special names with your classes.

Here is an example to illustrate:

.box {
  height:50px;
  background:red;
  margin:5px;
}

.80% {
  width:80%;
}

.50% {
  width:50%;
}
<div class="box 80%"></div>
<div class="box 50%"></div>

In the above nothing will happen because we need to escape the number and % inside the selector but with the attribute selector it's easy:

.box {
  height:50px;
  background:red;
  margin:5px;
}

[class~="80%"] {
  width:80%;
}

[class~="50%"] {
  width:50%;
}
<div class="box 80%"></div>
<div class="box 50%"></div>

For the first you need to write the following which is no trivial:

.box {
  height:50px;
  background:red;
  margin:5px;
}

.\38 0\% {
  width:80%;
}

.\35 0\% {
  width:50%;
}
<div class="box 80%"></div>
<div class="box 50%"></div>

Both would have exactly the same result so *[class~="classname"] is equivalent to .classname, just that the selection is made using the class attribute. See attribute selector to get more info on this syntax.

.classname {
  color: blue;
}

*[class~="classname"] {
  color: red;
}
<p class="classname">Content here</p>

*[class~="classname"] {
  color: red;
}

.classname {
  color: blue;
}
<p class="classname">Content here</p>

Related