CSS selector for certain position of matched classes - css

I have the following divs:
<div class="c">
<div class="a"></div>
<div class="a"></div>
<div class="a"></div>//this
</div>
<div class="c">
<div class="a"></div>//this
<div class="a"></div>//this
<div class="a"></div>
</div>
<div class="c">
<div class="a"></div>
<div class="a"></div>
<div class="a"></div>
</div>
Is there a CSS selector that lets me select .a elements situated in 3rd,4th and 5th position of the .a matched results?
Something similar to eq() in jQuery.
:nth-child() is not of help here as this is just a simplified case.
This is a fiddle with the results using jQuery. I want to know if there is a solution using just CSS.

No, there is no equivalent to jQuery's :eq() in CSS. In plain English, there is no selector for the nth element matching a complex selector (in your example, the 3rd, 4th and 5th elements matching the selector .a).
Just for the sake of completeness (because someone is going to say "well, actually..."), the specific elements are, of course, reachable with
.c:nth-child(1) > .a:nth-child(3), .c:nth-child(2) > .a:nth-child(1), .c:nth-child(2) > .a:nth-child(2)
But that assumes that is exactly how your markup appears, which is seldom ever a realistic assumption to make, especially if the page is dynamically generated.
In the very unlikely event that your markup is static and you can rely on the 3rd, 4th and 5th .a elements being in those exact positions, by all means use the selector above. But if their positions or structure can vary, then you will need other ways to identify them in CSS, for example with an additional class name.

.c:nth-child(1) .a:nth-child(3) { background:yellow; }
.c:nth-child(2) .a:nth-child(2), .c:nth-child(2) .a:nth-child(1) { background:yellow; }
<div class="c">
<div class="a">c1-a1</div>
<div class="a">c1-a2</div>
<div class="a">c1-a3 //this</div>
</div>
<div class="c">
<div class="a">c2-a1 //this</div>
<div class="a">c2-a2 //this</div>
<div class="a">c2-a3</div>
</div>
<div class="c">
<div class="a">c3-a1</div>
<div class="a">c3-a2</div>
<div class="a">c3-a3</div>
</div>

Related

How to Query Select all children of a class, but no grandsons of that class

I have the css class 'control', and I want to get all the 'control' children elements from my container, but I dont want to get grandsons 'control'.
<div id='mydiv'>
<div id='div1' class='control'>
<div id='div2' class='control'></div>
<div id='div3' class='control'></div>
</div>
<div class='other'>
<div id='div4' class='control'></div>
<div id='div5' class='control'>
<div id='div6' class='control'></div>
<div id='div7' class='control'></div>
</div>
</div>
</div>
The call below will get me all the controls inside 'mydiv'.
document.querySelectorAll('#mydiv .control');
I want a query that brings me only #div1, #div4 and #div5;
Is that possible?
With only querySelector* it will not work at the moment.
In the future, browsers will support the :has() pseudo-selector.
Then you can select only elements which has or not has elements inside them like this:
#mydiv .control:not(:has(.control))
See the current browser support for this: https://caniuse.com/css-has
For now you need following sulution:
const elements = [...document.querySelectorAll('#mydiv .control')].filter(element => {
return element.parentNode.closest('.control') == null
});
console.log(elements);
<div id='mydiv'>
<div id='div1' class='control'>
<div id='div2' class='control'></div>
<div id='div3' class='control'></div>
</div>
<div class='other'>
<div id='div4' class='control'></div>
<div id='div5' class='control'>
<div id='div6' class='control'></div>
<div id='div7' class='control'></div>
</div>
</div>
</div>
Explanation:
Get at first all .control elements into an array (querySelectorAll returns a NodeList and NodeList does'nt have methods like filter. So we extract it with the spread syntax [...variable]
Then filter all elements which has no parent elements named .control.
.closest() can return itself, so we need to make sure we call parentNode at first.
UPDATE End September 2022
Browser are starting to implement :has()

CSS selector, Match element that doesn't match given selector

I'm trying to match element that dose not match given selector using css.
Given the markup below, I'm trying to select only the first ".color"
<div uid="unique-id-1">
<div> <div class="color"></div> </div>
<div uid="unique-id-2">
<div class="color"></div>
</div>
</div>
I tried [uid="unique-id-1"] .color:not([uid="unique-id-1"] [uid] .color) which did not work obviously, but I think it will help to understand what I am looking for.
Thanks in advance!
If you're only going to apply the selector to this limited combination of elements (i.e. there aren't any other .colors in the page that could potentially be affected by this), then
[uid="unique-id-1"] > div:not([uid]) > .color
Do consider renaming the attribute to data-uid if your application allows, so as to make it clearer that this is an app-specific and non-standard uid attribute.
That seems simple:
[uid="unique-id-1"]>:first-child .color {
color: red;
}
<div uid="unique-id-1">
<div>
<div class="color">A</div>
</div>
<div uid="unique-id-2">
<div class="color">B</div>
</div>
</div>
That being said, uid as an attribute name makes your HTML invalid, so you should rename that to data-uid:
[data-uid="unique-id-1"]>:first-child .color {
color: red;
}
<div data-uid="unique-id-1">
<div>
<div class="color">A</div>
</div>
<div data-uid="unique-id-2">
<div class="color">B</div>
</div>
</div>

CSS nth-of-type not logical

CSS:
.banner:nth-of-type(1) {background-color:red;}
.banner:nth-of-type(2) {background-color:blue;}
HTML:
<div id="container">
<div class="copy">copy 1</div>
<div class="banner">banner 1</div>
<div class="copy">copy 1</div>
<div class="banner">banner 2</div>
<div class="copy">copy 1</div>
<div class="banner">banner 3</div>
<div class="banner">banner 4</div>
</div>
Shouldn't the CSS be counting the .banner elements regardless of the other sibling elements?
I'm expecting banner 1 to have a red background and banner 2 to have a blue background, but getting banner 1 with a blue background and banner 2 with no background -- I would expect this if I were using nth-child(n). Check my fiddle here: http://jsfiddle.net/JjNBV/3/
nth-of-type applies to the type of element -- ie <div> in this case, not to the class.
.banner:nth-of-type(1) doesn't match anything because none of the .banner elements is the first div inside the container.
.banner:nth-of-type(2) matches the first .banner element because it is the second div inside the container.
There isn't a CSS3 selector that matches classes in the way you're expecting.
If you want this kind of behaviour, you will need to use different element types for your banners and copy, then nth-of-type will work for you as you want. HTML5 provides several elements that may meet your needs in this regard.
Which elements you use would depend on what you're using them for; your supplied code doesn't give sufficient clues for me to give you a definitive recommendation, but here's your code with the copy elements changed from <div> into <article> elements...
<div id="container">
<article class="copy">copy 1</article>
<div class="banner">banner 1</div>
<article class="copy">copy 1</article>
<div class="banner">banner 2</div>
<article class="copy">copy 1</article>
<div class="banner">banner 3</div>
<div class="banner">banner 4</div>
</div>
With this change, your existing CSS should now work as you expect. (and here is the jsFiddle to show it working)
CSS4 does have a selector nth-match() which may possibly also do what you're looking for, but no browsers support this selector (nor are any looking likely to in the near future), so that's not really an option for the time being.
Try
.copy:nth-child(n+1) {background-color:red;}
.banner:nth-child(n+2) {background-color:blue;}
Fiddle here

select nth-of-type with the html markup order

The html markup may vary as in the following example .menu is illustrated:
<div id="main">
<div></div>
<div class="menu"></div>
<div class="menu"></div>
</div>
for this I could use .menu:last-child but if this is like this:
<div id="main">
<div></div>
<div class="menu"></div>
<div>
<div class="menu"></div> <!--- selecting this----->
</div>
</div>
Or, say like this:
<div id="main">
<div></div>
<div class="menu"></div> <!-- count as 1--->
<div>
<div>
<div class="menu"></div> <!--- selecting this-----> <!-- count as 2 ---->
<div class="menu"></div> <!-- count as 3---->
</div>
</div>
</div>
So, I want to target the .menu whether it is parent, children or siblings anything but lastly marked up html or say like nth-of-type. Is there any idea for this?
I mean I want as the type of the class name.
The nth-of-type will give you the nth sibling of the same type as the selected element.
This should be used when you are dealing with different element types in the same parent, and you want to select the 1st/last or nth element of a specific type only.
Unfortunately there isn't any such pseudo-class to select a specific element(At a particular position) in the sequence of the elements with the same type in the context of the whole BODY of the document. Hence in this particular set of examples you cannot select the 2nd of all the elements with the same specification i.e. in this case with class=menu in the context of the whole document but it is possible with all such elements under a single level of the object hierarchy of the DOM tree i.e. under a single parent.
So the only way is through JS:
Code
<script>
onload=function()
{
obj=document.getElementsByClassName('menu')[1];//index=1 to access the 2nd object
/*
Do something with 'obj'
*/
}
</script>

CSS first-child not working as expected

I am using the following CSS to try and remove the left-border on the first child div of any element with the class called, "tblRow"
.tblRow div:first-child{
border-left: none;
}
<div class="tbl">
<div class="tblRow">
<div class="tblCell">Lower limit QTY</div>
<div class="tblCell">Upper Limit</div>
<div class="tblCell">Discount</div>
</div>
<div class="tblRow">
<div class="tblCell">1</div>
<div class="tblCell">5</div>
<div class="tblCell">25%</div>
</div>
</div>
This only removes the left-border from the first child div in the first row. It does not remove it in the second row. Any ideas?
I generally only use the :first-child and :nth-child psuedo selectors when I have little or no control over the elements or they are populated dynamically where I cannot rely on an order. Additionally, since :nth-child is CSS3, you can't rely on complete browser compatibility. If you can do without this psuedo selector, my advise is to create a secondary class for this purpose.
.tblCell.firstCell{
border-left: none;
}
<div class="tbl">
<div class="tblRow">
<div class="tblCell firstCell">Lower limit QTY</div>
<div class="tblCell">Upper Limit</div>
<div class="tblCell">Discount</div>
</div>
<div class="tblRow">
<div class="tblCell firstCell">1</div>
<div class="tblCell">5</div>
<div class="tblCell">25%</div>
</div>
</div>
It seems to work on the fiddle, so you probably have a (hidden) text node somewhere there. Therefore I suggest using .tblRow div:first-of-type { ... }, if possible from browser support point-of-view.

Resources