How to not execute parent's :hover on child :hover - html

When the .post-item <div> is hovered I want to execute some specific styles (change background-color and cursor) but I don't want this to happen if the .rating-wrapper <div> is hovered too. This happens because I want the .rating-wrapper to do something different than the hover of its parent. Basic question: How to do only child's hover, ignoring the parent's hover
HTML:
<div class="post-item">
<div class="rating-wrapper">
<div class="upvote">
<img src="/images/upvote_arrow.png" alt="upvote" />
</div>
<div class="rating"></div>
<div class="downvote">
<img src="/images/downvote_arrow.png" alt="downvote" />
</div>
</div>
<span class="owner-data">
<img src="" alt="" class="owner-avatar" />
<span class="owner-username"></span>
</span>
<span class="creation-date"></span>
<div class="title"></div>
</div>

Since you want to change the style of the parent element based on a pseudo-class of the child element, this isn't really possible with CSS alone today.
You can do it with the :has() pseudo-class but that is currently only supported in Safari (with support for Chrome a few months away and no sign of it in Firefox, Edge, Opera or elsewhere).
#parent {
background: white;
border: solid black 1px;
padding: 2em;
max-width: 50%;
margin: auto;
}
#parent:hover:not(:has(#child:hover)) {
background: orange;
}
#child {
background: #aaa;
border: solid black 1px;
padding: 2em;
}
#child:hover {
background: green;
}
<div id="parent">
<div id="child"></div>
</div>
For a more reliable approach, you should probably look at adding a splash of JavaScript to the mix.
Use mouseenter and mouseleave events to modify the classes of the parent element, then reference the class in your stylesheet.
const parent = document.querySelector('#parent');
const child = document.querySelector('#child');
const enter = event => parent.classList.add('child-hover');
const leave = event => parent.classList.remove('child-hover');
child.addEventListener('mouseenter', enter);
child.addEventListener('mouseleave', leave);
#parent {
background: white;
border: solid black 1px;
padding: 2em;
max-width: 50%;
margin: auto;
}
#parent:hover:not(.child-hover) {
background: orange;
}
#child {
background: #aaa;
border: solid black 1px;
padding: 2em;
}
#child:hover {
background: green;
}
<div id="parent">
<div id="child"></div>
</div>

You can use this CSS Selector,
.post-item>:not(.rating-wrapper):hover {
background-color: white;
}
This will select all immediate children of .post-item which are not .rating-wrapper.
To change the block of the remaining items background color, you can enclose them in another div.

There is a css property called not property.The syntax is like:
:not(element) {
// CSS Property}
If you want to learn more, please visit this link:
https://www.geeksforgeeks.org/how-to-exclude-particular-class-name-from-css-selector/

The pointer-events CSS property sets under what circumstances (if any) a particular graphic element can become the target of pointer events.
try:
pointer-events: none
you can read more here: https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events

Related

Perform action when focused

I have 3 divs. 2 of them change their color when focused. Can also an action be performed on another div when 2 of them get focused?
div {
border: 1px solid;
margin: 5px;
width: 300px;
height: 50px;
padding: 2px;
}
.myClass:focus {
background-color: yellow;
outline: none;
}
<div class="myClass" tabindex="-1">
Focus me!
</div>
<div class="myClass" tabindex="-1">
You can focus me too!
</div>
<hr />
<div class="anotherClass">
I cannot be focused, but want to change my color, when one of the other divs above me get focused.
</div>
So when 1 of the 2 upper divs get focused I want the 3rd div at the bottom to change its color.
Here you can have a look: https://jsfiddle.net/ogpvvwtg/
Sure, you can use the general sibling selector ~
.myClass:focus ~ .anotherClass {
background-color: red;
outline: none;
}
div {
border: 1px solid;
margin: 5px;
width: 300px;
height: 50px;
padding: 2px;
}
.myClass:focus {
background-color: yellow;
outline: none;
}
.myClass:focus ~ .anotherClass {
background-color: red;
outline: none;
}
<div class="myClass" tabindex="-1">
Focus me!
</div>
<div class="myClass" tabindex="-1">
You can focus me too!
</div>
<hr />
<div class="anotherClass">
I cannot be focused, but want to change my color, when one of the other divs above me get focused.
</div>
you can do this with a little bit of javascript which might give you more control of the things you want to color.
colorDiv3 = function() {
window.document.getElementById("div3").style.backgroundColor = "lightGreen";
}
div {
border: 1px solid;
margin: 5px;
width: 300px;
height: 50px;
padding: 2px;
}
.myClass:focus {
background-color: yellow;
outline: none;
}
<div class="myClass" tabindex="-1" onFocus="colorDiv3()">
Focus me!
</div>
<div class="myClass" tabindex="-1" onFocus="colorDiv3()">
You can focus me too!
</div>
<hr />
<div id="div3" class="anotherClass">
I cannot be focused, but want to change my color, when one of the other divs above me get focused.
</div>
You can also accomplish this using JavaScript:
First give the divs IDs:
<div id="topDiv" class="myClass" tabindex="-1">
etc...
Then you can find them with:
var top_div = document.getElementById('top_div');
var middle_div = document.getElementById('middle_div');
var bottom_div = document.getElementById('bottom_div');
Assign an event listener to the objects. This allows you to call a function when an element is focused:
top_div.addEventListener("focus", changeBottomDivColor);
middle_div.addEventListener("focus", changeBottomDivColor);
And finally, the function to actually change the color:
function changeBottomDivColor() {
bottom_div.style.backgroundColor = "red";
}

Apply CSS Filter to all but specific sub-elements

I need a CSS filter to apply to all elements in a container, except for specific ones. Quick example to explain the situation:
<div class="container">
<img class="one" src="blah" />
<img class="two" src="blah" />
<img class="three" src="blah" />
</div>
Then I am applying filters as so:
.container {
-webkit-filter: grayscale(100%);
filter: grayscale(100%);
}
So the container has the greyscale filter applied to it, and all img in it are turned to grey. However, I want one of the img to not turn to grey:
.two {
-webkit-filter: grayscale(0);
filter: grayscale(0);
}
However, this is not working. The filter of the container seems to be overriding the filter of the contained element.
Any ideas how I can get around this? Is there an easy way, or do I have to write up some jQuery to look at all the elements that aren't ".two" and apply the filter to them, rather than the container?
Update: I neglected to mention an important caveat: The container has to be greyscale, due to it having a background-image property that is to also be turned grey. This little snippet is part of more containers that are all going greyscale as well, I'm really just trying to figure out if there's a way to have an overriding exemption to the rule on the parent, since the parent has to have the rule as well.
According to CSS specifity rules -
Either put the .two after the .container in the css,
Or make the .two more specific, i.e. img.two
UPDATE
The .container rule is on the div itself - not on the images. So the container goes grayscale regardless of what you tell the images to do. Try changing that into .container img, and then try incorporating the answers you received.
use > to specify an image that is a child of .container the use not: to specify that you don't want the second image grey
.container > img:not(.two) {
-webkit-filter: grayscale(100%);
filter: grayscale(100%);
}
<div class="container">
<img class="one" src="http://lorempixel.com/400/200" />
<img class="two" src="http://lorempixel.com/400/200" />
<img class="three" src="http://lorempixel.com/400/200" />
</div>
jsfiddle
.container > img:not(.two) {
-webkit-filter: grayscale(100%);
filter: grayscale(100%);
}
Use :not to exclude .two
The negation CSS pseudo-class, :not(X), is a functional notation taking a simple selector X as an argument. It matches an element that is not represented by the argument. X must not contain another negation selector.
.container img:not(.two) {
-webkit-filter: grayscale(100%);
filter: grayscale(100%);
}
Seven years after this question was asked, I thought I'd come up with a brilliant CSS-native solution to this, using:
calc()
CSS Custom Properties
Hours of experimenting with CSS filter have satisfied me that the solution will never work.
Why not? Because functions like filter: hue-rotate() are both more complicated than you might expect and also, unhelpfully, unreliable.
My first ("clever") solution
(Calculate reverse transformations - cute, but doesn't work)
The starting point of my "clever" solution was:
It's well-established that once you apply filter to a parent element, that filter (much like opacity) continues to apply to all descendant elements and there is no way to mask a descendant element from that filter.
But filter simply describes transformations, right? And - surely - anything transformed can be un-transformed via a transformation which represents a mirror-image of the original?
Furthermore, if the original transformation is built in the right way from CSS Custom Properties, then it ought to be possible to build the mirror-image transformation using the same CSS Custom Properties and calc().
So I came up with something like this:
/*
OTHER CSS CUSTOM PROPERTIES (NOT NECESSARY FOR THIS EXAMPLE)
.square[data-theme="green"] {
--saturation: 1;
--contrast: 0.775;
--brightness: 1.2;
}
.square[data-theme="blue"] {
--saturation: 1;
--contrast: 0.775;
--brightness: 1.2;
}
.filter {
--lightness: contrast(var(--contrast)) brightness(var(--brightness));
--hsl-filter: hue-rotate(var(--hue)) saturate(var(--saturation)) var(--lightness);
}
.no-filter {
--reverse-lightness: contrast(calc(1 / var(--contrast))) brightness(calc(1 / var(--brightness)));
--reverse-hsl-filter: hue-rotate(calc(0deg - var(--hue))) saturate(calc(1 / var(--saturation))) var(--reverse-lightness);
}
*/
h2 {
position: absolute;
top: 0;
left: 0;
z-index: 6;
margin: 2px 0 0 2px;
padding: 0;
color: rgb(255, 255, 255);
font-size: 12px;
font-family: sans-serif;
font-weight: 700;
}
.square {
position: relative;
float: left;
display: inline-block;
width: 92px;
height: 92px;
margin: 2px;
padding: 6px;
background-color: rgb(191, 0, 0);
box-sizing: border-box;
}
.square:nth-of-type(4) {
clear: left;
}
.circle {
width: 80px;
height: 80px;
padding: 30px;
background-color: rgb(255, 0, 0);
border-radius: 50%;
box-sizing: border-box;
}
.inner-square {
width: 20px;
height: 20px;
background-color: rgb(255, 127, 0);
}
.square[data-theme="green"] {
--hue: 112.5deg;
}
.square[data-theme="blue"] {
--hue: 212.5deg;
}
.filter {
--hsl-filter: hue-rotate(var(--hue));
filter: var(--hsl-filter);
}
.no-filter {
--reverse-hsl-filter: hue-rotate(calc(0deg - var(--hue)));
filter: var(--reverse-hsl-filter);
}
<div class="square">
<h2>Original</h2>
<div class="circle">
<div class="inner-square"></div>
</div>
</div>
<div class="square filter" data-theme="green">
<h2>Filtered</h2>
<div class="circle">
<div class="inner-square"></div>
</div>
</div>
<div class="square filter" data-theme="green">
<h2>No-Filter Test</h2>
<div class="circle no-filter">
<div class="inner-square"></div>
</div>
</div>
<div class="square">
<h2>Original</h2>
<div class="circle">
<div class="inner-square"></div>
</div>
</div>
<div class="square filter" data-theme="blue">
<h2>Filtered</h2>
<div class="circle">
<div class="inner-square"></div>
</div>
</div>
<div class="square filter" data-theme="blue">
<h2>No-Filter Test</h2>
<div class="circle no-filter">
<div class="inner-square"></div>
</div>
</div>
It's less obvious in the top row (at first glance), but in the second row, the last square (ie. bottom right) clearly shows how this reverse-transformation approach is neither robust nor reliable:
The orange square in the bottom-right square isn't perfect, but it's close enough to the original
The orange square in the top-right square is less perfect, but it's still passable (just about)
The red circle in the top-right square isn't perfect, but it's close enough to the original
The red circle in the bottom-right square is no good at all
My second (less clever) solution
(Make the non-filtered element a sibling instead of a descendant element - less clever but it does work)
We may conclude from the above that the matrix transformation initiated by filter: hue-rotate() cannot be easily reversed - and that even if a computational way to reverse it consistently via JavaScript can be found - I'm currently doubtful over whether even that is possible - it's almost certainly not going to be possible via CSS calc().
Alternatively, we can turn the descendant elements we don't want to be affected by the filter into siblings of the element which has the CSS filter applied to it, instead:
h2 {
position: absolute;
top: 0;
left: 0;
z-index: 6;
margin: 2px 0 0 2px;
padding: 0;
color: rgb(255, 255, 255);
font-size: 12px;
font-family: sans-serif;
font-weight: 700;
}
.container {
position: relative;
float: left;
display: inline-block;
width: 92px;
height: 92px;
margin: 2px;
background-color: rgb(0, 0, 0);
box-sizing: border-box;
}
.container:nth-of-type(4) {
clear: left;
}
.square {
width: 92px;
height: 92px;
background-color: rgb(191, 0, 0);
}
.circle {
position: absolute;
top: 0;
left: 0;
width: 80px;
height: 80px;
margin: 6px;
padding: 30px;
background-color: rgb(255, 0, 0);
border-radius: 50%;
box-sizing: border-box;
}
.inner-square {
width: 20px;
height: 20px;
background-color: rgb(255, 127, 0);
}
.container[data-theme="green"] {
--hue: 112.5deg;
}
.container[data-theme="blue"] {
--hue: 212.5deg;
}
.filter {
--hsl-filter: hue-rotate(var(--hue));
filter: var(--hsl-filter);
}
<div class="container">
<h2>Original</h2>
<div class="square"></div>
<div class="circle">
<div class="inner-square"></div>
</div>
</div>
<div class="container" data-theme="green">
<h2>Filtered</h2>
<div class="square filter"></div>
<div class="circle filter">
<div class="inner-square"></div>
</div>
</div>
<div class="container" data-theme="green">
<h2>No-Filter Test</h2>
<div class="square filter"></div>
<div class="circle">
<div class="inner-square"></div>
</div>
</div>
<div class="container">
<h2>Original</h2>
<div class="square"></div>
<div class="circle">
<div class="inner-square"></div>
</div>
</div>
<div class="container" data-theme="blue">
<h2>Filtered</h2>
<div class="square filter"></div>
<div class="circle filter">
<div class="inner-square"></div>
</div>
</div>
<div class="container" data-theme="blue">
<h2>No-Filter Test</h2>
<div class="square filter"></div>
<div class="circle">
<div class="inner-square"></div>
</div>
</div>
This second solution works perfectly, but it requires the HTML to be restructured and the CSS adjusted to compensate:
the filtered element from the original setup needs to be placed within a container element
the non-filtered descendant of the filtered element now needs to become a sibling of the filtered element, within the same container
finally, the non-filtered sibling needs to be re-positioned within the container so that it displays in the same place as before, back when it was a descendant
After taking some time to re-arrange markup and re-adjust styles, we can achieve the originally intended effect with some elements filtered and other elements non-filtered.
This second approach feels much less elegant than calculating mirror-image colour-transformations via CSS Custom Properties and calc() but until some kind of filter mask like:
filter-apply: all | none // or even (2 - n), (n + 3) etc.
is introduced into CSS...
... the only way for a child-element to be masked from a filter is to turn the child-element into a sibling-element.

How to style another object in when a user hover object in css

I want to style an object 2 when the user hovers object 1 in css. For Example:
<style>
.object1:Hover then style object2{
Styling of object2 Goes Here
}
</style>
how can i do that
You can do this in several ways, as long as the html element 1 and 2 fulfill some conditions:
Object 1 has to come before Object 2 in your markup (as you
cannot go "up" or "back" in css selectors).
Object 2 has to be reachable by a css selector from Object 1's perspective (again, you cannot go "up" or "back" in css
selectors), that means that Object 2 cannot for example be in a
parent context of Object 1 (which would also violate 1.).
Examples for such selectors:
1. Child selector
.object1:hover .object2 { your css rules here }
works for an html structure, where .object2 is a child element of .object1:
<div class="object1">
<div class="object2">Some content</div>
</div>
2. Adjacent sibling selector
.object1:hover + .object2 { your css rules here }
works for the (one!) immmediately following sibling .object2:
<div class="object1"></div
<div class="object2">This will be affected.</div>
<div class="object2">This will NOT be affected.</div>
3. All siblings selector
.object1:hover ~ .object2 { your css rules here }
will apply your style for all (possibly many!) sibling .object2 (but just as + NOT for child .object2):
<div class="object1">
<div class="object2">This will NOT be affected.</div>
</div>
<div class="object2">This will be affected.</div>
<someElementWhichisNotAffected></someElementWhichisNotAffected>
<p class="object2">This will be affected.</p>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
div{
width: 200px;
height: 200px;
border: 2px solid #ccc;
margin: 10px auto;
}
.div1:hover{
border: 2px solid #000;
}
.div1:hover ~ .div2{
background: #f00;
}
<div class="div1"></div>
<div class="div2"></div>

CSS selector :active not working on child element click in IE8

I have the following HTML structure:
<div id="ctr__Wrapper" class="wrapper">
<div id="ctr" class="control clickable">
<img src="logo.png">
</div>
</div>
And the following CSS for this:
.control
{
border: 1px solid #000;
background-color: #666;
padding: 20px;
}
.control:active
{
background-color: #bbb;
}
When I click on the element "ctr", I see the background color changing, but when I click on the image itself, it doesn't. This works fine in Firefox, but not in IE8. Is there something I can do to solve this in CSS.
The working example can be seen here:
http://jsfiddle.net/miljenko/DNMPd/
You could use a background image instead of a real image.
html:
<div id="ctr__Wrapper" class="wrapper">
<div id="ctr" class="control clickable">
</div>
</div>
css:
.control
{
border: 1px solid #000;
background-color: #666;
height: 40+height-of-logopx;
background-image:url(logo.png); background-repeat:no-repeat;
background-position:20px 20px;
}
.control:active
{
background-color: #bbb;
}
because < ie9 don't support :active on anything other than anchor elements. here's your fiddle, that should work in ie8 http://jsfiddle.net/jalbertbowdenii/DNMPd/12/

Remove ':hover' CSS behavior from element

I have CSS that changes formatting when you hover over an element.
.test:hover { border: 1px solid red; }
<div class="test">blah</div>
In some cases, I don't want to apply CSS on hover. One way would be to just remove the CSS class from the div using jQuery, but that would break other things since I am also using that class to format its child elements.
Is there a way to remove 'hover' css styling from an element?
One method to do this is to add:
pointer-events: none;
to the element, you want to disable hover on.
(Note: this also disables javascript events on that element too, click events will actually fall through to the element behind ).
Browser Support ( 98.12% as of Jan 1, 2021 )
This seems to be much cleaner
/**
* This allows you to disable hover events for any elements
*/
.disabled {
pointer-events: none; /* <----------- */
opacity: 0.2;
}
.button {
border-radius: 30px;
padding: 10px 15px;
border: 2px solid #000;
color: #FFF;
background: #2D2D2D;
text-shadow: 1px 1px 0px #000;
cursor: pointer;
display: inline-block;
margin: 10px;
}
.button-red:hover {
background: red;
}
.button-green:hover {
background:green;
}
<div class="button button-red">I'm a red button hover over me</div>
<br />
<div class="button button-green">I'm a green button hover over me</div>
<br />
<div class="button button-red disabled">I'm a disabled red button</div>
<br />
<div class="button button-green disabled">I'm a disabled green button</div>
Use the :not pseudo-class to exclude the classes you don't want the hover to apply to:
FIDDLE
<div class="test"> blah </div>
<div class="test"> blah </div>
<div class="test nohover"> blah </div>
.test:not(.nohover):hover {
border: 1px solid red;
}
This does what you want in one css rule!
I would use two classes. Keep your test class and add a second class called testhover which you only add to those you want to hover - alongside the test class. This isn't directly what you asked but without more context it feels like the best solution and is possibly the cleanest and simplest way of doing it.
Example:
.test { border: 0px; }
.testhover:hover { border: 1px solid red; }
<div class="test"> blah </div>
<div class="test"> blah </div>
<div class="test testhover"> blah </div>
add a new .css class:
#test.nohover:hover { border: 0 }
and
<div id="test" class="nohover">blah</div>
The more "specific" css rule wins, so this border:0 version will override the generic one specified elsewhere.
I also had this problem, my solution was to have an element above the element i dont want a hover effect on:
.no-hover {
position: relative;
opacity: 0.65 !important;
display: inline-block;
}
.no-hover::before {
content: '';
background-color: transparent;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 60;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<button class="btn btn-primary">hover</button>
<span class="no-hover">
<button class="btn btn-primary ">no hover</button>
</span>
You want to keep the selector, so adding/removing it won't work. Instead of writing a hard and fast CSS selectors (or two), perhaps you can just use the original selector to apply new CSS rule to that element based on some criterion:
$(".test").hover(
if(some evaluation) {
$(this).css('border':0);
}
);