I want to apply CSS to a sibling div when an a link is :active
.navigation-menu:active ~ .container-menu,
left: 0;
}
I know IE9 and below don't support this but does IE10?
No it doesn't work in IE10. I tested with the following fiddle: http://jsfiddle.net/uYsXP/
HTML:
<div>
Click me
<div class="container-menu">Bacon!</div>
</div>
CSS:
.navigation-menu:active ~ .container-menu {
color: green;
}
To use the general sibling selector with a pseudo class, you run into some bugs, but this can be fixed. Refer to this article:
http://css-tricks.com/webkit-sibling-bug/
body { -webkit-animation: bugfix infinite 1s; }
#-webkit-keyframes bugfix { from { padding: 0; } to { padding: 0; } }
This should work IE8+
The :active state of a child is not propagated down from the parent (at least in IE 10)
There's a JS workaround posted on this SO answer: Make a whole div clickable with working :active css rule in IE10
It's worth noting that the IE dev team has classified this issue as won't fix
Propagating the active state to ancestor elements can significantly
degrade the responsiveness of web pages due to the large number of
elements that may be impacted by the state change. As a result, this
makes interactive controls feel sluggish to an end user, particularly
in touch interaction where tiny delays are easily perceptible.
source: https://connect.microsoft.com/IE/feedback/details/757765/ie10-active-psuedo-class-should-be-triggered-by-child-elements-too
Related
I know that there does not exist a CSS parent selector, but is it possible to style a parenting element when hovering a child element without such a selector?
To give an example: consider a delete button that when hovered will highlight the element that is about to become deleted:
<div>
<p>Lorem ipsum ...</p>
<button>Delete</button>
</div>
By means of pure CSS, how to change the background color of this section when the mouse is over the button?
I know it is an old question, but I just managed to do so without a pseudo child (but a pseudo wrapper).
If you set the parent to be with no pointer-events, and then a child div with pointer-events set to auto, it works:)
Note that <img> tag (for example) doesn't do the trick.
Also remember to set pointer-events to auto for other children which have their own event listener, or otherwise they will lose their click functionality.
div.parent {
pointer-events: none;
}
div.child {
pointer-events: auto;
}
div.parent:hover {
background: yellow;
}
<div class="parent">
parent - you can hover over here and it won't trigger
<div class="child">hover over the child instead!</div>
</div>
Edit:
As Shadow Wizard kindly noted: it's worth to mention this won't work for IE10 and below. (Old versions of FF and Chrome too, see here)
Well, this question is asked many times before, and the short typical answer is: It cannot be done by pure CSS. It's in the name: Cascading Style Sheets only supports styling in cascading direction, not up.
But in most circumstances where this effect is wished, like in the given example, there still is the possibility to use these cascading characteristics to reach the desired effect. Consider this pseudo markup:
<parent>
<sibling></sibling>
<child></child>
</parent>
The trick is to give the sibling the same size and position as the parent and to style the sibling instead of the parent. This will look like the parent is styled!
Now, how to style the sibling?
When the child is hovered, the parent is too, but the sibling is not. The same goes for the sibling. This concludes in three possible CSS selector paths for styling the sibling:
parent sibling { }
parent sibling:hover { }
parent:hover sibling { }
These different paths allow for some nice possibilities. For instance, unleashing this trick on the example in the question results in this fiddle:
div {position: relative}
div:hover {background: salmon}
div p:hover {background: white}
div p {padding-bottom: 26px}
div button {position: absolute; bottom: 0}
Obviously, in most cases this trick depends on the use of absolute positioning to give the sibling the same size as the parent, ánd still let the child appear within the parent.
Sometimes it is necessary to use a more qualified selector path in order to select a specific element, as shown in this fiddle which implements the trick multiple times in a tree menu. Quite nice really.
Another, simpler "alternate" approach (to an old question)..
would be to place elements as siblings and use:
Adjacent Sibling Selector (+)
or
General Sibling Selector (~)
<div id="parent">
<!-- control should come before the target... think "cascading" ! -->
<button id="control">Hover Me!</button>
<div id="target">I'm hovered too!</div>
</div>
#parent {
position: relative;
height: 100px;
}
/* Move button control to bottom. */
#control {
position: absolute;
bottom: 0;
}
#control:hover ~ #target {
background: red;
}
Demo Fiddle here.
there is no CSS selector for selecting a parent of a selected child.
you could do it with JavaScript
As mentioned previously "there is no CSS selector for selecting a parent of a selected child".
So you either:
use a CSS hack as described in NGLN's answer
use javascript - along with jQuery most likely
Here is the example for the javascript/jQuery solution
On the javascript side:
$('#my-id-selector-00').on('mouseover', function(){
$(this).parent().addClass('is-hover');
}).on('mouseout', function(){
$(this).parent().removeClass('is-hover');
})
And on the CSS side, you'd have something like this:
.is-hover {
background-color: red;
}
In 2022:
This can be now achieved with CSS only, using the :has pseudo-class and the following expression:
div:has(button:hover) {}
Here's a snippet showcasing the original proposition:
div:has(button:hover) {
background-color: cyan;
}
<div>
<p>Lorem ipsum ...</p>
<button>Delete</button>
</div>
See browser support here. At the time of writing, all major browser support it—except Firefox, which still has a flawed experimental implementation.
This solution depends fully on the design, but if you have a parent div that you want to change the background on when hovering a child you can try to mimic the parent with a ::after / ::before.
<div class="item">
design <span class="icon-cross">x</span>
</div>
CSS:
.item {
background: blue;
border-radius: 10px;
position: relative;
z-index: 1;
}
.item span.icon-cross:hover::after {
background: DodgerBlue;
border-radius: 10px;
display: block;
position: absolute;
z-index: -1;
top: 0;
left: 0;
right: 0;
bottom: 0;
content: "";
}
See a full fiddle example here
This is extremely easy to do in Sass! Don't delve into JavaScript for this. The & selector in sass does exactly this.
http://thesassway.com/intermediate/referencing-parent-selectors-using-ampersand
I'm trying to use CSS attr() to change background color of a pseudo :before element.
<ul>
<li data-color="#ff0000">R</li>
<li data-color="#00ff00">G</li>
<li data-color="#0000ff">B</li>
</ul>
Here's the CSS
ul {
list-style: none;
}
li:before {
background-color: attr(data-color, color);
content: "";
display: inline-block;
height: 10px;
width: 10px;
}
But the before element doesn't show background color according to the data-color attribute.
But when I add this CSS
li:after {
content: attr(data-color);
}
The :after element shows the data-color attribute content as the content.
Here's the JS fiddle http://jsfiddle.net/b7Rve/
What did I do wrong?
UPDATE
I just reread about color in the Mozilla developer docs. It says that color type is experimental. I guess I still need to wait until it's released.
Please, look at this other thread Setting width with CSS attr().
In short: "according to Mozilla Developer Network's documentation, is only compatible with the CSS content property [...], but cannot (yet) be used to generate values for other properties."
UPDATE MAY 16, 2016:
Looking at Mozilla Developer Network's documentation now is possibile but with caution:
The attr() function can be used with any CSS property, but support for
properties other than content is experimental.
So, actually you can use it but surely browsers' support, altough better than in the past, is still only rare and experimental.
Is there any way to inspect elements that were added via the CSS :before selector, in the Chrome or FF web inspector and inspect their calculated styles (and manipulate them on the fly)?
Setup is
li:before {
display: block;
width: 50px;
height: 50px;
position: absolute;
}
So it's real block element without any HTML, but on inspection he only selects the related LI element. The "force element state"-option does not work either, it's only for interaction states like :hover but not :before
Yes, there is. Inspect the element itself (not the pseudo), the pseudo element's styles should show up below, before the inherited styles.
Pseudo elements now show in Chrome Inspector (as of Chrome 31). See the pseudo element in Chrome's built in inspector. You also can edit the css properties as you'd expect.
Scenario
I have a CSS selector that is supposed to display sub-content when a label is clicked. The selector is along the lines of input:checked + element + element giving that final element a display of block (default is none). The problem is that it works in all the major browsers with the exception of webkit. Chrome, Safari, and a mobile browser for android (v2.2 sorry, I'm behind the times) all fail to display the element. When I inspect the element in Chrome, it shows that it is supposed to be display: block but it doesn't render it. I can unchec and check the property in developer tools and it displays, but not before.
I assume that this is a bug in webkit.
Question
Here is the multipart question: Is this a known bug in webkit? Am I doing anything wrong with my selectors? And how can I work around the issue for webkit browsers (any creative suggestions)?
Code
HTML
<input id="c1" type="checkbox">
<label for="c1">Ein</label>
<section>Content</section>
<input id="c2" type="checkbox">
<label for="c2">Zwei</label>
<section>Content</section>
<input id="c3" type="checkbox">
<label for="c3">Drei</label>
<section>Content</section>
CSS
input {
float:left;
clear:left;
visibility: hidden;
position:absolute;
}
label {
color:green;
display:block;
cursor:pointer;
}
section {
display:none;
}
label:after {
content:" +";
}
input:checked + label:after {
content:" -";
}
input:checked + label + section {
display:block;
}
Demo
Demo: http://jsbin.com/epibin/2
Source: http://jsbin.com/epibin/2/edit
Chain A Pseudo-Class
This demonstrates that this code fixes the bug (note that nth-child(n) matches any element, but the adding of it into the chain causes it to work):
input:checked + label:nth-child(n) + section {
display:block;
}
#ScottS provides a solid solution. Another possible one that worked for me and makes more sense from an outsiders "why the heck did they do that" point of view:
input:checked ~ section {
display:block;
}
which selects every 'section' that come after and are siblings of 'input:checked'.
There are two conditions I can think of where #ScottS's version is superior because the element in the position of 'label' gets selected as well in my solution:
(1) 'input's sibling #1 & #2 are the same elements (instead of 'label' & 'section')
(2) you are trying to be general by using the '*' selector.
sounds like a match to Bug 45168 – CSS multiple adjacent sibling selector sequence is ignored if prefixed with a pseudo-class selector
if you swap the <label> and <input> structure in the markup (and adjust the CSS accordingly) it works.
http://jsbin.com/epibin/10/edit
(but now the + - don't toggle)
EDIT:
putting the <label> and <section> in a div container works: http://jsbin.com/epibin/12/edit
As mdmullinax states, this is an outstanding bug in chrome.
This hack worked for me from the link in the accepted answer:
body { -webkit-animation: bugfix infinite 1s; }
#-webkit-keyframes bugfix { from { padding: 0; } to { padding: 0; } }
I have some HTML that a 3rd party API builds, so I have no control of the output. The only thing I can change is the CSS. I would prefer not to use JavaScript, if possible.
What I'm trying to do is swap 2 elements using float:left on the second, so it's displayed before the first one. This works well on modern browsers, but causes the "swapped" element to move to the second line on older IE browsers (specifically 6 and 7, and IE in compatibility mode).
jsFiddle Example
HTML (cannot change)
<div class="wrapper">
<a class="page">Page: </a>
<a class="previous">Prev</a>
<span>
<a>1</a>
<a>2</a>
</span>
<a class="next">Next</a>
</div>
CSS
.wrapper{
line-height:36px;
}
.wrapper span, .page{
float:left;
}
.wrapper span a, .page{
display:inline-block;
}
.wrapper span a{
width:20px;
}
.previous, .next{
width:30px;
display:inline-block;
}
Modern Browser Screenshot
Internet Explorer Screenshot
The issue turned out to be a bug with how IE6 and IE7 (not present in IE8) handle float:right; within a left-aligned element. Instead of simply positioning the element on the closest point to the left, past any content (as modern browsers do), IE6 and IE7 position the element in the farthest right point possible (which, isn't that much different in terms of definition, but makes a huge difference in cases like this).
Anyway, to get past this limitation, float:right; could not be used as a solution. As there was no way of knowing (without JavaScript, which the OP stated should not be used) what the width of .content span was (variable number of pages), a static width could not be used on .wrapper. Instead, the "Next" and "Prev" link elements had to be "discarded" until the end, then positioned absolutely (relative to .wrapper) after the width of .wrapper had been figured out.
jsFiddle Example
The Magical CSS
.wrapper {
float:left; /* Can be 'display:inline;' instead, but this makes it possible to treat this as "block" */
clear:left; /* Can be discarded if 'float:left;' isn't used */
position:relative; /* Keeps 'next'/'prev' contained */
}
.page, span {
float:left; /* Positions 'Page:' and page numbers on left */
}
.page, span a {
padding-right:.5em; /* Can change this to whatever */
}
.previous {
position:absolute;
right:-6em; /* Width (including padding, borders, etc) of .previous and .next */
width:2.5em;
padding-right:.5em;
}
.next {
position:absolute;
right:-3em; /* Width (including padding, borders, etc) of .next */
width:2.5em;
padding-right:.5em;
}
Which version of IE is the 'older IE version', specifically? If it's IE6, bfrohs is right that inline-block could be messing you up. I messed around with your fiddle, and came up with this:
http://jsfiddle.net/chippper/5rzVQ/15/
CSS:
.wrapper{
line-height:36px;
}
.wrapper span, .page{
float:left;
display: inline;
}
.wrapper span a{
width:20px;
float:left;
display: block;
}
.previous, .next{
width:30px;
}
Which seems to achieve the effect you're after. I haven't checked in IE, but it doesn't use inline-block, so there is a better chance that it will work.
The problem you have is the display:inline-block;.
IE6/7 has a known issue with this display type, in that it doesn't work if the element's default display type is block (ie as it is in your case, since you're applying it to a <div> element).
The work-around for this is to use display:inline; instead. This work-around takes advantage of the fact that IE6/7 also have bugs with the inline display type, which mean that it can be used in place of inline-block in some cases.
Obviously you don't want it to take the inline style for other browsers, so you'll need to use a CSS hack, conditional comments, or some other way of applying the style differently specific for IE6/7.
Hope that helps.
Using tag names as CSS selectors won't work properly in older versions of IE. Using an id or class name as css selectors , should work for you.