Undistraction
Undistraction

Reputation: 43589

Universal Selector with Descendent Selector Specificity

I have a generic layout component that needs to lay out its children with a vertical space between them:

.container > * + * {
  margin-top: 1rem;
}

For reasons I won't go into, I can't guarantee the order the component styles are loaded in.

If a child component has had a reset to its margins applied, for example …

.child {
  margin: 0
}

… and it is loaded after the .container css, its styled will win out because a wildcard selector has no specificity, meaning both declarations are of equal weight (so the last declaration will win).

I don't want the container to know or care about what its children are (and I don't want to add a specific class to all the children).

Is there any way to increase the specificity of the first selector while leaving it generic (so it applies to any children).

Upvotes: 2

Views: 180

Answers (2)

BoltClock
BoltClock

Reputation: 723448

A more elegant alternative (i.e. one that comes with the additional specificity you need without requiring specificity hacks) is

.container > :not(:first-child)

which is functionally equivalent to your original selector, with a specificity of (0, 2, 0) over the original's (0, 1, 0).

.container {
  margin: 1rem 0;
  border-style: solid;
}

/* 1 class, 1 pseudo-class -> specificity = (0, 2, 0) */
.container > :not(:first-child) {
  margin-top: 1rem;
}

/* 1 class                 -> specificity = (0, 1, 0) */
.child {
  margin: 0;
}
<div class="container">
  <div class="child">Child</div>
  <div class="child">Child</div>
  <div class="child">Child</div>
</div>
<div class="container">
  <div class="child">Child</div>
  <div class="child">Child</div>
  <div class="child">Child</div>
</div>

Upvotes: 2

Tschallacka
Tschallacka

Reputation: 28722

By adding the selector

.container > * + [class] 

You can get a more specific selector it seems for the margin rule.

You can also use the :not() rule as suggested by Temani Afif

.container, .container2, .container3 {
   background-color: goldenrod;
   border: 1px solid black;
   display: block;
   margin-bottom:50px;
}

.container > * + * {
  margin-top: 1rem;
}

.container2 > * + *,
.container2 > * + [class] {
  margin-top: 1rem;
}

.container3:not(#doyoudreamofelectricsheep) > * + * {
  margin-top: 1rem;
}


.child {
  margin: 0;
  height: 20px;
  background-color:red;
  color: black;
  
}

.foobar {
  height: 20px;
  background-color:black;
  color: white;
}
Without the "fix"
<section class="container2">
   <div class="foobar">
       foobar
   </div>
   <div class="child">
       child
   </div>
   <div class="foobar">
       foobar
   </div>
   <div class="child">
       child
   </div>
   <div class="foobar">
       foobar
   </div>
   <div class>
       just class
   </div>
</section>

With the [class] "fix"
<section class="container2">
   <div class="foobar">
       foobar
   </div>
   <div class="child">
       child
   </div>
   <div class="foobar">
       foobar
   </div>
   <div class="child">
       child
   </div>
   <div class="foobar">
       foobar
   </div>
   <div class>
       just class
   </div>
</section>

With the :not(#doyoudreamofelectricsheep) "fix"
<section class="container3">
   <div class="foobar">
       foobar
   </div>
   <div class="child">
       child
   </div>
   <div class="foobar">
       foobar
   </div>
   <div class="child">
       child
   </div>
   <div class="foobar">
       foobar
   </div>
   <div class>
       just class
   </div>
</section>

Upvotes: 1

Related Questions