Sometimes it appears helpful to make certain page elements only visible on e.g. hovers. An example is stackoverflow's "feedback - Was this post useful to you?"-widget. As those elements might be crucial to the interface, such a show-on-hover-feature should be a progressive enhancement or, in other terms, unobtrusive and degrade gracefully.
The usual way appears to be employing javascript, e.g. hiding the elements and making them available when a parent element is hovered. The reason for that choice might be :hover is not support for all elements especially in legacy browsers, thereby forbidding you to hide elements in the first place up to css2. (for a js/jQuery example cf. jquery showing elements on hover)
I wonder if you can achieve such a feature safely* with pure css3, using :not(:hover) and :hover, not affecting older browsers. As far as I can see, the requirement is that every browser supporting :not() must support :hover for all elements. According to the following sources, that appears to be the case
http://www.quirksmode.org/css/contents.html
http://kimblim.dk/css-tests/selectors/
Example implementation: http://jsfiddle.net/LGQMJ/
What do you think? Any objections or other sources?
*by safely I mean the browser should always show all elements as a last resort.
Your solution looks alright for CSS3. There isn't anything I can think of to improve your solution for modern browsers as the opacity property will never be applied by browsers that don't support it anyway.
There is literally no other browser besides IE6 and NN4 (and older) without support for :hover on elements other than a. As implied in your question, all browsers that support :not() are known to also fully support :hover.
That said, you end up leaving IE7 and IE8 missing out on the hover effect, the latter of which is still quite prevalent. You're probably looking to support IE6 as well, but here's a solution that I believe will address these concerns, if you need it:
Omit :not(:hover) altogether so your first selector becomes less specific rather than equally specific to your second selector with :hover, and you can reach out to IE7 and IE8 which don't support :not() but do support :hover on all visual elements:
div span.question {
opacity: 0;
}
div:hover span.question {
opacity: 1;
}
Use the visibility property instead of the opacity property to reach out to IE7 and IE8 which don't support CSS3 opacity:
div span.question {
visibility: hidden;
}
div:hover span.question {
visibility: visible;
}
Keep in mind that visibility: hidden will make an element invisible to mouseovers as well, but in this case you're applying it to a child element, so the parent will remain visible to mouseovers.
Use CSS2/3 combinators that IE6 doesn't support but IE7 and IE8 do (child >, adjacent sibling +, general sibling ~) to hide both rules from IE6. This borders on "hacky", but your situation is one where the child combinator > fits very well, so it can be integrated organically rather than hacked in like the famous html > body filter:
div > span.question {
visibility: hidden;
}
div:hover > span.question {
visibility: visible;
}
Updated fiddle
Related
My question is really simple, just what i am trying to do is :hover, :after and :before , i want hover anf after to embed in same element, check out my css code:-
#sidebar .widget li a:before:hover, #sidebar .widget li a.active:before {
background-position: 65% 65.7%;
}
Here the element have an icon in :before which i cnt remove or modify, and also i want to have an hover effect on it...
Any solution for this, my console doesn't show the hovering effect?
Interesting question. If you're able to show us a working example we could probably be of more help.
However, in theory there's nothing wrong with what you're attempting to do (although not all browsers will like it: particularly IE8 and below).
The important thing to understand here is that :hover is a pseudo-class, whereas :before is a pseudo-element.
Here's a quick excerpt from the standard (with thanks to this answer previously on Stack Overflow):
Pseudo-classes are allowed anywhere in selectors while pseudo-elements
may only be appended after the last simple selector of the selector.
The mistake you're making is in your syntax: the order that you're appending them.
Try this instead:
#sidebar .widget li a:hover:before,
#sidebar .widget li a.active:before {
background-position: 65% 65.7%;
}
That should do as you wish. However this isn't going to give you great cross-browser coverage, it's not something that all browsers support of have implemented.
A better approach would be to:
reset the :before element to nothing (overwrite the styles you can't access);
use a non-repeated background image on the anchor instead (to display the image), and padding-left to give the indentation;
You can then switch the background-image in whatever fashion you see fit using :hover on the anchor in your CSS.
This will give you far better cross-browser compatibility.
HTML:
<p>Hover</p>
CSS:
p::after {
content: " here";
transition: all 1s;
}
p:hover::after {
font-size: 200%;
color: red;
}
Live demo: http://jsfiddle.net/SPHzj/13/ (works in Firefox and Chrome)
As you can see, I've set up CSS transitions on the ::after pseudo-element of the paragraph. Then, when the paragraph is hovered, two new styles apply for the pseudo-element which are transitioned.
This works in Firefox and Chrome, but not in IE10. My reasoning was that IE doesn't understand the p:hover::after selector, as it works in IE if you set the hover on an ancestor element, e.g. div:hover p::after - live demo: http://jsfiddle.net/SPHzj/14/.
However, this is not the case, as IE is indeed able to understand that selector. The trick is to define a p:hover {} rule as well. (Discovered by #maxw3st.)
p:hover {}
This rule can be empty. The mere presence of this rule will make the transitioning work in IE10.
Live demo: http://jsfiddle.net/SPHzj/15/ (also works in IE10)
What's going on here? Why does IE require that rule to be present in order for transitions to work on the pseudo-element? Should this be considered a bug?
Appears to be a Regression
This does appear to be a legitimate regression in Internet Explorer 10. As indicated on MSDN, since Internet Explorer 7 users have been able to target the hover state of any element , and not only a.
Curiously I tried the :active pseudo-class, and this appears to work as expected. Further establishing that this is a regression, you can see that by changing this to an a element, the transition takes place as expected (since historically, a and :hover go hand-in-hand).
Optional Work-Arounds
There are only a few solutions that I can think of at this point (while waiting for this to be fixed):
Use the empty p:hover {} fix.
Modify your markup to target ::after on a child of the p.
Modify the selector to use combinators.
The first item is that which you specified in your question, and is very attractive given its simplicity. In fact, you could use :hover{} and get the same results (probably the best solution).
The second item is also do-able, but a little less desirable since it requires modifying the markup, which is not always possible, and to be frank, a bit silly.
The last option is somewhat interesting. If you modify the selector to be based on sibling relationships, it magically begins to work again. For instance, suppose we have multiple elements in the body:
<h1>Hello, World</h1>
<p>This is my first paragraph. it does not animate.</p>
<p>This animates, with a pseudo-element.</p>
We can now use combinators to target the second paragraph:
p+p:hover::after {}
This selector will match any paragraph following a paragraph though, which isn't desirable. At this point we could consider :nth-child, or :nth-of-type to further specify which paragraph we want, even using the general sibling combinator:
h1~p:nth-of-type(2):hover::after {} /* Targets second <p> nearest <h1> */
But more ideally we would target with a class:
h1~.hoverme:hover::after {} /* Targets <p class="hoverme"> */
A Two-Char Solution?
One step further, maybe you don't want to be locked down explicitly providing a general sibling tag. You could also use the Universal Selector:
*~.hoverme:hover::after {} /* Targets <p class="hoverme"> among siblings */
This requires that the p tag have siblings, which is typically expected. Very rarely does a document consist of nothing more than a single paragraph tag.
I understand that these aren't ideal, but they are a means to an end for now. Let's hope to see this resolved in future releases of Internet Explorer.
Strangely, the effect will work on a <a> link rather than a paragraph tag.
It certainly appears to be an IE10 bug or regression. Fortunately, you've found a nice fix.
This same phenomenon popped up when I tried adding a rule to change the cursor to a pointer. However, cursor: pointer; has to be included in the pseudo's parent, it can't be used to target just the pseudo's content string in IE10.
http://jsfiddle.net/maxw3st/SPHzj/22/ uses a div as a container, http://jsfiddle.net/maxw3st/7sBVC/ uses the p:hover workaround. Adding the div was suggested by #simevidas, and works fine for the transition, just not the pointer. The pointer only seems to appear in IE10 when it is applied to the parent of the pseudo-element.
Is it possible to use attribute selectors to partially-search an inline style attribute?
Can anyone find a way to get this bit of code working?
http://jsfiddle.net/v4xPY/1/
It seems that it's not possible to do this .hidden[style*="display: block"] + .below, nor even just [style]
The attribute selector you're trying to use isn't legit CSS, though it is a jQuery attribute selector. As far as I know, CSS is limited to [attribute=value], [attribute~=value] and [attribute|=value]. (derp, see below)
But, since you're already using jQuery to toggle the hidden div, it'd be a lot simpler to just toggle a class on the below div at the same time, rather than wrestling with the attribute selector (unless there's more to it than that).
Modified jQuery:
$(function() {
$('html').click(function() {
$('.hidden').slideToggle();
$('.below').toggleClass('yellow');
});
});
and CSS:
/* Margin of Below should reduce when hidden is opened */
.yellow {
margin-top: 10px;
background: yellow;
}
Fiddle here.
Edit: Okay, I was way off on the bit about the attribute selectors, it is legit CSS3; I don't know the details on browser support, though I'd guess it'd be supported in all the usual "modern" browsers. Also, there's apparently a problem with IE7 targeting the style attribute specifically. There's a pretty good write-up at http://www.impressivewebs.com/attribute-selectors/.
Once more: Though I can't find anything that explicitly confirms this, it looks like the attribute selectors only apply to attributes that are actually hardcoded into the html; basically it's just parsing strings, not examining the dom elements' "states" as such?
As mentioned, an element on a canvas jumps after the canvas itself is dragged. I'm using -webkit-transform: translate(x,y) to drag the canvas around. Any ideas on what to look into for this problem?
Look for changes that cause a reflow in CSS:
visibility:hidden/visible
display:none
:hover
and JavaScript:
offsetWidth or offsetHeight
scroll event
The sad truth about CSS3 selectors is that they really shouldn’t be used at all if you care about page performance. Decorating your markup with classes and ids and matching purely on those while avoiding all uses of sibling, descendant and child selectors will actually make a page perform significantly better in all browsers.
With parent selectors it becomes extremely easy to accidentally cause a document-wide grovel. People can and will misuse this selector. Supporting it is giving people a whole lot of rope to hang themselves with.
The complete profile is appropriate for contexts which aren't extremely performance sensitive. For example, implementations of the Selectors API specification [SELECTORS-API] should use the ‘complete’ profile. It includes all of the selectors defined in this document.
CSS implementations conformant to Selectors Level 4 must use the ‘fast’ profile for CSS selection.
The fast profile is appropriate for use in any context, including dynamic browser CSS selector matching. It includes every selector defined in this document, except for:
Combinators within :matches(), :not(), :nth-match(), and :nth-last-match().
The reference combinator
The subject indicator
In particular, in the situation the browser is looking at most of the selectors it's considering don't match the element in question. So the problem becomes one of deciding that a selector doesn't match as fast as possible; if that requires a bit of extra work in the cases that do match you still win due to all the work you save in the cases that don't match.
Use browser specific selectors to target the document itself:
#-moz-document url-prefix()
{
#media all
{
.foo { color: red } /* Firefox */
}
}
*::-ms-backdrop, .foo { color: red } /* IE11 */
*:-webkit-any-link, .foo { color: red } /* Webkit */
If you want to reference a child element based on its context, use the XML serialization of HTML5 and CSS3 namespaces:
#namespace m "http://www.w3.org/1998/Math/MathML/";
m|math { border: 1px solid blue; }
If you want to display a child element based on a parent pseudo class, you can define the default state of the child element, then redefine it for each state change of the parent:
li:hover > a * { display: none; }
li:hover > a:hover * { display: block; }
References
XHTML5 + CSS Namespaces
CSS Selectors: Should You Optimize Them To Perform Better?
Performance Impact of CSS Selectors
Why do browsers match CSS selectors from right to left?
List of suggested extensions to CSS
Force Element to Self-Clear its Children
The IE8 “hover” Bug: The Most Awesome IE Bug Ever?
MDN: #document
Issues for CSS Selectors Level 4
Reflows and Repaints: CSS Performance making your JavaScript Slow
How Browsers Work
I'm wondering if it's possible to change the text of an element on selection. For example, if I had
<span class=time>12:00</span>
Would it be possible to change the content to [12:00] by using CSS :before, :after, and ::selection pseudo-elements?
.time::selection:before {
content: '[';
}
.time::selection:after {
content: ']';
}
Although my current project requires a CSS solution (and also only needs to work in Opera), I'd not be averse to JavaScript solutions if CSS seems impossible, just for future reference.
In case it is of any use, I'm attempting to change the formatting of Opera's IRC setup using im.css in order to make copy/pasted logs format more like they do from conventional IRC clients.
You cannot currently nest the ::before or ::after pseudo-elements with any other pseudo-elements (not even themselves).