简体   繁体   中英

First-child styling only works on first element

I got some code where I'm selecting some elements by first child, and then styling the accordingly. I noticed that it behaves quite strangely, and the css is only being applied to the first element. I tried to select them both with JS, and it seems like, although I'm doing the exact same thing, just on another element, it doesn't return the div.

Code:

 console.log(document.querySelector(".index-0:first-child")); // returns div console.log(document.querySelector(".index-1:first-child")); // returns null 
 .index-0:first-child { color: green; } .index-1:first-child { color: blue; /* doesn't work */ } 
 <div class="index-0"> <p class="message"></p> <div class="shout"> <span>Message 1</span> </div> </div> <div class="index-1"> <p class="message"></p> <div class="shout"> <span>Message 2</span> </div> </div> 

jsfiddle: https://jsfiddle.net/a4k03eny/1/

You're misunderstanding how CSS selectors work. (You're not alone; this is a very frequent misunderstanding.) Compound selectors like .index-1:first-child or div.foo are "AND" operations for their individual parts: .index-1:first-child means that it matches an element that's got the class index-1 and is the first child of its parent. Your .index-1 element isn't the first child in its parent, it's the second child.

In this case, you'd use .index-1 to style it, without the :first-child bit.

(If your goal is to style the first child within .index-1 , add a > (a child combinator ):

.index-1 > :first-child {
    color: green;
}

...but I don't think that's what you're trying to do. Or you could use a space [a descendant combinator] , but that would apply to all elements within .index-1 that were the first child of their parent, which I also suspect isn't what you want to do.)


From you comment:

I want to style the first element that has a new class differently.

You can do that by combining .index-1:first-child with :not(.index-1) + .index-1 :

.index-1:first-child, :not(.index-1) + .index-1 {
    color: blue;
}

That latter uses an adjacent sibling combinator to say "apply the rules to an .index-1 that isn't immediately after an .index-1 ):

 console.log(document.querySelector(".index-0:first-child, :not(.index-0) + .index-0")); console.log(document.querySelector(".index-1:first-child, :not(.index-1) + .index-1")); 
 .index-0:first-child, :not(.index-0) + .index-0 { color: green; } .index-1:first-child, :not(.index-1) + .index-1 { color: blue; } 
 <div class="index-0"> <p class="message"></p> <div class="shout"> <span>Message 1</span> </div> </div> <div class="index-1"> <p class="message"></p> <div class="shout"> <span>Message 2</span> </div> </div> 

Of course, that requires that you style them specifically (rules for .index-0 , .index-1 , etc.). You can't do it generically in CSS, but you could in JavaScript. This looks through all elements with the class index , picks out their index-N class name if they have it, and adds highlight to the first in any given run of them:

var lastClass = null;
document.querySelectorAll(".index").forEach(function(e) {
  var m = e.className.match(/(?:^| )(index-\d+)(?: |$)/);
  var thisClass = m ? m[1] : null;
  if (thisClass != lastClass) {
    lastClass = thisClass;
    e.classList.add("highlight");
  }
});

Example:

 var lastClass = null; document.querySelectorAll(".index").forEach(function(e) { var m = e.className.match(/(?:^| )(index-\\d+)(?: |$)/); var thisClass = m ? m[1] : null; if (thisClass != lastClass) { lastClass = thisClass; e.classList.add("highlight"); } }); 
 .highlight { color: green; } 
 <div class="index index-0"> <p class="message"></p> <div class="shout"> <span>first .index-0</span> </div> </div> <div class="index index-0"> <p class="message"></p> <div class="shout"> <span>second .index-0 in a row</span> </div> </div> <div class="index index-1"> <p class="message"></p> <div class="shout"> <span>first .index-1</span> </div> </div> 

Note: Many browsers now support forEach on the NodeList returned by querySelectorAll , but not quite all do. You can polyfill it if missing:

if (typeof NodeList !== "undefined" &&
    NodeList.prototype &&
    !NodeList.prototype.forEach) {
    Object.defineProperty(NodeList.prototype, "forEach", {
        value: Array.prototype.forEach
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM