Inaccuracy in nth-last-child selector - css

Having trouble understanding.
With the following css :
.bloc .field:nth-last-child(2){ ...some values... }
and the following html (well, haml) :
.bloc
.field
.field
.field
.field
.clearfix
The .clearfix div gets counted in the selector, from this I can't get the good .field's div to be specifically styled.
It seems a bug to me, but I might be wrong. The same kind of problem applies for nth-child.

The big misunderstanding here is how filtering using :nth-child() works.
.bloc .field:nth-last-child(2) means:
"select all second-to-last elements that have the .field class that are inside a .bloc".
It does not mean:
"select all second-to-last .field elements that are inside a .bloc".
With this understanding, you could just change your selector to .bloc :nth-last-child(3).
However, the second paragraph of bažmegakapa's answer makes a lot of sense. You should just remove the .clearfix element and use a different float containment technique. The "micro clearfix" is a good choice. Another option is to add overflow: hidden to .bloc.

Simply remove the clearfix div. The :nth-last-child() and :nth-last-of-type() selectors do not work the way you expect. They will not make a distinction on class names (the first does not make a distinction, only counts from backwards, the second only makes a distinction on element type).
There are thousands of clearing techniques and only some of them require adding markup. Simply overflow: hidden or overflow: auto on the container. If you can use :nth-last-child you could also use a clearing technique that employs ::after.

You are selecting an element with that class if it's a :nth-last-child(2).
You could achieve what you really want, if you were using a different type for the .field and .clearfix elements, with :nth-last-of-type().

Try this, seems to be getting the one before .clear for me:
.bloc .field:nth-last-child(2) { color: #CC0000; }​
http://jsfiddle.net/clowerweb/Dp3yW/

Related

CSS working inline but not from stylesheet

I've read through all the other posts on this topic but non seemed to help.
When I have:
.tb-megamenu-submenu .dropdown-menu .mega-dropdown-menu .nav-child{
left:50% !important;
}
It doesn't add the style to the element.
But If I use it inline it works:
<div data-class="increase-background-about" data-width="0" class="tb-megamenu-submenu increase-background-about dropdown-menu mega-dropdown-menu nav-child" style="left:50px">
I'm completely stumped and the other questions haven't helped.
Remove all the spaces and try. It should work!
.tb-megamenu-submenu.dropdown-menu.mega-dropdown-menu.nav-child{
left:50% !important;
}
The issue with your styling is that all the classes you mentioned are for the same element.
So to target them you need to do it like I've done above - without spaces.
Your styling would work when these classes are descendants
i.e. .tb-megamenu-submenu -> .dropdown-menu -> .mega-dropdown-menu -> .nav-child
Arrow represents the parent-child relation.
Learn basics of CSS from here.
Your selector is wrong. That is actually looking for a .nav-child element, inside a .mega-dropdown-menu, inside a .dropdown-menu, inside a .tb-megamenu-submenu. You should remove the spaces in your selector:
.tb-megamenu-submenu.dropdown-menu.mega-dropdown-menu.nav-child{
left: 50%;
}
Please do not use !important. It makes your code very hard to maintain. Instead, try to write more specific selectors (incidentally, this should be specific enough).
You are trying to specify your element through multiple classes right? But by putting spaces between the selector you are actually getting descendants:
.tb-megamenu-submenu
. dropdown-menu
.nav-child <- getting this element
To get the right result you should concotenate the .classes without spaces between, like:
.tb-megamenu-submenu.dropdown-menu.mega-dropdown-menu.nav-child {
left:50% !important;
}

CSS grouping :hover & :active

When I want to define css selector with :hover and :active I have to do:
#mainPage #content div.group:hover, #mainPage #content div.group:active {}
As one can see it contians repeated #mainPage #content div.group and can get messy. Is there a way to group it somehow like:
#mainPage #content div.group:hover:active {}
In pure CSS there is not much of a better way to handle both more succinctly without adding a class or ids.
You could consider a CSS pre-compiler (like LESS or SASS/SCSS).
In LESS or SCSS:
#mainPage #content div.group {
&:hover, &:active {
color: red;
}
}
I suggest add ID for the element has class group and write below code will reduce the effort:
#idname.group:hover, #idname.group:active{}
Is there a reason why you're using #mainPage #content before div.group?
Generally, it's not necessary to add that much 'specificity' to your selectors - it's better to instead, have unique classes. So make sure that the class .group is only used for elements that you want to have the same styles.
If you do that, you should be able to style those elements just using
.group { styles here}
You might run into an issue now where if you try to override any of the styles you set like #mainPage #content, those will be more specific and so in effect 'stronger' than styles where you don't use the full list of parents. If possible, change all your styles not to include the parent elements - this is also worthwhile in case you ever want to move an object to a different part of the html!
It's also, in general, advisable not to use id's (#name) to attach css styles - if possible, just use classes. Unless you're doing javascript, you shouldn't have much need for id's.
Obviously there exceptions to the above, and for all I know you may have a perfectly good reason for doing things the way you have - in which case SASS (as suggested in a few other answers) is a good solution for you.
If not useful for you, I hope at least this answer might be useful for someone who might come along later - I've noticed that a lot of people newer to css don't realize how specificity of selectors works and end up making their styles a lot more complicated than necessary as a result! :)
Old question, but this should be relevant for somebody who needs this.
Pseudo-class released by the end of 2020
You can use :is() pseudo-class like so :
#mainPage #content div.group:is(:hover, :active) {
}
Here is a little snippet to picture it :
a:is(:hover, :focus) {
color: red;
outline: #5bc8ea dotted 4px;
outline-offset: 4px;
font-weight: 600;
}
Hover/Focus me
More informations about :is() pseudo class here: https://developer.mozilla.org/en-US/docs/Web/CSS/:is and here: https://css-tricks.com/almanac/selectors/i/is/.
Works with most of the popular browsers (incompatible with IE, Opera and Safari < 14) https://caniuse.com/css-matches-pseudo.
It surely is more often used to select elements than pseudo-classes like :hover or :focus but it will do the trick as I can't see any other solution for now.
Why you use #mainPage #content? #content should be enough to find the div your looking for without the #mainPage.
Also id's are only allowed to be used once and not in multiple places like classes are. Id's are usually reserved for script assignments and not CSS. I would do
#content .group:hover{}
#content .group:active{}
if i understood correctly, you want a group of elements to act a certain way? manipulate the parent class then.
.parent-class:hover {
.child-class {
…desired styles go here
}
}

Using css universal selector (*) for clearing the flow

This works, but actually I've never come across it earlier. Does it have some "weak spots"?
div.floated { float: left; }
div.floated+* { clear: both; }
Though I did not notice any "side effect".
You can use it at your will, although according to MDN, you should take into account that universal selector is the most expensive CSS selector in terms of webpage performance.
Universal CSS Selector Performance
Here some problems I see:
"floated" is not a semantic class name.
This will clear adjacent elements after divs with the "floated" class, but not anything that is floated by other means.
In most designs I work with, I don't want to clear adjacent elements. Now I'll have to write more CSS to undo this.
I think I don't understand the value of this.

How to exclude a class with all children in style definition

I have a file like
<div>
<div class="abc">
<div>
<!--some more divs inside-->
</div>
</div>
</div>
What I want to do is to apply styles only to the first div. I tried to use div:not(.abc, .abc *), div:not(.abc):not(.abc *), div:not(.abc), div:not(.abc) * but none of these worked. It would be hard to edit the html, because there would be many files to be edited. Also the code shown above appears in different places, so using > selector is not the solution... Does someone know how to do this?
You cannot reliably use the :not() selector in CSS for excluding an element and/or its descendants. The reason for it is explained in this answer (and some others that it links to):
You can't use combinators. This works in jQuery, but not CSS:
/*
* Grab everything that is neither #foo itself nor within #foo.
* Notice the descendant combinator (the space) between #foo and *.
*/
:not(#foo, #foo *)
This one is particularly nasty, primarily because it has no proper workaround. There are some loose workarounds (1 and 2), but they usually depend on the HTML structure and are therefore very limited in utility.
And since your markup is unpredictable enough that you cannot edit it or use the > selector, I'm afraid there's not much of a way out for you other than to either find a way to apply a class to your top div and use that class, as demonstrated by Fluidbyte, and/or use jQuery, as implied above.
I usually find it's easier to include what you need via a class then try to exclude descendant elements. See the fiddle here: http://jsfiddle.net/cLtHg/
That takes care of inheritance issues and is much more cross-browser friendly.
If you're really not touching the HTML, then a simple although dirty approach would be to apply styles to the first div and then remove them from subsequent divs, like so:
div {margin-bottom: 20px; border: 1px solid #ccc;}
div div {margin-bottom: 0; border: none;}
The major drawback here is that some styles in the child divs may get removed unintendedly. Depends on how they're styled in the first place.
Use :first-child with the ID or Class of its parent Element. If you are unable to catch the element using CSS, it is suggested to use Javascript or jQuery.
Have you tried :first-child or :nth-child() selecor?

nth-child(odd) not working as expected

Why does every row have a red background when I'm using nth-child(odd)?
<div id="ClientTable">
<div class="ClientTableHeaderRow"><span class="ClientTableHeaderColumn">Full Name</span></div>
<div class="ClientTableRow"><span class="ClientName">Umpa Beeson</span></div>
<div class="ClientTableRow"><span class="ClientName">Umpa Beeson</span></div>
<div class="ClientTableRow"><span class="ClientName">Umpa Beeson</span></div>
<div class="ClientTableRow"><span class="ClientName">Umpa Beeson</span></div>
</div>​
#ClientTable {position: relative;
display: table;
margin-top: 20px;
width: 100%;}
#ClientTable:nth-child(odd) {background-color:#FF0000;}
.ClientTableHeaderRow, .ClientTableRow {display: table-row; }
.ClientTableHeaderRow {font-weight: bold;}
.ClientTableHeaderRow span, .ClientTableRow span {display: table-cell;}​
View the jsFiddle
The expected result is every other row to be red. Instead, as you can see, every row is red.
P.S. Umpa is my cat.
You should be setting ClientTableRow class, like so:
.ClientTableRow:nth-child(odd) {background-color:#FF0000;}
Demo: http://jsfiddle.net/gMR2K/4/
EDIT
As also explained by animuson, you need to apply the :nth-childselector to the element itself, not the parent. The name of the selector can lead one to think it will apply the styling to the children of the selected element, when actually the style is applied to n-th child of the selected element, across the whole document.
Also, if you're worried about browser compatibility you can also do this with JavaScript. Here's an example using jQuery.
$(document).ready()
{
$(".ClientTableRow:nth-child(odd)").addClass("redBackground");
}
Demo: http://jsfiddle.net/gMR2K/10/
As stated here by BoltClock: jQuery "polyfills the :nth-child() selector for older browsers anyway."
nth-child applies to the actual element, not its children. #ClientTable is the 1st (and only) child of its parent. Therefore, it has a red background. You need to be applying the nth-child to the elements inside that division.
Is this the result you want?:
http://jsfiddle.net/gMR2K/6/
#ClientTable div:nth-child(odd) {background-color:#FF0000;}
and that only works in the better browsers. IE 8 and below don't get it. But, you can use jQuery to make it work everywhere or (painfully) add a class to the odd rows.
In my case I made a small mistake
.someclassA .someclassB: nth-child(odd){
You can see as above there is one space between someclassB: and nth-child. thats it.. By deleting that space it started working :)

Resources