How can I change the style of another element when a link is hovered - without jQuery/ JavaScript?
ul>li>a:hover main {
opacity: 0.1;
}
main p {
font-size: 200px;
}
<header>
<ul>
<li>Hover me</li>
</ul>
</header>
<main>
<p>Hello World!</p>
</main>
I want to change the opacity of the text in main when the link is hovered.
Is it possible?
EDIT
I tried with a sibling:
a:hover ul {
opacity: 0.5;
}
<header>
<ul>
<li>Hover me<span></span>
<ul>
<li>Child 1</li>
<li>Child 2</li>
<li>Child 3</li>
</ul>
</li>
</ul>
</header>
But still does not work...
It's possible but the layout must be situated differently due to CSS cascading behavior. Whatever you hover over (call it the trigger) and whatever is fading because of the hover (call it target) must have specific positions in order for it to work.
Trigger -
Can be before target as an "older" sibling.
OR
Can be an ancestor of target or a sibling of an ancestor of target.
Demo
a {
border: 3px dotted blue;
padding: 0 5px;
color: #000;
text-decoration: none;
display: block;
}
a.aunt {
border-color: red;
margin: 10px 0;
}
a.aunt:hover+main p {
opacity: 0.1;
transition: 1s;
}
a.brother:hover+p {
color: red;
}
a.sister:hover~p {
color: blue;
}
main.mom {
border: 5px dashed tomato;
}
main.mom p {
opacity: 1;
font-size: 50px;
margin-top: 10px;
transition: 1s;
border: 3px solid red;
}
main.mom:hover p {
font-size: 100px;
}
b {
font-size: 25px
}
<a href='#/' class='aunt'>Aunt - Older sibling of an ancestor of the target</a>
<main class='mom'>
<a href='#/' class='sister'>Big Sister - Sibling to target with <br>sibling combinator: <b>~</b></a><br><br>
<a href='#/' class='brother'>Big Brother - Adjacent Sibling to target with <br>adjacent sibling combinator: <b>+</b></a>
<p>Target</p>
<a href='#/' class='brother'>Little Brother - Cannot influence target when hovered on.</a>
<br> Mom - hovering over affects all descendants<br>(i.e. all siblings and siblings' and target's descendants)<br>
</main>
<a href='#/' class='aunt'>Aunt - This is after target's ancestor so it cannot influence target</a>
In general, this type of problem is solved using combinators.
In this specific case, you need a parent combinator, which does not exist in CSS, so it is impossible without restructuring the HTML (e.g. to make the <main> a sibling of the <a>).
It is not possible to use + or ~ sibling selectors, becouse <a> and <main> elements are not siblings. Thus you could use JavaScript. For example it is possible using by fadeTo() within hover() method:
$("a[data-opacity-target]").hover(function() {
var selector = $(this).data("opacity-target");
$(selector).fadeTo(500, 0.1);
}, function() {
var selector = $(this).data("opacity-target");
$(selector).fadeTo(500, 1);
});
main p {
font-size: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
<ul>
<li>Hover me</li>
</ul>
</header>
<main>
<p>Hello World!</p>
</main>
In your EDIT section you should use a:hover~ul selector instead of a:hover ul.
Really interesting question.
You can try out the following code:
.trigger{
color: black;
}
div:hover ~ .trigger{
color: orange;
}
div{
display: inline-block;
border: 1px solid green;
border-radius: 10px;
padding: 5px;
width: auto;
}
<!DOCTYPE html>
<html>
<head>
<title>Pure CSS event handling</title>
</head>
<body>
<div>Hover over me for pure CSS events</div>
<p class="trigger">Hey Pikachu!</p>
</body>
</html>
Take a look at this link, it explains about the tilde selector in CSS:
what-does-the-tilde-squiggle-twiddle-css-selector-mean
I personally thought this was not possible. I learnt something new today! :D
Related
I want to change the color of the menu on text hover. But not when the menu text is hovered but another heading. I have a heading "Not a restaurant, but here for them." and when the user hovers the word "restaurant" the menu text color should change to white and the word "restaurant" to red and the rest of the heading to white. The second part (that "restaurant" changes to red and the rest of the heading to white) already works. But how can I make it that also the color of the menu changes?
.headingRestaurant:hover {
color: red;
}
.headingRestaurant {
cursor: pointer;
}
.textb {
pointer-events: none;
}
.headingRestaurant {
pointer-events: initial;
}
.textb:hover {
color: white;
}
<nav>
<ul>
<li>
Home
</li>
<li>
About
</li>
</ul>
</nav>
<h1 class="textb">
Not a <span id="heading1" class="headingRestaurant">restaurant</span>,
<br> but here for them.
</h1>
Since CSS can only interact with things inside or below the current element, the easiest solution would be to use Javascript to handle the hover for you.
You can use the function addEventListener to add both a mouseover and a mouseout event on your restaurant text to add/remove a hover class to whichever element you want to hover.
var nav = document.querySelector('nav');
var headingRestaurant = document.querySelector('.headingRestaurant');
headingRestaurant.addEventListener('mouseover', function() {
nav.classList.add('hover');
});
headingRestaurant.addEventListener('mouseout', function() {
nav.classList.remove('hover');
});
.headingRestaurant:hover {
color: red;
}
.headingRestaurant {
cursor: pointer;
}
.textb {
pointer-events: none;
}
.headingRestaurant {
pointer-events: initial;
}
.textb:hover {
color: white;
}
nav.hover,
nav.hover a {
color: red;
}
<nav>
<ul>
<li>
<a
href="file:///C:/Users/.../index.html"
>Home</a
>
</li>
<li>
<a
href="file:///C:/Users/.../about.html"
>About</a
>
</li>
</ul>
</nav>
<h1 class="textb">
Not a <span id="heading1" class="headingRestaurant">restaurant</span>,
<br />
but here for them.
</h1>
If you'd like to use html and css only, you'd have to reverse the html flow so that the element you want to change is coded below the element you're hovering over.
In this case I've moved the nav and h1 to a container div and swapped them around so that the h1 is coded above the nav. The display order is then fixed by using both the properties display: flex and flex-direction: column-reverse. The hover in this method uses the css selector ~ which matches an selector that is preceded by another selector. In the case of .textb:hover ~ nav it would select any nav element that is preceded by a .textb which is hovered over. Since the part after the ~ is still a selector, you could also change a specific menu item.
.headingRestaurant {
cursor: pointer;
pointer-events: initial;
}
.textb {
pointer-events: none;
}
.textb:hover {
color: white;
}
.textb:hover .headingRestaurant {
color: red;
}
.textb:hover ~ nav,
.textb:hover ~ nav a {
color: red;
}
.textb:hover ~ nav a.about {
color: purple;
}
.reversed {
display: flex;
flex-direction: column-reverse;
}
<div class="reversed">
<h1 class="textb">
Not a <span id="heading1" class="headingRestaurant">restaurant</span>,
<br />
but here for them.
</h1>
<nav>
<ul>
<li>
<a class="about" href="file:///C:/Users/.../index.html">Home</a>
</li>
<li>
About
</li>
</ul>
</nav>
</div>
:has is definitely the way to go here but there are some clever cookies out there who might come up with something innovative. Note that this isn't fully supported yet.
/* This is just making things pretty */
nav ul li {
display: inline-block;
padding: 0.5rem 1rem;
margin: 0;
border: 1px dotted red;
}
nav ul {
list-style-type: none;
margin: 0;
padding: 0;
}
nav ul li a {
text-decoration: none;
color: inherit;
}
/* This is the functional stuff */
.headingRestaurant:hover {
color: red;
}
.headingRestaurant {
cursor: pointer;
}
.textb {
pointer-events: none;
}
.headingRestaurant {
pointer-events: initial;
}
.textb:hover {
color: white;
}
/* This colours the menu on hover */
body:has(.headingRestaurant:hover) nav {
background-color: lightblue;
}
<nav>
<ul>
<li>
Home
</li>
<li>
About
</li>
</ul>
</nav>
<h1 class="textb">
Not a <span id="heading1" class="headingRestaurant">restaurant</span>,
<br> but here for them.
</h1>
Replace target with whatever class/id you are using to identify your menu element and it will control the styling when hovering on the .headingRestaurant element.
.headingRestaurant:hover target {
}
This question already has answers here:
Make CSS Hover state remain after "unhovering"
(11 answers)
Hover CSS styling that persists after mouse away
(3 answers)
Closed 3 years ago.
I have created a navigation bar with a :hover effect and I'd like to know how to make that effect persistent, even after the cursor is removed from the area. The effect is a background color under the given word. For example, when Home is selected I'd like for that effect to stay on the element until another element (for example, Register) is clicked.
.navbar {
list-style-type: none;
background-color: black;
display: flex;
justify-content: flex-start;
align-items: center;
margin: 0;
height: 50px;
padding: 0;
}
.navbar a {
text-decoration: none;
color: gray;
padding: 17px;
transition: background-color 0.5s linear;
}
.navbar a:hover {
background-color: green;
color: honeydew;
}
body {
margin: 0;
}
<header>
<nav>
<ul class='navbar'>
<li><a href='#home'>Home</a></li>
<li><a href='#download'>Download</a></li>
<li><a href='#register'>Register</a></li>
<li><a href='#contact'>Contact</a></li>
<li><a href='#FAQ'>FAQ</a></li>
</ul>
</nav>
</header>
The desired effect can be achieved with just CSS but it's tricky and the only way I know of would cause your links to become non-functional (since it requires replacing your links with <input type="radio">). So overall, I would recommend to use JavaScript for this.
The JavaScript way would be, using jQuery, to add a class when the mouseover event is triggered and to remove it from all other elements on another desired event getting triggered.
Example: (I have replaced the :hover pseudoselector with a .hover class selector and added the jQuery library and required code.)
jQuery is not required to achieve this effect, you can do this just fine with vanilla JavaScript.
$(".navbar a").on("mouseover", function () {
$(".navbar a").removeClass("hover");
$(this).addClass("hover");
});
.navbar {
list-style-type: none;
background-color: black;
display: flex;
justify-content: flex-start;
align-items: center;
margin: 0;
height: 50px;
padding: 0;
}
.navbar a {
text-decoration: none;
color: gray;
padding: 17px;
transition: background-color 0.5s linear;
}
.navbar a.hover {
background-color: green;
color: honeydew;
}
body {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
<nav>
<ul class='navbar'>
<li><a href='#home'>Home</a></li>
<li><a href='#download'>Download</a></li>
<li><a href='#register'>Register</a></li>
<li><a href='#contact'>Contact</a></li>
<li><a href='#FAQ'>FAQ</a></li>
</ul>
</nav>
</header>
I imported a third party CSS (which I'm not allowed to modify) into my application. This CSS file is declaring a class name and a selector, e.g.:
.third-party-class{
color: blue;
}
.third-party-class:last-of-type{
color: red;
}
My goal is to remove the .third-party-class:last-of-type selector completely by using CSS only. Of course you could just override the .third-party-class:last-of-type selector and copy every property from .third-party-class. But this is really inconvenient if .third-party-class has a lot of properties.
.third-party-class{
color: blue;
}
.third-party-class:last-of-type{
color: red;
}
.desired-li{
color: blue;
}
<div>
Currently:
<ul>
<li class="third-party-class">one</li>
<li class="third-party-class">two</li>
<li class="third-party-class">three</li>
</ul>
Desired:
<ul>
<li class="desired-li">one</li>
<li class="desired-li">two</li>
<li class="desired-li">three</li>
</ul>
</div>
Question
Is it possible to override/remove a CSS selector completely, without redeclaring all properties of the "base" class by using CSS (no JS) only?
Since we are dealing with last-of-type and you cannot change the CSS, you can add an extra element that will trigger this selector and hide it (I suppose you are able to adjust the HTML):
.third-party-class {
color: blue;
}
.third-party-class:last-of-type {
color: red;
background:pink;
font-size:250px;
opacity:0.9;
display:flex;
vertical-align:sub;
/*doesn't matter what CSS you will have here*/
}
ul li:last-of-type {
display:none!important;
}
<ul>
<li class="third-party-class">one</li>
<li class="third-party-class">two</li>
<li class="third-party-class">three</li>
<li></li>
</ul>
I agree with the comment that BenM made to your original question.
But...If the CSS is as simple (only one line) as your fiddle leads me to believe you could just use "!important" on the selector you want to overwrite.
.third-party-class:last-of-type{
color: blue !important;
}
That would allow you, on a selector by selector basis (assuming there are more than just color being used), specify what you want the third party code to do.
You could use the [attribute^=value] Selector, it will overide every ellement who starts with "value" so you can make something like this:
.third-party-class{
background: blue;
height: 20px;
width: 20px;
margin-bottom: 10px;
}
.third-party-class:last-of-type{
background: red;
}
div[class^="third-party-class"]{
background: green;
}
<div class="third-party-class"></div>
<div class="third-party-class"></div>
<div class="third-party-class"></div>
<div class="third-party-class"></div>
<div class="third-party-class"></div>
<div class="third-party-class"></div>
<div class="third-party-class"></div>
<div class="third-party-class"></div>
<div class="third-party-class"></div>
<div class="third-party-class"></div>
Sorry if i do not understand it right
Please have a look at the codes (HTML and CSS) and please let me know how can I hover over one menu item and them the corresponding divs appear at the bottom. Let me know what is wrong with my code!!!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Trying to show a div while hover over menu items</title>
<style type="text/css">
.menu_div {
width: 300px;
height: 50px;
background-color:red;
display: block;}
.menu_div ul li {list-style: none; display:inline-block;}
.show_div ul li {display: inline-block;}
.show_div_one {
width: 300px;
height: 50px;
background-color: orange;
margin-top: 50px;
display: none;
}
.show_div_two {
width: 300px;
height: 50px;
background-color: orange;
margin-top: 50px;
display: none;
}
.menu_div ul li.menu_item_one:hover + .show_div ul li.show_div_one{display:block;}
.menu_div ul li.menu_item_two:hover + .show_div ul li.show_div_two{display:block;}
</style>
</head>
<body>
<div class="menu_div">
<ul>
<li class="menu_item_one">
Home
</li>
<li class="menu_item_two">
about
</li>
</ul>
</div>
<div class="show_div">
<ul>
<li>
<div class="show_div_one">
</div>
</li>
<li>
<div class="show_div_two">
</div>
</li>
</ul>
</div>
</body>
</html>
Your CSS selectors, although they may seem to be logically using the + adjacency operator, in fact, arent.
The direct adjacency selector is for DOM elements that come directly after one another. In your HTML, in order to reach the elements you wish to show you have to first traverse the DOM 'upward' to the parent menu_div element, then across to its sibling show_div and then down to the correct child. CSS cannot do this.
More on this from MDN
(+) This is referred to as an adjacent selector. It will select only
the specified element that immediately follows the former specified
element.
You will need to change your code per the below, to place the element you wish to show immediately following the element you wish to hover on, you may also want to control its positioning by setting position:absolute
Demo Fiddle
<div class="menu_div">
<ul>
<li class="menu_item_one"> Home
<div class="show_div_one">show me!</div>
</li>
<li class="menu_item_two"> about
<div class="show_div_two">show me!</div>
</li>
</ul>
</div>
CSS
.menu_div {
width: 300px;
height: 50px;
background-color:red;
display: block;
}
.menu_div ul li {
list-style: none;
display:inline-block;
}
.show_div ul li {
display: inline-block;
}
.show_div_one, .show_div_two {
width: 300px;
height: 50px;
background-color: orange;
margin-top: 50px;
display: none;
position:absolute; /* <--- keep the flow you anticipate */
}
.menu_div ul li.menu_item_one a:hover + .show_div_one {
display:block;
}
.menu_div ul li.menu_item_two a:hover + .show_div_two {
display:block;
}
Why not use JQuery as this will be far better than relying on CSS alone.
Example: Fiddle
$( document ).ready( function() {
$('.show_div_one').hide();
$('.menu_item_one').hover(
function(){
$('.show_div_one').show();
},
function(){
$('.show_div_one').hide();
}
);
});
Not tested, but thats the general idea for each one you would want to appear and disappear based on hover.
I've got a navigation menu. But the menu get's wild.
The submenu class (this is the dropdown if you hover firstmenu). 'firstmenu' are the main areas of the site, hence the first level of the list.
Problem: Submenu get's the Firstmenus values. Even the tiny arrow background: url(images/nav-arrow.png) no-repeat center bottom; in - BUT WHY?!
We already looked into this, split up the code, removed typo3, all JavaScript and ended up with this css code:
#firstmenu {
list-style: none;
margin: 0;
padding: 0;
}
#firstmenu .firstLevel {
float: left;
}
#firstmenu .firstLevel a {
display: block;
font-size: 1.166em;
font-weight: 600;
line-height: normal;
color: #333;
padding: 41px 20px 26px;
margin-bottom: 4px;
}
#firstmenu .firstLevel .current a,
#firstmenu .firstLevel a:hover,
#firstmenu .firstLevel a.selected {
color: #fff;
background: url(images/nav-arrow.png) no-repeat center bottom;
}
#firstmenu .firstLevel a:hover,
#firstmenu .firstLevel a.selected {
background-color: #333;
}
/* Drop-Down Menus */
.submenu {
list-style: none;
margin: 0;
padding: 0;
position: absolute;
}
.submenu > ul {
top: 4px !important;
}
.submenu .secoundLevel {
width: 200px;
background: #fca500;
}
.submenu .secoundLevel a {
display: block;
color: #fff;
padding: 8px 15px;
border-top: 1px solid rgba(255,255,255,0.2);
}
.submenu .secoundLevel a:hover {
background-color: #333;
border-color: #1a1a1a;
}
.submenu .secoundLevel:first-child a {
border-top: none;
}
Anyone knows the fix?
EDIT, html:
<nav id="nav">
<ul id="firstmenu" class="clearfix">
<li class="firstLevel"><a href="index.php?id=99" >Startseite</a></li>
<li class="firstLevel current">Rootserver
<ul class="submenu">
<li class="secoundLevel"><a href="index.php?id=96" >Vergleich</a></li>
</ul>
</li>
<li class="firstLevel">Voiceserver
<ul class="submenu">
<li class="secoundLevel">Preisvergleich</li>
</ul>
</li>
</ul>
</nav>
I think the problem is a matter of understanding of CSS selectors. This selector:
#firstmenu .firstLevel a.selected {
color: #fff;
background: url(images/nav-arrow.png) no-repeat center bottom;
}
States the following: Match ALL <a> links that have a parent with class name firstLevel and it having a parent with ID firstmenu
That means this HTML bit matches:
<ul id="firstmenu" class="clearfix">
// snip
<li class="firstLevel current">Rootserver
<ul class="submenu">
<li class="secoundLevel">Vergleich</li>
</ul>
</li>
// snip
because the "secondLevel" menu has an anchor tag (<a>) that is a child (of any order, ie child, grandchild, great-grandchild, etc) of .firstLevel which is a child (of any order) of #firstmenu.
This is exactly how CSS is suppose to work but there ways to prevent what you're seeing.
The first option is to use the child selector (what I sometimes refer to as "direct descendent" selector) >
.firstLevel > a:hover{ /* code */ }
This selector specifically states: "all anchor tag that you hover which are directly descendent from .firstLevel, but no deeper.
Which means, it matches:
<li class="firstLevel">A</li>
but not the link with value "B" below
<li class="firstLevel">A
<ul>
<li><a href="#">B</b></li>
</ul>
</li>
because the second <a> tag is not directly descendant of .firstLevel, there's a <ul> and <li> between them.
The second option is to "overwrite" the previous style by having another rule with a higher CSS specificity.
#firstmenu .firstLevel .submenu a.selected {
background-image: none; /* remove the arrow from drop-down menus*/
}
There's reasons for doing one or the other.
Using the child selector is good when the styles are very specific to that element. You don't want ANY of the styles to carry over to further elements.
Use the "replacement" technique (for lack of a better term) when you're looking to modify only one specific style from another element. Ie. You want to keep the color, font, font-weight, but only want to remove the background image.
I hope that helps!
Here's some (bad) fiddles showing the base case:
http://jsfiddle.net/zTCbF/
with child selector
http://jsfiddle.net/zTCbF/1/
with the replacement technique
http://jsfiddle.net/zTCbF/2/
#firstmenu .firstLevel a {
This will target any anchor tag under .firstLevel including those under .secondLevel
So when you say...
#firstmenu .firstLevel a:hover,
You are applying your hover styles to ALL anchor tags that are descendants of .firstLevel
You want to say ...
#firstmenu .firstLevel > a {
Which will target only anchor tags that are a direct descendant of .firstLevel