mouseover() mouseout() jQuery add/removeClass problem - javascript

I am trying to create a simple mouseover effect using a combination of mouseover, mouseout, addClass, and removeClass. Basically, when the user mouses over an element, I want to apply a different border (1px dashed gray). The initial state is "1px solid white". I have a class called "highlight" which simply has "border: 1px dashed gray" in it. I want to add that class onmouseover and remove it on onmouseout but I am unable to get the effect I want unless I use !important within the "highlight" class.

It sounds as though you've got the javascript working fine as is, but it's just a problem with the specificity of your CSS rules, which is why !important makes it work.
You just have to make your highlighted css rules more specific than the non-highlighted rules.
#someItem ul li { /* Specificity = 102 */
border-color: white;
}
.highlight { /* Specificity = 10 -- not specific enough! */
border-color: grey;
}
#someItem ul li.highlight { /* Specificity = 112 -- this will work */
border-color: grey;
}
Edit with further explanation:
Let's say the relevant parts of your HTML look like this:
<div id="someItem">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
and you have this CSS:
#someItem ul li {
border: 1px solid white;
}
.highlight {
border-color: grey;
}
Currently, all the list items in the ul in #someItem div will have a white border, and nothing has the class highlight so nothing's grey.
Through whatever means you want (in your case a hover event in jQuery), you add a class to one of the items:
$(this).addClass('highlight');
The HTML will now look something like this:
<div id="someItem">
<ul>
<li>Item 1</li>
<li class="highlight">Item 2</li>
<li>Item 3</li>
</ul>
</div>
So far, your Javascript and HTML are working fine, but you don't see a grey border! The problem is your CSS. When the browser is trying to decide how to style the element, it looks at all the different selectors which target an element and the styles defined in those selectors. If there are two different selectors both defining the same style (in our case, the border colour is contested), then it has to decide which style to apply and which to ignore. It does this by means of what is known as "Specificity" - that is, how specific a selector is. As outlined in the HTML Dog article, it does this by assigning a value to each part of your selector, and the one with the highest score wins. The points are:
element selector (eg: "ul", "li", "table") = 1 point
class selector (eg: ".highlight", ".active", ".menu") = 10 points
id selector (eg: "#someItem", "#mainContent") = 100 points
There are some more rules, eg: the keyword !important and also inline styles, but that's mostly irrelevant for this, uhh... "lesson". The only other thing you should know is that if two selectors have the same specificity, then the one defined later in the file wins.
Going back to your problem, given the CSS we had before, we can see why it's still not got a grey border:
#someItem ul li = id + element + element = 100 + 1 + 1 = 102 points
.highlight = class = 10 points
As mentioned earlier, the solution is to create a more specific selector:
#someItem ul li.highlight
= id + element + element + class
= 100 + 1 + 1 + 10
= 112 points
And to answer your question in the comments, you don't need to change any of your javascript or HTML for this to work. If you break down that selector, what it's saying is:
Look for the element with id "someItem", inside that look for a ul element, and then an li element which has the class "highlight" on it.
...and now, given the simple .addClass() call that you made earlier, the li satisfies these conditions, so the border should turn grey.

From Jquery 1.3.3 you'll be able to do this a little simpler. There will be an enhanced version of .toggleClass() available which will be very powerful.
If you don't need to break this out into a function then from 1.3.3 you'll be able to simply do:
$(".myclass").hover(function(){ $(this).toggleClass('highlight'); });
If you're having to include !important then your highlight class may need to be more specific (see CSS Specificity).

I'm guessing you're using an inline style on the element for the initial style:
<style type="text/css">
.hover { border: 1px dashed gray; } /* will never apply */
</style>
...
<!-- this style has priority over class styles! -->
<div style="border: 1px solid white">
...
</div>
This will override the styles applied using a class... So instead of using inline styles, just use a different initial class to apply the initial styles:
<style type="text/css">
.normal { border: 1px solid white; }
.hover { border: 1px dashed gray; }
</style>
...
<div class="normal">
...
</div>

This is an example of a hover I have used:
$(".myclass").hover(jbhovershow,jbhoverhide);
jbhovershow = function () {
$(this).addClass("jimtest");
};
jbhoverhide = function () {
$(this).removeClass("jimtest");
}
you don't really have to break something this simple up into seperate functions.
I suspect your issue might be with a conflict in the css - try just applying your highlight class by hardcodeing it , or on a click and see if it is really working.
Hope that helps
Jim

Have you considered a pure css approach?
For example:
someClass {
border: 1px solid white;
}
someClass:hover {
border: 1px dashed gray;
}
The hover pseudo class will give you the behavior that you want: when the user is moused over the element, it will use the lower style, otherwise it will use the first style.
Note: as someone commented, this doesn't work for non a elements in IE. It does however work for me in Chrome, Firefox, Safari, and Opera.
It also works for any element in IE8 and IE7 standards mode. I don't have IE6 to test with though.

CSS:
div.target {
border: 1px solid #000000;
}
div.target-hover {
border-color: #ff0000;
}
JS:
$("div.target").hover(
function () {
$(this).addClass("target-hover");
},
function () {
$(this).removeClass("target-hover");
}
);
i usually do it this way. (allows more options)

Or you can just do it with simple CSS by using:
#namehere { border: 1px solid #fff; }
#namehere:hover { border: 1px dashed #aaa }

Related

Change parent element background when checkbox is checked [duplicate]

How do I select the <li> element that is a direct parent of the anchor element?
As an example, my CSS would be something like this:
li < a.active {
property: value;
}
Obviously there are ways of doing this with JavaScript, but I'm hoping that there is some sort of workaround that exists native to CSS Level 2.
The menu that I am trying to style is being spewed out by a CMS, so I can't move the active element to the <li> element... (unless I theme the menu creation module which I'd rather not do).
The Selectors Level 4 Working Draft includes a :has() pseudo-class that will provide this capability. It will be similar to the jQuery implementation, but is currently not supported by Firefox.
li:has(> a.active) { /* styles to apply to the li tag */ }
As of 2022, Firefox is the only browser not supporting it by default.
In the meantime, you'll have to resort to JavaScript in Firefox if you need to select a parent element with full cross-browser support.
You can use the :has() CSS pseudo-class
But it has limited browser support (Currently only Chrome / Edge / Safari).
I don’t think you can select the parent in CSS only.
But as you already seem to have an .active class, it would be easier to move that class to the li (instead of the a). That way you can access both the li and the a via CSS only.
You can use this script:
*! > input[type=text] { background: #000; }
This will select any parent of a text input. But wait, there's still much more. If you want, you can select a specified parent:
.input-wrap! > input[type=text] { background: #000; }
Or select it when it's active:
.input-wrap! > input[type=text]:focus { background: #000; }
Check out this HTML:
<div class="input-wrap">
<input type="text" class="Name"/>
<span class="help hide">Your name sir</span>
</div>
You can select that span.help when the input is active and show it:
.input-wrap! .help > input[type=text]:focus { display: block; }
There are many more capabilities; just check out the documentation of the plugin.
BTW, it works in Internet Explorer.
As mentioned by a couple of others, there isn't a way to style an element's parent/s using just CSS but the following works with jQuery:
$("a.active").parents('li').css("property", "value");
There is no parent selector; just the way there is no previous sibling selector. One good reason for not having these selectors is because the browser has to traverse through all children of an element to determine whether or not a class should be applied. For example, if you wrote:
body:contains-selector(a.active) { background: red; }
Then the browser will have to wait until it has loaded and parsed everything until the </body> to determine if the page should be red or not.
The article Why we don't have a parent selector explains it in detail.
The pseudo element :focus-within allows a parent to be selected if a descendent has focus.
An element can be focused if it has a tabindex attribute.
Browser support for focus-within
Tabindex
Example
.parent:focus-within {
background: hsl(199deg, 65%, 73%);
}
/* demo styles */
body {
margin: 0;
}
.parent {
background: hsl(0, 0%, 80%);
min-height: 100vh;
display: grid;
place-content: center;
}
.child {
background: hsl(0, 0%, 0%);
color: white;
padding: 3rem;
outline: 0;
cursor: pointer;
font: 18px/1.25 sans-serif;
width: 20ch;
}
<div class="parent">
<div class="child" tabindex="1">
Click or Focus on me, my parent will change.
</div>
</div>
There isn't a way to do this in CSS 2. You could add the class to the li and reference the a:
li.active > a {
property: value;
}
Try to switch a to block display, and then use any style you want. The a element will fill the li element, and you will be able to modify its look as you want. Don't forget to set li padding to 0.
li {
padding: 0;
overflow: hidden;
}
a {
display: block;
width: 100%;
color: ..., background: ..., border-radius: ..., etc...
}
a.active {
color: ..., background: ...
}
The CSS selector “General Sibling Combinator” could maybe used for what you want:
E ~ F {
property: value;
}
This matches any F element that is preceded by an E element.
Not in CSS 2 as far as I'm aware. CSS 3 has more robust selectors but is not consistently implemented across all browsers. Even with the improved selectors, I don't believe it will accomplish exactly what you've specified in your example.
This is the most discussed aspect of the Selectors Level 4 specification.
With this, a selector will be able to style an element according to its child by using an exclamation mark after the given selector (!).
For example:
body! a:hover{
background: red;
}
will set a red background-color if the user hovers over any anchor.
But we have to wait for browsers' implementation :(
You might try to use hyperlink as the parent, and then change the inner elements on hover. Like this:
a.active h1 {color:red;}
a.active:hover h1 {color:green;}
a.active h2 {color:blue;}
a.active:hover h1 {color:yellow;}
This way you can change the style in multiple inner tags, based on the rollover of the parent element.
I know the OP was looking for a CSS solution but it is simple to achieve using jQuery. In my case I needed to find the <ul> parent tag for a <span> tag contained in the child <li>. jQuery has the :has selector so it's possible to identify a parent by the children it contains:
$("ul:has(#someId)")
will select the ul element that has a child element with id someId. Or to answer the original question, something like the following should do the trick (untested):
$("li:has(.active)")
Here's a hack using pointer-events with hover:
<!doctype html>
<html>
<head>
<title></title>
<style>
/* accessory */
.parent {
width: 200px;
height: 200px;
background: gray;
}
.parent,
.selector {
display: flex;
justify-content: center;
align-items: center;
}
.selector {
cursor: pointer;
background: silver;
width: 50%;
height: 50%;
}
</style>
<style>
/* pertinent */
.parent {
background: gray;
pointer-events: none;
}
.parent:hover {
background: fuchsia;
}
.parent
.selector {
pointer-events: auto;
}
</style>
</head>
<body>
<div class="parent">
<div class="selector"></div>
</div>
</body>
</html>
There's a plugin that extends CSS to include some non-standard features that can really help when designing websites. It's called EQCSS.
One of the things EQCSS adds is a parent selector. It works in all browsers, Internet Explorer 8 and up. Here's the format:
#element 'a.active' {
$parent {
background: red;
}
}
So here we've opened an element query on every element a.active, and for the styles inside that query, things like $parent make sense, because there's a reference point. The browser can find the parent, because it's very similar to parentNode in JavaScript.
Here's a demo of $parent and another $parent demo that works in Internet Explorer 8, as well as a screenshot in case you don't have Internet Explorer 8 around to test with.
EQCSS also includes meta-selectors: $prev for the element before a selected element and $this for only those elements that match an element query, and more.
Currently there is no parent selector & it is not even being discussed in any of the talks of W3C. You need to understand how CSS is evaluated by the browser to actually understand if we need it or not.
There is a lot of technical explanation here.
Jonathan Snook explains how CSS is evaluated.
Chris Coyier on the talks of Parent selector.
Harry Roberts again on writing efficient CSS selectors.
But Nicole Sullivan has some interesting facts on positive trends.
These people are all top class in the field of front end development.
Just an idea for horizontal menu...
Part of HTML
<div class='list'>
<div class='item'>
<a>Link</a>
</div>
<div class='parent-background'></div>
<!-- submenu takes this place -->
</div>
Part of CSS
/* Hide parent backgrounds... */
.parent-background {
display: none; }
/* ... and show it when hover on children */
.item:hover + .parent-background {
display: block;
position: absolute;
z-index: 10;
top: 0;
width: 100%; }
Updated demo and the rest of code
Another example how to use it with text-inputs - select parent fieldset
It's now 2019, and the latest draft of the CSS Nesting Module actually has something like this. Introducing #nest at-rules.
3.2. The Nesting At-Rule: #nest
While direct nesting looks nice, it is somewhat fragile. Some valid nesting selectors, like .foo &, are disallowed, and editing the selector in certain ways can make the rule invalid unexpectedly. As well, some people find the nesting challenging to distinguish visually from the surrounding declarations.
To aid in all these issues, this specification defines the #nest rule, which imposes fewer restrictions on how to validly nest style rules. Its syntax is:
#nest = #nest <selector> { <declaration-list> }
The #nest rule functions identically to a style rule: it starts with a selector, and contains declarations that apply to the elements the selector matches. The only difference is that the selector used in a #nest rule must be nest-containing, which means it contains a nesting selector in it somewhere. A list of selectors is nest-containing if all of its individual complex selectors are nest-containing.
(Copy and pasted from the URL above).
Example of valid selectors under this specification:
.foo {
color: red;
#nest & > .bar {
color: blue;
}
}
/* Equivalent to:
.foo { color: red; }
.foo > .bar { color: blue; }
*/
.foo {
color: red;
#nest .parent & {
color: blue;
}
}
/* Equivalent to:
.foo { color: red; }
.parent .foo { color: blue; }
*/
.foo {
color: red;
#nest :not(&) {
color: blue;
}
}
/* Equivalent to:
.foo { color: red; }
:not(.foo) { color: blue; }
*/
The short answer is NO; we don't have a parent selector at this stage in CSS, but if you don't have to swap the elements or classes anyway, the second option is using JavaScript. Something like this:
var activeATag = Array.prototype.slice.call(document.querySelectorAll('a.active'));
activeATag.map(function(x) {
if(x.parentNode.tagName === 'LI') {
x.parentNode.style.color = 'red'; // Your property: value;
}
});
Or a shorter way if you use jQuery in your application:
$('a.active').parents('li').css('color', 'red'); // Your property: value;
The W3C excluded such a selector because of the huge performance impact it would have on a browser.
Technically there is no direct way to do this. However, you can sort that out with either jQuery or JavaScript.
However, you can do something like this as well.
a.active h1 {color: blue;}
a.active p {color: green;}
jQuery
$("a.active").parents('li').css("property", "value");
If you want to achieve this using jQuery here is the reference for the jQuery parent selector.
Although there is no parent selector in standard CSS at present, I am working on a (personal) project called axe (ie. Augmented CSS Selector Syntax / ACSSSS) which, among its 7 new selectors, includes both:
an immediate parent selector < (which enables the opposite selection to >)
an any ancestor selector ^ (which enables the opposite selection to [SPACE])
axe is presently in a relatively early BETA stage of development.
See a demo here:
.parent {
float: left;
width: 180px;
height: 180px;
margin-right: 12px;
background-color: rgb(191, 191, 191);
}
.child {
width: 90px;
height: 90px;
margin: 45px;
padding-top: 12px;
font-family: sans-serif;
text-align: center;
font-size: 12px;
background-color: rgb(255, 255, 0);
}
.child.using-axe < .parent {
background-color: rgb(255, 0, 0);
}
<div class="parent">
<div class="child"></div>
</div>
<div class="parent">
<div class="child using-axe">Here, the axe parent selector turns the outer square red.</div>
</div>
<script src="https://rouninmedia.github.io/axe/axe.js"></script>
In the example above < is the immediate parent selector, so
.child.using-axe < .parent
means:
any immediate parent of .child.using-axe which is .parent
You could alternatively use:
.child.using-axe < div
which would mean:
any immediate parent of .child.using-axe which is a div
The CSS parent selector (also know as the :has() selector) has finally landed in Safari TP 137. The feature is currently being implementated in Chrome as well. (MDN Documentation)
Parent selection is done via the pseudo-class :has(). For example, div:has(> .child) will select all <div> elements with a child having a child class.
Other examples:
Selecting direct parent of an element
<div>
<p>Child Element</p>
</div>
div:has(> p)
Selecting all the parents of an element
<div id="grandparent">
<div id="parent">
<div id="child"></div>
<div>
</div>
The following selector will select both grandparent and parent
div:has(.child)
You can also use it for nested selectors and even with other pseudo classes:
div:has(> :nth-child(10))
Other valid CSS operators can be used to customize the query.
Keep an eye on caniuse.com/css-has for browser compatibility.
Updated 2022 CSS Selectors 4
In the CSS Selectors 4 specification, CSS introduces a new selector called :has(), which finally lets us select parents. That means is we’ll be able to target a CSS element that has specific children within it. This is already supported in Safari and is also in Chrome 105. The full support table is shown
here.
Parent Selectors workings
In CSS, if we want to select something, we use selectors that descend the DOM.
For example, selecting a p tag within a div tag looks like this:
div p {
color: red;
}
Until now, couldn’t really select the div tags which had p tags within them, though, and this meant we had to resort to Javascript. The main reason this wasn’t implemented in CSS is that it’s quite an expensive operation to do. CSS is relatively fast to parse, but selecting parent tags requires a relatively significantly larger amount of processing.
Using the :has selector, we can now select div elements which have a p children, or any normal combination of selectors.
For example, selecting a div with a child p now looks like this:
div:has(p) {
color: red;
}
This will make any div with a child p red.
Combining parent selection with other selectors
Just like any other CSS selector, we can combine this for specific circumstances.
For example, if you want to select only div tags which have direct span children:
div:has(> span) {
color: red;
}
As the vocabulary of :has suggested, it is not just limited to parent selection.
For example, below we can select a span which :has a sibling div:
span:has(+ div) {
color: red;
}
Or even, selecting an element which does not have a child, by using the :not() selector.
For example, the following will select any div which does not have a p child:
div:not(:has(p)) {
color: red;
}
Selecting elements that only contain text in CSS
One very common problem in CSS is that the :empty tag does not select elements that contain any text - so sometimes an element can contain one space, and :empty will not apply. The :has selector gives us the power to select elements that only contain text nodes and no other child elements.
Although this is not the perfect solution for simply :empty elements with spaces (as this will select any element with just text and no additional HTML DOM elements) - it does give us the ability to select DOM elements with only text nodes, which was not previously possible. We can achieve this with the following code:
div:not(:has(*)) {
background: green;
}
Any ideas?
CSS4 will be fancy if it adds some hooks into walking backwards. Until then it is possible (though not advisable) to use checkbox and/or radio inputs to break the usual way that things are connected, and through that also allow CSS to operate outside of its normal scope...
/* Hide things that may be latter shown */
.menu__checkbox__selection,
.menu__checkbox__style,
.menu__hidden {
display: none;
visibility: hidden;
opacity: 0;
filter: alpha(opacity=0); /* Old Microsoft opacity */
}
/* Base style for content and style menu */
.main__content {
background-color: lightgray;
color: black;
}
.menu__hidden {
background-color: black;
color: lightgray;
/* Make list look not so _listy_ */
list-style: none;
padding-left: 5px;
}
.menu__option {
box-sizing: content-box;
display: block;
position: static;
z-index: auto;
}
/* ▼ - \u2630 - Three Bars */
/*
.menu__trigger__selection::before {
content: '\2630';
display: inline-block;
}
*/
/* ▼ - Down Arrow */
.menu__trigger__selection::after {
content: "\25BC";
display: inline-block;
transform: rotate(90deg);
}
/* Customize to look more `select` like if you like */
.menu__trigger__style:hover,
.menu__trigger__style:active {
cursor: pointer;
background-color: darkgray;
color: white;
}
/**
* Things to do when checkboxes/radios are checked
*/
.menu__checkbox__selection:checked + .menu__trigger__selection::after,
.menu__checkbox__selection[checked] + .menu__trigger__selection::after {
transform: rotate(0deg);
}
/* This bit is something that you may see elsewhere */
.menu__checkbox__selection:checked ~ .menu__hidden,
.menu__checkbox__selection[checked] ~ .menu__hidden {
display: block;
visibility: visible;
opacity: 1;
filter: alpha(opacity=100); /* Microsoft!? */
}
/**
* Hacky CSS only changes based off non-inline checkboxes
* ... AKA the stuff you cannot unsee after this...
*/
.menu__checkbox__style[id="style-default"]:checked ~ .main__content {
background-color: lightgray;
color: black;
}
.menu__checkbox__style[id="style-default"]:checked ~ .main__content .menu__trigger__style[for="style-default"] {
color: darkorange;
}
.menu__checkbox__style[id="style-one"]:checked ~ .main__content {
background-color: black;
color: lightgray;
}
.menu__checkbox__style[id="style-one"]:checked ~ .main__content .menu__trigger__style[for="style-one"] {
color: darkorange;
}
.menu__checkbox__style[id="style-two"]:checked ~ .main__content {
background-color: darkgreen;
color: red;
}
.menu__checkbox__style[id="style-two"]:checked ~ .main__content .menu__trigger__style[for="style-two"] {
color: darkorange;
}
<!--
This bit works, but will one day cause troubles,
but truth is you can stick checkbox/radio inputs
just about anywhere and then call them by id with
a `for` label. Keep scrolling to see what I mean
-->
<input type="radio"
name="colorize"
class="menu__checkbox__style"
id="style-default">
<input type="radio"
name="colorize"
class="menu__checkbox__style"
id="style-one">
<input type="radio"
name="colorize"
class="menu__checkbox__style"
id="style-two">
<div class="main__content">
<p class="paragraph__split">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
</p>
<input type="checkbox"
class="menu__checkbox__selection"
id="trigger-style-menu">
<label for="trigger-style-menu"
class="menu__trigger__selection"> Theme</label>
<ul class="menu__hidden">
<li class="menu__option">
<label for="style-default"
class="menu__trigger__style">Default Style</label>
</li>
<li class="menu__option">
<label for="style-one"
class="menu__trigger__style">First Alternative Style</label>
</li>
<li class="menu__option">
<label for="style-two"
class="menu__trigger__style">Second Alternative Style</label>
</li>
</ul>
<p class="paragraph__split">
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</div>
... pretty gross, but with just CSS and HTML it is possible to touch and re-touch anything but the body and :root from just about anywhere by linking the id and for properties of radio/checkbox inputs and label triggers; likely someone'll show how to re-touch those at some point.
One additional caveat is that only one input of a specific id maybe used, first checkbox/radio wins a toggled state in other words... But multiple labels can all point to the same input, though that would make both the HTML and CSS look even grosser.
... I'm hoping that there is some sort of workaround that exists native to CSS Level 2...
I am not sure about the other pseudo classes, but I :checked for pre-CSS 3. If I remember correctly, it was something like [checked] which is why you may find it in the above code, for example,
.menu__checkbox__selection:checked ~ .menu__hidden,
.menu__checkbox__selection[checked] ~ .menu__hidden {
/* rules: and-stuff; */
}
... but for things like ::after and :hover, I'm not at all certain in which CSS version those first appeared.
That all stated, please don't ever use this in production, not even in anger. As a joke sure, or in other words just because something can be done does not always mean it should.
No, you cannot select the parent in CSS only.
But as you already seem to have an .active class, it would be easier to move that class to the li (instead of the a). That way you can access both the li and the a via CSS only.
At least up to and including CSS 3 you cannot select like that.
But it can be done pretty easily nowadays in JavaScript, you just need to add a bit of vanilla JavaScript, notice that the code is pretty short.
cells = document.querySelectorAll('div');
[].forEach.call(cells, function (el) {
//console.log(el.nodeName)
if (el.hasChildNodes() && el.firstChild.nodeName=="A") {
console.log(el)
};
});
<div>Peter</div>
<div>Jackson link</div>
<div>Philip</div>
<div>Pullman link</div>
Try this...
This solution uses plain CSS2 rules with no Javascript and works in all browsers, old and new. When clicked, the child anchor tag activates its active pseudo-class event. It then simply hides itself, allowing the active event to bubble up to the parent li tag who then restyles himself and reveals his anchor child again with a new style. The child has styled the parent.
Using your example:
<ul>
<li class="listitem">
<a class="link" href="#">This is a Link</a>
</li>
</ul>
Now apply these styles with the active pseudo-class on a to restyle the parent li tag when the link is clicked:
a.link {
display: inline-block;
color: white;
background-color: green;
text-decoration: none;
padding: 5px;
}
li.listitem {
display: inline-block;
margin: 0;
padding: 0;
background-color: transparent;
}
/* When this 'active' pseudo-class event below fires on click, it hides itself,
triggering the active event again on its parent which applies new styles to itself and its child. */
a.link:active {
display: none;
}
.listitem:active {
background-color: blue;
}
.listitem:active a.link {
display: inline-block;
background-color: transparent;
}
You should see the link with a green background now change to the list item's blue background on click.
turns to
on click.
Changing parent element based on child element can currently only happen when we have an <input> element inside the parent element. When an input gets focus, its corresponding parent element can get affected using CSS.
Following example will help you understand using :focus-within in CSS.
.outer-div {
width: 400px;
height: 400px;
padding: 50px;
float: left
}
.outer-div:focus-within {
background: red;
}
.inner-div {
width: 200px;
height: 200px;
float: left;
background: yellow;
padding: 50px;
}
<div class="outer-div">
<div class="inner-div">
I want to change outer-div(Background color) class based on inner-div. Is it possible?
<input type="text" placeholder="Name" />
</div>
</div>

Please help just using html and css how to show hide either of div from nav bar buttons [duplicate]

How do I select the <li> element that is a direct parent of the anchor element?
As an example, my CSS would be something like this:
li < a.active {
property: value;
}
Obviously there are ways of doing this with JavaScript, but I'm hoping that there is some sort of workaround that exists native to CSS Level 2.
The menu that I am trying to style is being spewed out by a CMS, so I can't move the active element to the <li> element... (unless I theme the menu creation module which I'd rather not do).
The Selectors Level 4 Working Draft includes a :has() pseudo-class that will provide this capability. It will be similar to the jQuery implementation, but is currently not supported by Firefox.
li:has(> a.active) { /* styles to apply to the li tag */ }
As of 2022, Firefox is the only browser not supporting it by default.
In the meantime, you'll have to resort to JavaScript in Firefox if you need to select a parent element with full cross-browser support.
You can use the :has() CSS pseudo-class
But it has limited browser support (Currently only Chrome / Edge / Safari).
I don’t think you can select the parent in CSS only.
But as you already seem to have an .active class, it would be easier to move that class to the li (instead of the a). That way you can access both the li and the a via CSS only.
You can use this script:
*! > input[type=text] { background: #000; }
This will select any parent of a text input. But wait, there's still much more. If you want, you can select a specified parent:
.input-wrap! > input[type=text] { background: #000; }
Or select it when it's active:
.input-wrap! > input[type=text]:focus { background: #000; }
Check out this HTML:
<div class="input-wrap">
<input type="text" class="Name"/>
<span class="help hide">Your name sir</span>
</div>
You can select that span.help when the input is active and show it:
.input-wrap! .help > input[type=text]:focus { display: block; }
There are many more capabilities; just check out the documentation of the plugin.
BTW, it works in Internet Explorer.
As mentioned by a couple of others, there isn't a way to style an element's parent/s using just CSS but the following works with jQuery:
$("a.active").parents('li').css("property", "value");
There is no parent selector; just the way there is no previous sibling selector. One good reason for not having these selectors is because the browser has to traverse through all children of an element to determine whether or not a class should be applied. For example, if you wrote:
body:contains-selector(a.active) { background: red; }
Then the browser will have to wait until it has loaded and parsed everything until the </body> to determine if the page should be red or not.
The article Why we don't have a parent selector explains it in detail.
The pseudo element :focus-within allows a parent to be selected if a descendent has focus.
An element can be focused if it has a tabindex attribute.
Browser support for focus-within
Tabindex
Example
.parent:focus-within {
background: hsl(199deg, 65%, 73%);
}
/* demo styles */
body {
margin: 0;
}
.parent {
background: hsl(0, 0%, 80%);
min-height: 100vh;
display: grid;
place-content: center;
}
.child {
background: hsl(0, 0%, 0%);
color: white;
padding: 3rem;
outline: 0;
cursor: pointer;
font: 18px/1.25 sans-serif;
width: 20ch;
}
<div class="parent">
<div class="child" tabindex="1">
Click or Focus on me, my parent will change.
</div>
</div>
There isn't a way to do this in CSS 2. You could add the class to the li and reference the a:
li.active > a {
property: value;
}
Try to switch a to block display, and then use any style you want. The a element will fill the li element, and you will be able to modify its look as you want. Don't forget to set li padding to 0.
li {
padding: 0;
overflow: hidden;
}
a {
display: block;
width: 100%;
color: ..., background: ..., border-radius: ..., etc...
}
a.active {
color: ..., background: ...
}
The CSS selector “General Sibling Combinator” could maybe used for what you want:
E ~ F {
property: value;
}
This matches any F element that is preceded by an E element.
Not in CSS 2 as far as I'm aware. CSS 3 has more robust selectors but is not consistently implemented across all browsers. Even with the improved selectors, I don't believe it will accomplish exactly what you've specified in your example.
This is the most discussed aspect of the Selectors Level 4 specification.
With this, a selector will be able to style an element according to its child by using an exclamation mark after the given selector (!).
For example:
body! a:hover{
background: red;
}
will set a red background-color if the user hovers over any anchor.
But we have to wait for browsers' implementation :(
You might try to use hyperlink as the parent, and then change the inner elements on hover. Like this:
a.active h1 {color:red;}
a.active:hover h1 {color:green;}
a.active h2 {color:blue;}
a.active:hover h1 {color:yellow;}
This way you can change the style in multiple inner tags, based on the rollover of the parent element.
I know the OP was looking for a CSS solution but it is simple to achieve using jQuery. In my case I needed to find the <ul> parent tag for a <span> tag contained in the child <li>. jQuery has the :has selector so it's possible to identify a parent by the children it contains:
$("ul:has(#someId)")
will select the ul element that has a child element with id someId. Or to answer the original question, something like the following should do the trick (untested):
$("li:has(.active)")
Here's a hack using pointer-events with hover:
<!doctype html>
<html>
<head>
<title></title>
<style>
/* accessory */
.parent {
width: 200px;
height: 200px;
background: gray;
}
.parent,
.selector {
display: flex;
justify-content: center;
align-items: center;
}
.selector {
cursor: pointer;
background: silver;
width: 50%;
height: 50%;
}
</style>
<style>
/* pertinent */
.parent {
background: gray;
pointer-events: none;
}
.parent:hover {
background: fuchsia;
}
.parent
.selector {
pointer-events: auto;
}
</style>
</head>
<body>
<div class="parent">
<div class="selector"></div>
</div>
</body>
</html>
There's a plugin that extends CSS to include some non-standard features that can really help when designing websites. It's called EQCSS.
One of the things EQCSS adds is a parent selector. It works in all browsers, Internet Explorer 8 and up. Here's the format:
#element 'a.active' {
$parent {
background: red;
}
}
So here we've opened an element query on every element a.active, and for the styles inside that query, things like $parent make sense, because there's a reference point. The browser can find the parent, because it's very similar to parentNode in JavaScript.
Here's a demo of $parent and another $parent demo that works in Internet Explorer 8, as well as a screenshot in case you don't have Internet Explorer 8 around to test with.
EQCSS also includes meta-selectors: $prev for the element before a selected element and $this for only those elements that match an element query, and more.
Currently there is no parent selector & it is not even being discussed in any of the talks of W3C. You need to understand how CSS is evaluated by the browser to actually understand if we need it or not.
There is a lot of technical explanation here.
Jonathan Snook explains how CSS is evaluated.
Chris Coyier on the talks of Parent selector.
Harry Roberts again on writing efficient CSS selectors.
But Nicole Sullivan has some interesting facts on positive trends.
These people are all top class in the field of front end development.
Just an idea for horizontal menu...
Part of HTML
<div class='list'>
<div class='item'>
<a>Link</a>
</div>
<div class='parent-background'></div>
<!-- submenu takes this place -->
</div>
Part of CSS
/* Hide parent backgrounds... */
.parent-background {
display: none; }
/* ... and show it when hover on children */
.item:hover + .parent-background {
display: block;
position: absolute;
z-index: 10;
top: 0;
width: 100%; }
Updated demo and the rest of code
Another example how to use it with text-inputs - select parent fieldset
It's now 2019, and the latest draft of the CSS Nesting Module actually has something like this. Introducing #nest at-rules.
3.2. The Nesting At-Rule: #nest
While direct nesting looks nice, it is somewhat fragile. Some valid nesting selectors, like .foo &, are disallowed, and editing the selector in certain ways can make the rule invalid unexpectedly. As well, some people find the nesting challenging to distinguish visually from the surrounding declarations.
To aid in all these issues, this specification defines the #nest rule, which imposes fewer restrictions on how to validly nest style rules. Its syntax is:
#nest = #nest <selector> { <declaration-list> }
The #nest rule functions identically to a style rule: it starts with a selector, and contains declarations that apply to the elements the selector matches. The only difference is that the selector used in a #nest rule must be nest-containing, which means it contains a nesting selector in it somewhere. A list of selectors is nest-containing if all of its individual complex selectors are nest-containing.
(Copy and pasted from the URL above).
Example of valid selectors under this specification:
.foo {
color: red;
#nest & > .bar {
color: blue;
}
}
/* Equivalent to:
.foo { color: red; }
.foo > .bar { color: blue; }
*/
.foo {
color: red;
#nest .parent & {
color: blue;
}
}
/* Equivalent to:
.foo { color: red; }
.parent .foo { color: blue; }
*/
.foo {
color: red;
#nest :not(&) {
color: blue;
}
}
/* Equivalent to:
.foo { color: red; }
:not(.foo) { color: blue; }
*/
The short answer is NO; we don't have a parent selector at this stage in CSS, but if you don't have to swap the elements or classes anyway, the second option is using JavaScript. Something like this:
var activeATag = Array.prototype.slice.call(document.querySelectorAll('a.active'));
activeATag.map(function(x) {
if(x.parentNode.tagName === 'LI') {
x.parentNode.style.color = 'red'; // Your property: value;
}
});
Or a shorter way if you use jQuery in your application:
$('a.active').parents('li').css('color', 'red'); // Your property: value;
The W3C excluded such a selector because of the huge performance impact it would have on a browser.
Technically there is no direct way to do this. However, you can sort that out with either jQuery or JavaScript.
However, you can do something like this as well.
a.active h1 {color: blue;}
a.active p {color: green;}
jQuery
$("a.active").parents('li').css("property", "value");
If you want to achieve this using jQuery here is the reference for the jQuery parent selector.
Although there is no parent selector in standard CSS at present, I am working on a (personal) project called axe (ie. Augmented CSS Selector Syntax / ACSSSS) which, among its 7 new selectors, includes both:
an immediate parent selector < (which enables the opposite selection to >)
an any ancestor selector ^ (which enables the opposite selection to [SPACE])
axe is presently in a relatively early BETA stage of development.
See a demo here:
.parent {
float: left;
width: 180px;
height: 180px;
margin-right: 12px;
background-color: rgb(191, 191, 191);
}
.child {
width: 90px;
height: 90px;
margin: 45px;
padding-top: 12px;
font-family: sans-serif;
text-align: center;
font-size: 12px;
background-color: rgb(255, 255, 0);
}
.child.using-axe < .parent {
background-color: rgb(255, 0, 0);
}
<div class="parent">
<div class="child"></div>
</div>
<div class="parent">
<div class="child using-axe">Here, the axe parent selector turns the outer square red.</div>
</div>
<script src="https://rouninmedia.github.io/axe/axe.js"></script>
In the example above < is the immediate parent selector, so
.child.using-axe < .parent
means:
any immediate parent of .child.using-axe which is .parent
You could alternatively use:
.child.using-axe < div
which would mean:
any immediate parent of .child.using-axe which is a div
The CSS parent selector (also know as the :has() selector) has finally landed in Safari TP 137. The feature is currently being implementated in Chrome as well. (MDN Documentation)
Parent selection is done via the pseudo-class :has(). For example, div:has(> .child) will select all <div> elements with a child having a child class.
Other examples:
Selecting direct parent of an element
<div>
<p>Child Element</p>
</div>
div:has(> p)
Selecting all the parents of an element
<div id="grandparent">
<div id="parent">
<div id="child"></div>
<div>
</div>
The following selector will select both grandparent and parent
div:has(.child)
You can also use it for nested selectors and even with other pseudo classes:
div:has(> :nth-child(10))
Other valid CSS operators can be used to customize the query.
Keep an eye on caniuse.com/css-has for browser compatibility.
Updated 2022 CSS Selectors 4
In the CSS Selectors 4 specification, CSS introduces a new selector called :has(), which finally lets us select parents. That means is we’ll be able to target a CSS element that has specific children within it. This is already supported in Safari and is also in Chrome 105. The full support table is shown
here.
Parent Selectors workings
In CSS, if we want to select something, we use selectors that descend the DOM.
For example, selecting a p tag within a div tag looks like this:
div p {
color: red;
}
Until now, couldn’t really select the div tags which had p tags within them, though, and this meant we had to resort to Javascript. The main reason this wasn’t implemented in CSS is that it’s quite an expensive operation to do. CSS is relatively fast to parse, but selecting parent tags requires a relatively significantly larger amount of processing.
Using the :has selector, we can now select div elements which have a p children, or any normal combination of selectors.
For example, selecting a div with a child p now looks like this:
div:has(p) {
color: red;
}
This will make any div with a child p red.
Combining parent selection with other selectors
Just like any other CSS selector, we can combine this for specific circumstances.
For example, if you want to select only div tags which have direct span children:
div:has(> span) {
color: red;
}
As the vocabulary of :has suggested, it is not just limited to parent selection.
For example, below we can select a span which :has a sibling div:
span:has(+ div) {
color: red;
}
Or even, selecting an element which does not have a child, by using the :not() selector.
For example, the following will select any div which does not have a p child:
div:not(:has(p)) {
color: red;
}
Selecting elements that only contain text in CSS
One very common problem in CSS is that the :empty tag does not select elements that contain any text - so sometimes an element can contain one space, and :empty will not apply. The :has selector gives us the power to select elements that only contain text nodes and no other child elements.
Although this is not the perfect solution for simply :empty elements with spaces (as this will select any element with just text and no additional HTML DOM elements) - it does give us the ability to select DOM elements with only text nodes, which was not previously possible. We can achieve this with the following code:
div:not(:has(*)) {
background: green;
}
Any ideas?
CSS4 will be fancy if it adds some hooks into walking backwards. Until then it is possible (though not advisable) to use checkbox and/or radio inputs to break the usual way that things are connected, and through that also allow CSS to operate outside of its normal scope...
/* Hide things that may be latter shown */
.menu__checkbox__selection,
.menu__checkbox__style,
.menu__hidden {
display: none;
visibility: hidden;
opacity: 0;
filter: alpha(opacity=0); /* Old Microsoft opacity */
}
/* Base style for content and style menu */
.main__content {
background-color: lightgray;
color: black;
}
.menu__hidden {
background-color: black;
color: lightgray;
/* Make list look not so _listy_ */
list-style: none;
padding-left: 5px;
}
.menu__option {
box-sizing: content-box;
display: block;
position: static;
z-index: auto;
}
/* ▼ - \u2630 - Three Bars */
/*
.menu__trigger__selection::before {
content: '\2630';
display: inline-block;
}
*/
/* ▼ - Down Arrow */
.menu__trigger__selection::after {
content: "\25BC";
display: inline-block;
transform: rotate(90deg);
}
/* Customize to look more `select` like if you like */
.menu__trigger__style:hover,
.menu__trigger__style:active {
cursor: pointer;
background-color: darkgray;
color: white;
}
/**
* Things to do when checkboxes/radios are checked
*/
.menu__checkbox__selection:checked + .menu__trigger__selection::after,
.menu__checkbox__selection[checked] + .menu__trigger__selection::after {
transform: rotate(0deg);
}
/* This bit is something that you may see elsewhere */
.menu__checkbox__selection:checked ~ .menu__hidden,
.menu__checkbox__selection[checked] ~ .menu__hidden {
display: block;
visibility: visible;
opacity: 1;
filter: alpha(opacity=100); /* Microsoft!? */
}
/**
* Hacky CSS only changes based off non-inline checkboxes
* ... AKA the stuff you cannot unsee after this...
*/
.menu__checkbox__style[id="style-default"]:checked ~ .main__content {
background-color: lightgray;
color: black;
}
.menu__checkbox__style[id="style-default"]:checked ~ .main__content .menu__trigger__style[for="style-default"] {
color: darkorange;
}
.menu__checkbox__style[id="style-one"]:checked ~ .main__content {
background-color: black;
color: lightgray;
}
.menu__checkbox__style[id="style-one"]:checked ~ .main__content .menu__trigger__style[for="style-one"] {
color: darkorange;
}
.menu__checkbox__style[id="style-two"]:checked ~ .main__content {
background-color: darkgreen;
color: red;
}
.menu__checkbox__style[id="style-two"]:checked ~ .main__content .menu__trigger__style[for="style-two"] {
color: darkorange;
}
<!--
This bit works, but will one day cause troubles,
but truth is you can stick checkbox/radio inputs
just about anywhere and then call them by id with
a `for` label. Keep scrolling to see what I mean
-->
<input type="radio"
name="colorize"
class="menu__checkbox__style"
id="style-default">
<input type="radio"
name="colorize"
class="menu__checkbox__style"
id="style-one">
<input type="radio"
name="colorize"
class="menu__checkbox__style"
id="style-two">
<div class="main__content">
<p class="paragraph__split">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
</p>
<input type="checkbox"
class="menu__checkbox__selection"
id="trigger-style-menu">
<label for="trigger-style-menu"
class="menu__trigger__selection"> Theme</label>
<ul class="menu__hidden">
<li class="menu__option">
<label for="style-default"
class="menu__trigger__style">Default Style</label>
</li>
<li class="menu__option">
<label for="style-one"
class="menu__trigger__style">First Alternative Style</label>
</li>
<li class="menu__option">
<label for="style-two"
class="menu__trigger__style">Second Alternative Style</label>
</li>
</ul>
<p class="paragraph__split">
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</div>
... pretty gross, but with just CSS and HTML it is possible to touch and re-touch anything but the body and :root from just about anywhere by linking the id and for properties of radio/checkbox inputs and label triggers; likely someone'll show how to re-touch those at some point.
One additional caveat is that only one input of a specific id maybe used, first checkbox/radio wins a toggled state in other words... But multiple labels can all point to the same input, though that would make both the HTML and CSS look even grosser.
... I'm hoping that there is some sort of workaround that exists native to CSS Level 2...
I am not sure about the other pseudo classes, but I :checked for pre-CSS 3. If I remember correctly, it was something like [checked] which is why you may find it in the above code, for example,
.menu__checkbox__selection:checked ~ .menu__hidden,
.menu__checkbox__selection[checked] ~ .menu__hidden {
/* rules: and-stuff; */
}
... but for things like ::after and :hover, I'm not at all certain in which CSS version those first appeared.
That all stated, please don't ever use this in production, not even in anger. As a joke sure, or in other words just because something can be done does not always mean it should.
No, you cannot select the parent in CSS only.
But as you already seem to have an .active class, it would be easier to move that class to the li (instead of the a). That way you can access both the li and the a via CSS only.
At least up to and including CSS 3 you cannot select like that.
But it can be done pretty easily nowadays in JavaScript, you just need to add a bit of vanilla JavaScript, notice that the code is pretty short.
cells = document.querySelectorAll('div');
[].forEach.call(cells, function (el) {
//console.log(el.nodeName)
if (el.hasChildNodes() && el.firstChild.nodeName=="A") {
console.log(el)
};
});
<div>Peter</div>
<div>Jackson link</div>
<div>Philip</div>
<div>Pullman link</div>
Try this...
This solution uses plain CSS2 rules with no Javascript and works in all browsers, old and new. When clicked, the child anchor tag activates its active pseudo-class event. It then simply hides itself, allowing the active event to bubble up to the parent li tag who then restyles himself and reveals his anchor child again with a new style. The child has styled the parent.
Using your example:
<ul>
<li class="listitem">
<a class="link" href="#">This is a Link</a>
</li>
</ul>
Now apply these styles with the active pseudo-class on a to restyle the parent li tag when the link is clicked:
a.link {
display: inline-block;
color: white;
background-color: green;
text-decoration: none;
padding: 5px;
}
li.listitem {
display: inline-block;
margin: 0;
padding: 0;
background-color: transparent;
}
/* When this 'active' pseudo-class event below fires on click, it hides itself,
triggering the active event again on its parent which applies new styles to itself and its child. */
a.link:active {
display: none;
}
.listitem:active {
background-color: blue;
}
.listitem:active a.link {
display: inline-block;
background-color: transparent;
}
You should see the link with a green background now change to the list item's blue background on click.
turns to
on click.
Changing parent element based on child element can currently only happen when we have an <input> element inside the parent element. When an input gets focus, its corresponding parent element can get affected using CSS.
Following example will help you understand using :focus-within in CSS.
.outer-div {
width: 400px;
height: 400px;
padding: 50px;
float: left
}
.outer-div:focus-within {
background: red;
}
.inner-div {
width: 200px;
height: 200px;
float: left;
background: yellow;
padding: 50px;
}
<div class="outer-div">
<div class="inner-div">
I want to change outer-div(Background color) class based on inner-div. Is it possible?
<input type="text" placeholder="Name" />
</div>
</div>

Select element based in css property

I want to select a child element that has a specific background color.
For example, I have my parent #xxx (id) and it has lots of direct children. I want to select all the children from this parent #xxx that have bakground:#000
I searched a lot and couldnt find an answer. Could you help me? Something like this (of course it does not work):
#xxx > div(background:#000) {
}
You can't do this with css, but you can use jquery for that:
$('#xxx div').filter((index, el) => {
return $(el).css('backgroundColor') == 'rgb(0, 0, 0)'
}).css('color', 'white');
.a {
background: red;
}
.b {
background: green;
}
.c {
background: blue;
}
.d {
background: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="xxx">
<div class="a">a1</div>
<div class="b">a2</div>
<div class="c">a3</div>
<div class="d">a4</div>
</div>
As far as I know this isn't possible.
You could do it with jQuery.
But a better option might be something like this:
.black { background-color: #000000; }
.red { background-color: #ff0000; }
#xxx > .black { padding: 10px; }
If you don't want to use JQuery, There is a pretty good way to use CSS3 [attribute*=value] Selector to achieve that:
#xxx > div(style*="background:#000")
{
...
}
BUT
Notice 1: keep this in your mind that as attribute selectors don't support regular expressions, you can only perform exact sub-string matches of the attribute value.
Notice 2: You have to use inline mode style, otherwise it does not work.
I hope to be helpful :)
Some of you said this is not possible but it is possible. It's very possible. You just need to take care with the color, browsers (Chrome and Firefox latest that I could try) allow selection based in the background color BUT it has to be in RGB format and you need to use a space after the comma in the color. This will work perfectly:
#xxx[style*="background: rgb(255, 255, 255)"]>div:hover{
border:10px solid #000000;
}

Setting the border color of text boxes on the form

I want to set all text boxes border color on the form to red. I tried using
$('*').css('border', 'black');
also
var all = document.getElementsByTagName('*');
for(var i=0;i<all.length;i++)
{
all[i].style.backgroundColor = "Red";
}
Nothing is working for me.
In the CSS file all text boxes
input[type=text], .htmlplusinput {
border: 1px solid #C79988;
padding:1px;
width:120px;
cursor: text;
}
input[type=text]:focus, .htmlplusinput:focus {
border:2px solid #25a3fc;
padding:0px;
}
To start with, the $('*') selector matches all elements. If you only want text boxes, you'll want to use $('input:text').
Once you have the selector correct, you need to set the colour of the border. If I recall correctly, the correct CSS property is border-color, so you'd do:
$('input:text').css('border-color', 'red');
Another, potentially better, solution would be to add a class to each of the elements, rather than modifying their style property, then use a CSS declaration for that class to control the appearance of the border:
$('input:text').addClass('redborder');
.redborder {
border-color: red;
}
This should do the job:
jQuery('input:text').css('borderColor', '#000');

Strange behavior in IE when combining click handler with CSS sibling selector

I am trying to design a menu that is triggered by clicking a button. When the user clicks the button, a click handler runs which adds a class to the button, and a CSS rule using an sibling selector makes the menu visible. It works fine in all the browsers I tested except IE 7 and 8.
In IE 7 and 8, I am experiencing these problems:
Clicking the button toggles the class but the menu doesn't appear or disappear until I move the mouse around a little bit.
The menu doesn't work at all unless I have a CSS :hover declaration for children of the menu. It doesn't matter what I put in the declaration, or if I put anything at all, but the menu does not show up without it.
Can anyone tell me why this is happening and what I can do about it? I was thinking of adding a separate class to the menu but I am wondering if there is a simpler fix or workaround. Here is my code:
<!DOCTYPE html>
<html><head>
<title>IE selector test</title>
<style type="text/css">
button {
border: outset 1px #eeeeee;
}
button.active {
border-style: inset;
}
.menu {
display: none;
border: solid 1px #888888;
}
button.active ~ .menu {
display: block;
}
.menu > :hover {
/* For some reason, the menu doesn't work at all without this declaration */
}
</style>
</head>
<body>
<button type="button" id="menuButton">Menu</button>
<div class="menu">
<div>option</div>
</div>
<script>
document.getElementById("menuButton").onclick = function() {
if (this.className) {
this.className = "";
} else {
this.className = "active";
}
};
</script>
</body>
</html>
You can also test it at http://jsfiddle.net/QKqpn/.
You can work around it by forcing page redraw:
document.body.className = document.body.className;
See http://jsfiddle.net/uGW4M/
BTW, in your case you can use + (one immediate sibling) combinator instead of more common ~ (all subsequent siblings):
button.active + .menu {/* ... */}

Categories