133

I'm a little confused about CSS and the class attribute. I always thought, the order in which I specify multiple classes in the attribute value has a meaning. The later class could/should overwrite definitions of the previous, but this doesn't seem to work. Here's an example:

<html>
<head>
<style type="text/css">
    .extra {
        color: #00529B;
        border:1px solid #00529B; /* Blue */
        background-color: #BDE5F8;
    }

    .basic {
           border: 1px solid #ABABAB;
    }
</style>
</head>
<body>
    <input type="text" value="basic" class="basic"/>
    <input type="text" value="extra" class="extra"/>
    <input type="text" value="basic extra" class="basic extra"/>
    <input type="text" value="extra basic" class="extra basic"/>
</body>
</html>

I would expect, the third example with class="basic extra" should have a blue border, since the in extra specified border would overwrite the border from basic.

I'm using FF 3 on ubuntu 9.04

mixel
  • 25,177
  • 13
  • 126
  • 165
Tim Büthe
  • 62,884
  • 17
  • 92
  • 129

3 Answers3

282

The order in which the attributes are overwritten is not determined by the order the classes are defined in the class attribute, but instead where they appear in the CSS.

.myClass1 {color:red;}
.myClass2 {color:green;}
<div class="myClass2 myClass1">Text goes here</div>

The text in the div will appear green, and not red; because .myClass2 is further down in the CSS definition than .myClass1. If I were to swap the ordering of the class names in the class attribute, nothing would change.

someOne
  • 1,975
  • 2
  • 14
  • 20
Zoidberg
  • 10,137
  • 2
  • 31
  • 53
  • 30
    I can't understand why they'd implement it like this. Funnily enough that's also my opinion for most other things CSS can do. – byxor Apr 18 '18 at 22:08
  • 4
    @ because because rules are _cascading_. they apply form top to bottom, left to right. makes sense to me – O-9 Jul 03 '20 at 09:56
  • I actually noticed in Bootstrap that my custom "back-to-top" class was ignored inside a

    tag. But then when I reversed them and put my custom class first, both my class and Bootstrap's class' features were accepted:

    . Any idea why?

    – Peter G. Williams Aug 19 '20 at 22:11
  • Depends on the attributes defined in each class. If your custom class specified a border of 1px solid black and the bootstrap class had nothing defined for borders, then your border attribute would be used. – Zoidberg Sep 07 '20 at 14:16
  • @O-9 In the modern world, the order of the CSS rules is pretty random. My dev server and webpack build give different results. It's just bad design, plain and simple. – Ark-kun Jul 28 '21 at 07:40
  • what happens if the classes are in different files. Will the order of the files be a deciding factor then (i.e the class in the file that was declared later will take precedence) – Anupam Sep 24 '21 at 08:42
  • Because of JS being able to dynamically add or remove classes (see: `element.classList.add()`) the order in the HTML should not have impact. The only place where it should have any sort of impact is a preprocessor of HTML or dynamic HTML builder (aka a JS framework) where it can detect the style rules and resolve it in some programmatic way (see: Stylex), but this would actually output new classes or remove duplicate properties to generate the expected output. – Mark Oct 12 '22 at 19:19
30

The order of classes in the attribute is irrelevant. All the classes in the class attribute are applied equally to the element.

The question is: in what order do the style rules appear in your .css file. In your example, .basic comes after .extra so the .basic rules will take precedence wherever possible.

If you want to provide a third possibility (e.g., that it's .basic but that the .extra rules should still apply), you'll need to invent another class, .basic-extra perhaps, which explicitly provides for that.

VoteyDisciple
  • 37,319
  • 5
  • 97
  • 97
5

This can be done, but you have to get a little creative with your selectors. Using attribute selectors, you can specify things like "begins with", "ends with", "contains", etc. See example below using your same markup, but with attribute selectors.

[class$="extra"] {
  color: #00529B;
  border:1px solid #00529B;
  background-color: #BDE5F8;
}
[class$="basic"] {
  border: 1px solid #ABABAB;
}
input {display:block;}
<input type="text" value="basic" class="basic"/>
<input type="text" value="extra" class="extra"/>
<input type="text" value="basic extra" class="basic extra"/>
<input type="text" value="extra basic" class="extra basic"/>
TravisV
  • 51
  • 1
  • 1