Amit
Amit

Reputation: 6294

Why would CSS ignore selector under attribute

I have a button: <button class="outline">Outline</button> which I want to set the outline on, but all of the other buttons should not have outline.

If give it a class b1 and do:

[dir="ltr"] .b1 {
    border: 0;
}
[dir="ltr"] .b1.outline {
    border-width: 1px;
}

It does not have an outline.

However, if give it a class b2 and do:

.b2 {
  border: 0;
}
.b2.outline {
  border-width: 1px;
}

It does have an outline!

Codepen to see for yourselves: https://codepen.io/anon/pen/gRMBdZ

Why does that happen?

Upvotes: 3

Views: 154

Answers (5)

hungerstar
hungerstar

Reputation: 21675

This has to do with specifity and the use of border: 0;. The specificity of the two sets of selectors applies border: 0; in a different order than one another. border is a shorthand property used to apply border-width, border-style and border-color. Applying 0 or none will remove the styles for all of those properties.

In your CodePen you have button.outline which is playing a role in the visibility of the button's border.

Your first set is applied in this order:

  1. button.outline - border-style and border-color properties applied
  2. [dir="ltr"] .b1 - border properties removed with border: 0;
  3. [dir="ltr"] .b1.ouline - border-width applied, no color or style

Border is not visible even though there is a width because the rest of the border properties do not have values that would make it visible, like color and style.


Your second set is applied in this order:

  1. .b2 - border properties removed with border: 0;
  2. button.outline - border-style and border-color properties applied
  3. .b2.ouline - border-width applied

Border is visible because we have border properties that make it visible, i.e. width, color, style.

Upvotes: 4

tao
tao

Reputation: 90013

It's because

border:0;

... translates to:

border-top-color: initial;
border-top-style: initial;
border-top-width: 0px;
border-right-color: initial;
border-right-style: initial;
border-right-width: 0px;
border-bottom-color: initial;
border-bottom-style: initial;
border-bottom-width: 0px;
border-left-color: initial;
border-left-style: initial;
border-left-width: 0px;
border-image-source: initial;
border-image-slice: initial;
border-image-width: initial;
border-image-outset: initial;
border-image-repeat: initial;

This means the border-style property is set to initial, which defaults it to none. The width applies, but the style is initial = none. You need to set it any render-able value so it applies a visible border:

[dir="ltr"] .b1 {
  border: 0;
}

[dir="ltr"] .b1.outline {
  border-width: 1px;
  border-style: solid;
}

Upvotes: 3

wortwart
wortwart

Reputation: 3350

Because the styles with the [dir="ltr"] selector have higher precedence.

When you set:

[dir="ltr"] .b1 {border: 0}

You make all border-specific declarations in button.outline {...} obsolete. Therefore you have a border-width, but neither border-style nor border-color which are just as well necessary.

Upvotes: 0

p1errot
p1errot

Reputation: 41

Take in count the rules of CSS. If you have more levels of nesting, this will be the priority. In your case, .b2 is the basic level, so when you set button.outline this will be more important than .b2 rule, for that reason all .b2 elements will have the outline. If you want to rewritte the rules, you have to call button.b2.outline instead only .b2

    /* BASE CLASSES */
    button {
        font-size: 1.7rem;
    }
    .outline { /* Only use one level */
        border-style: solid;
        border-color: #387ef5;
        color: #387ef5;
        background-color: transparent;
    }

    /* B1 + DIRECTION */
    [dir="ltr"] .b1 {
        border: 0;
    }
    [dir="ltr"] .b1.outline {
        border-width: 1px;
    }

    /* B2 NO DIRECTION */
    button.b2 { /* Be more specific to replace previous rule */
      border: 0;
    }
    button.b2.outline {
      border-width: 1px;
    }

Upvotes: 0

Jennifer Goncalves
Jennifer Goncalves

Reputation: 1512

When you add the [dir="ltr"], it changes the order in which rules are processed.

For Button 1 (no outline):

[dir="ltr"] .b1.outline {
    border-width: 1px;
}

[dir="ltr"] .b1 {
    border: 0;
}

button.outline {
    border-style: solid;
    border-color: #387ef5;
    color: #387ef5;
    background-color: transparent;
}

button {
    font-size: 1.7rem;
}

And for Button 2 (outline):

.b2.outline {
    border-width: 1px;
} 

button.outline {
    border-style: solid;
    border-color: #387ef5;
    color: #387ef5;
    background-color: transparent;
}

.b2 {
    border: 0;
}

button {
    font-size: 1.7rem;
}

Notice how button.outline is the 3rd rule on Button 1 and the 2nd rule on Button 2 since the specificity changed.

Upvotes: 2

Related Questions