Why does ':last-child' change the priority of styles? - html

I encountered a scenario which confuses me - usage of :last-child affects how parent classes are applied.
What I have is a list of elements, and the goal is to apply some styles to the last element.
However, when I use :last-child, the priority of styles changes, and one of the parent classes stops working, only !important fixes the problem.
I made a simple demo here:
http://jsfiddle.net/wC2AX/1/
HTML:
<div class="hover">
<div class="focus_on_last_child" style="background-color:red; width:100px; height:100px">
<div class="attribution">
</div>
</div>
</div>
CSS:
/*this should be applied on hover always*/
.hover:hover .attribution{
background-color: black; /*try adding !important*/
bottom: 0px;
}
/*basic properties*/
.attribution {
height: 60px;
overflow: hidden;
position: absolute;
bottom: -60px;
width: 100px;
}
/*depending on a screen size styles are changed*/
.focus_on_last_child:last-child .attribution { /*try removing :last:child*/
background-color: pink;
bottom: -30px;
}
The example is a little bit stupid, the idea is on hover styles should be changed. But it works only when either !important is used or :last-child is removed.
Thanks for any suggestions!!

This is an issue of selector specificity.
Your first rule has two classes and a pseudo-class:
.hover:hover .attribution
And your last rule also has two classes and a pseudo-class (:last-child being that pseudo-class):
.focus_on_last_child:last-child .attribution
Since your two rules are equally specific, the one that comes later will take precedence. When you remove the :last-child pseudo-class, only the two class selectors remain and so the specificity of that rule is reduced, allowing your :hover rule to take precedence.
The simplest solution is to move your :hover rule underneath your :last-child rule, so that rule takes precedence and you won't have to make use of !important.

It's because:
.hover:hover .attribution{
Is more specific than:
.focus_on_last_child .attribution {
But if you would add .hover to it, it would be more specific, and will work:
.hover .focus_on_last_child .attribution {

Related

Undo hover effect of parent when hovering over child [duplicate]

I know that there does not exist a CSS parent selector, but is it possible to style a parenting element when hovering a child element without such a selector?
To give an example: consider a delete button that when hovered will highlight the element that is about to become deleted:
<div>
<p>Lorem ipsum ...</p>
<button>Delete</button>
</div>
By means of pure CSS, how to change the background color of this section when the mouse is over the button?
I know it is an old question, but I just managed to do so without a pseudo child (but a pseudo wrapper).
If you set the parent to be with no pointer-events, and then a child div with pointer-events set to auto, it works:)
Note that <img> tag (for example) doesn't do the trick.
Also remember to set pointer-events to auto for other children which have their own event listener, or otherwise they will lose their click functionality.
div.parent {
pointer-events: none;
}
div.child {
pointer-events: auto;
}
div.parent:hover {
background: yellow;
}
<div class="parent">
parent - you can hover over here and it won't trigger
<div class="child">hover over the child instead!</div>
</div>
Edit:
As Shadow Wizard kindly noted: it's worth to mention this won't work for IE10 and below. (Old versions of FF and Chrome too, see here)
Well, this question is asked many times before, and the short typical answer is: It cannot be done by pure CSS. It's in the name: Cascading Style Sheets only supports styling in cascading direction, not up.
But in most circumstances where this effect is wished, like in the given example, there still is the possibility to use these cascading characteristics to reach the desired effect. Consider this pseudo markup:
<parent>
<sibling></sibling>
<child></child>
</parent>
The trick is to give the sibling the same size and position as the parent and to style the sibling instead of the parent. This will look like the parent is styled!
Now, how to style the sibling?
When the child is hovered, the parent is too, but the sibling is not. The same goes for the sibling. This concludes in three possible CSS selector paths for styling the sibling:
parent sibling { }
parent sibling:hover { }
parent:hover sibling { }
These different paths allow for some nice possibilities. For instance, unleashing this trick on the example in the question results in this fiddle:
div {position: relative}
div:hover {background: salmon}
div p:hover {background: white}
div p {padding-bottom: 26px}
div button {position: absolute; bottom: 0}
Obviously, in most cases this trick depends on the use of absolute positioning to give the sibling the same size as the parent, ánd still let the child appear within the parent.
Sometimes it is necessary to use a more qualified selector path in order to select a specific element, as shown in this fiddle which implements the trick multiple times in a tree menu. Quite nice really.
Another, simpler "alternate" approach (to an old question)..
would be to place elements as siblings and use:
Adjacent Sibling Selector (+)
or
General Sibling Selector (~)
<div id="parent">
<!-- control should come before the target... think "cascading" ! -->
<button id="control">Hover Me!</button>
<div id="target">I'm hovered too!</div>
</div>
#parent {
position: relative;
height: 100px;
}
/* Move button control to bottom. */
#control {
position: absolute;
bottom: 0;
}
#control:hover ~ #target {
background: red;
}
Demo Fiddle here.
there is no CSS selector for selecting a parent of a selected child.
you could do it with JavaScript
As mentioned previously "there is no CSS selector for selecting a parent of a selected child".
So you either:
use a CSS hack as described in NGLN's answer
use javascript - along with jQuery most likely
Here is the example for the javascript/jQuery solution
On the javascript side:
$('#my-id-selector-00').on('mouseover', function(){
$(this).parent().addClass('is-hover');
}).on('mouseout', function(){
$(this).parent().removeClass('is-hover');
})
And on the CSS side, you'd have something like this:
.is-hover {
background-color: red;
}
In 2022:
This can be now achieved with CSS only, using the :has pseudo-class and the following expression:
div:has(button:hover) {}
Here's a snippet showcasing the original proposition:
div:has(button:hover) {
background-color: cyan;
}
<div>
<p>Lorem ipsum ...</p>
<button>Delete</button>
</div>
See browser support here. At the time of writing, all major browser support it—except Firefox, which still has a flawed experimental implementation.
This solution depends fully on the design, but if you have a parent div that you want to change the background on when hovering a child you can try to mimic the parent with a ::after / ::before.
<div class="item">
design <span class="icon-cross">x</span>
</div>
CSS:
.item {
background: blue;
border-radius: 10px;
position: relative;
z-index: 1;
}
.item span.icon-cross:hover::after {
background: DodgerBlue;
border-radius: 10px;
display: block;
position: absolute;
z-index: -1;
top: 0;
left: 0;
right: 0;
bottom: 0;
content: "";
}
See a full fiddle example here
This is extremely easy to do in Sass! Don't delve into JavaScript for this. The & selector in sass does exactly this.
http://thesassway.com/intermediate/referencing-parent-selectors-using-ampersand

on hovers with parents and child in css

I have a situation in which i want to change the color of my box with the on hover from the container i which this box is found.
I found out how to do this through a different question here on stackoverflow How to affect other elements when a div is hovered
But now i want to change the color of my box to a third option when i hover the box itself.
This is and exaple html with css.
<body>
<div class="container">container
<div class="box">
box</div>
</div
</body>
</html>
and the css.
.container{
background-color:grey;
height: 100px;
width:100px;
}
.container:hover .box{
background-color: aqua;
}
.box{
background-color: blue;
width:50px;
height: 50px;
}
.box:hover{
background-color: white;
}
This is the way i tried to do it but this does not work. The first steps works but i can't get the third color.
Simply change
.box:hover{
background-color: white
}
TO
.container:hover>.box:hover{
background-color: white
}
And try it here: http://jsfiddle.net/czmzxd6j/
You'll have to create a more specific selector.
You're setting .container:hover .box {...} which is more specific than .box:hover.
Your issue will be resolved if you use .container:hover .box:hover {...} because this is more specific than the one with just the .box at the end.
Using the direct-child selector isn't the way nor is !important (sorry guys, no offence but it's just not the correct approach here.)
CSS is all about overwriting and that is why these things can be nasty sometimes.
Whenever something doesn't get applied correctly just think to yourself for 3 seconds: "Are there any other selectors that manipulate this element that could be more specific?".
With the general selector .box:hover any box anywhere in the DOM will have that hover as long as it has the .box class however this is not true for the other selector including .container:hover .box:hover.
That selector is actually more specific due to the fact that now only .box elements within the .container elements get the hover.
By specifying the general selector instead of one that is atleast as specific it will simply be overwritten by the more specific one, that's why you need to re-add .container:hover to the selector.
I hope it makes sense to you.
Good luck!
try this:
.box:hover{
background-color: white !important;
}
you can see it here: https://jsfiddle.net/fusg2o3f/

Inline CSS works, external doesn't (JsFiddle included)

http://jsfiddle.net/xw0vvo9e/4/
I'm attempting to set a background color for my navBar. As you can see in the jsfiddle, I have:
div .navBar {
width: 100%;
height: 45px;
background-color: #FF0000;
top: 0px;
position: fixed;
}
and it doesn't work. However, if I remove it, and change the HTML to:
<div class="navBar" style="background-color:#FF0000;">
it works just fine. I've been scratching my head on this for quite some time now.
You should remove the space in your selector, i.e. it should be div.navBar. Your current selector which is a descendant combinator selector tries to find .navBar descendants of the div elements. As the .navBar element doesn't have any div parents/grandparents the selector fails to select the target element.

:hover but :not on a specific class

How do I apply a hover effect on an a element, but not to an a element with the class active?
a:hover(not: .active)
Seems something is missing.
The functional notation is on :not(), not :hover:
a:not(.active):hover
If you prefer to put :hover first, that's fine:
a:hover:not(.active)
It doesn't matter which pseudo-class comes first or last; either way, the selector works the same. It just happens to be my personal convention to put :hover last as I tend to place user-interaction pseudo-classes behind structural pseudo-classes.
You have the option of using the not() selector.
a:not(.active):hover { ... }
However, this may not work in all browsers, as not all browsers implement CSS3 features.
If you are targeting a large audience and want to support older browsers, the best way would be to define a style for the .active:hover and undo whatever you're doing in a:hover.
We can use :not() operator on hover like below example.
We can use this when we don't want to apply :hover effect to the selected item
.block-wraper {
display: flex;
}
.block {
width: 50px;
height: 50px;
border-radius: 3px;
border: 1px solid;
margin: 0px 5px;
cursor: pointer;
}
.active {
background: #0095ff;
}
.block:not(.active):hover {
background: #b6e1ff;
}
<div class="block-wraper">
<div class="block"></div>
<div class="block active"></div>
<div class="block"></div>
<div class="block"></div>
</div>

How to stop my css declaration from being overridden

I have a div with classes of A B C
I added a style to c to show the color as "Red";
The problem is it's overridden from the styles of A and B.
I read that !important only prevents the css being overridden by the inline style but does not prevent the override by other css.
How do I mark the style of C as the strongest?
Increase the specificity of rule C above that of rules A and B. Normally I would include some explanation here, but the one over at the linked site is superb.
An !important declaration provides a way for a stylesheet author to give a CSS value more weight than it naturally has. It should be noted here that the phrase “!important declaration” is a reference to an entire CSS declaration, including property and value, with !important added.
Here is a simple code example that clearly illustrates how !important affects the natural way that styles are applied:
#example {
font-size: 14px !important;
}
#container #example {
font-size: 10px;
}
In the above code sample, the element with the id of “example” will have text sized at 14px, due to the addition of !important.
div.a, div.b {
background-color: #00f;
}
div.c {
background-color: #f00 !important;
}
The !important will up priority of rule and inheritance will be ignored.
div.a, div.b, div.c {
background-color: #00f;
}
div.c {
background-color: #f00;
}
should work, CSS is sequential. This means the last style for that element is applied of no more specific style is available. More specific would be for example
body div.c {
background-color: #f00;
}
!important should work just fine, but if not you can chain your classes in your declaration like so:
div.a.c,div.b.c,div.a.b.c
{
color:red
}