Preamble: This is a somewhat 'academic' question. I'm looking for an explanation and intelligent conjecture, not a practical solution (there is no real problem to "solve").
So, I notice that if I make a :hover selector set its display property to none, it has no discernible effect in Chrome (v23). In fact, no other properties in the selector are applied. It's as if the entire selector is ignored.
e.g.
<div class="myElement">Hover over this. Nothing happens!</div>
...
.myElement:hover {
display:none;
color:red;
}
(Check out the jsFiddle of this)
Obviously, since an element with display:none cannot be hovered, the element is instantly no longer becomes selected by the :hover selector, so loses the display:none property (and becomes eligible for selection again).
The paradoxical nature of this rule leads me to wonder why (for example) the display property doesn't toggle rapidly (every frame, or mouse move) as it does in other browsers (ie9, firefox). Although I think I prefer Chrome's implementation, I wonder why the other properties (e.g. color:red) aren't applied.
The question: is there some official documented reason why Chrome chooses to bail on this silly selector, or is this some kind of bug?
The question: is there some official documented reason why Chrome chooses to bail on this silly selector, or is this some kind of bug?
After looking at the render events that occur when you hover the link, it looks like Chrome actually renders this change in display (I originally thought Chrome was ignoring it for performance reasons). In 1.65s, it captured 11360 events recalculating style and layout because of this change in display.
So why don't you see a flicker? Chrome is rendering the change at such a fast rate you won't see the change (or the browser just doesn't render it). When you switch to visibility: hidden, you see that flickr because the item is still in the render tree, just hidden (plus, it's slower, a lot less render events are firing).
I wonder why the other properties (e.g. color:red) aren't applied.
It's cascading, so the display: none is applied, then the red color. The same reason why you never see the hover state is the same reason why you don't see the color change.
Hope that helps!
I think display:none and hover at same time is causing the confusion to the browser. It works with visibility:hidden though.
display:block;
visibility:hidden;
color:red;
you can check it here: http://jsfiddle.net/MnZyx/2/
Related
I'm trying to style an input[type="button"] and it seems that when I click on the label IE (9 in my case; I don't care for lower versions) doesn't apply the :active style. Everything works beautifully on Chrome and Firefox and also in IE if I click outside of the label. I had no luck in finding any clues to what might be the problem.
A <button> doesn't have this problem, so I guess there's something special about the other button's label, but what? And is there any workaround?
The problem is demonstrated at http://jsfiddle.net/Kmved/1/
Interesting find there. To answer the first question, "why?": unfortunately, the CSS spec leaves the semantics of :active entirely up to the browser vendor:
CSS does not define which elements may be in the above states, or how
the states are entered and left. Scripting may change whether elements
react to user events or not, and different devices and UAs may have
different ways of pointing to, or activating elements.
Now I would consider this a bug in IE (and expect it to be fixed in IE10 perhaps), but the letter of the law says that this is perfectly acceptable and tough luck to you.
To answer the second question (workaround?): well, you said it yourself. Use a <button> instead; as a bonus you get the option of placing any type of content inside the button in addition to simple text.
Here's my site. This is the last problem of a series of cross-browser discrepancies I've experienced and solved thanks to the community.
Basically, in Internet Explorer 8 and Internet Explorer 9 the :active styles are not applied to the menu. It should turn darker when pressed. Please let me know why and how to fix. Thanks in advance.
The :active pseudo-class applies while
an element is being activated by the
user. For example, between the times
the user presses the mouse button and
releases it. See W3 documentation.
But you are applying your :active selector to your <li> element, which cannot have an active state since it never really gets activated - only hovered. You should apply :active state to <a> <- True for IE 6.
UPDATE: Here's a test sample at jsFiddle as you can see it works ok on <a> element but not ok on <li>
Interesting info I found here
The :active pseudo-class applies while
a link is being selected by the user.
CSS1 was a little ambiguous on this
behavior: "An 'active' link is one
that is currently being selected (e.g.
by a mouse button press) by the
reader." Also, in CSS1, :active was
mutually exclusive from :link and
:visited. (And there was no :hover
pseudo-class.)
CSS2 changed things so that rules for
:active can apply at the same time as
:visited or :link. And the behavior
was explained a little better: "The
:active pseudo-class applies while an
element is being activated by the
user. For example, between the times
the user presses the mouse button and
releases it."
IMO, FF et al comply with CSS2 better
than IE. But since a link is supposed
to load a new page, IE could
legitimately say the link is still
"active" while the new page is
loading, which is what happens.
You can see a similar
counter-intuitive behavior in FF by
clicking the link, but moving your
mouse off of the link while holding
the mouse-button down. The link is not
activated (a new page is not loaded),
but the link remains in the :active
state. On the other hand, Chrome and
Opera de-activate the link, but at
different times; Chrome as soon as the
mouse leaves the link area, Opera not
till the mouse button is released. IE
behaves the same as FF in this
example. (Hit enter after dragging
your mouse off the link, and you will
see more differences in behavior.)
I would not call any of these
differences "bugs", because of
ambiguities in the spec.
The only work-around I can offer is to
accept that you can't control every
aspect of browser behavior. Users of
different browsers have differing
expectations of behavior, and if you
start messing with user expectation,
you're on the wrong path.
Just for the sake of relevancy and to save anyone else the hassle of searching for a solution, I also found a "bug" in IE <= 10, where you cannot apply styles to an :active child, e.g;
a:active img {
position:absolute;
top:-30px;
}
The above won't change the position of the image in IE <= 10, in which case you would need to apply :active on the child element itself;
a:active img,
a img:active {
position:absolute;
top:-30px;
}
Which in most cases isn't a perfect solution as any text inside the anchor needs to have a higher z-index value than the image, meaning that the image will only change it's position based on clicking the image itself (giving the image the :active state)... which left me in a minor bind, but a bind none-the-less (for a css only solution).
So although this is not a fix, it is more of a note of "warning" for others about the downfall to the :active pseudo selector in IE. Rubbish. =(
In Google Chrome, the CSS hover state isn't being triggered when the left mouse button is held down, as shown here:
a:hover {
color: red;
}
words
http://jsfiddle.net/RHGG6/1/
This issue doesn't occur in either FF8 or IE9. It's problematic because I'm implementing a drag-and-drop action and using CSS to highlight the drop target. I could do this pretty trivially in JavaScript, but that seems heavy-handed for what is essentially a CSS problem. Are there any workarounds to this?
From a little playing around, it seems that Chrome 30.0.1599.69 m on windows7 doesn't generate a mouseenter event if the left button is held when moving over an element. As such, relying on the onmouseenter event gives the same result as using css - perhaps this (non-triggered) event is used to signal the css engine that something needs to change.
Anyhow, you can just add code to handle mousemove and mouseout events. I simply set the text colour with the js, though something that toggled a class would probably be a better option. At least the js will be using the time that the css should have been using, so it won't all be overhead, although it does suck redoing it all anytime the mouse moves.
Perhaps you could use removeEventListener from inside the handler you're trying to remove. If so, you could attach the js to handle the events with addEventListener, attaching to both events on page load. When the onmousemove event was triggered, you could change the style and then remove the handler. Then, when the mouseout event fired, you could restore the style and re-attach the onmove handler. I wouldn't be surprised if trying to remove a handler from an event, from within the handler itself would fail, but one can only try. It would only add a few bytes to the js, but would improve efficiency (in terms of the link, not the whole page) tremendously - from potentially very poor if the mouse was moved over the link a lot to 100% - i.e the style is set exactly once and cleared exactly once per enter/leave cycle.
words
Works for me - Note: only tested with chrome in win7.
I checked in Safari and Opera as well and they behave just like IE9 and Firefox. It seems Chrome is the only browser that behaves this way. The only way I was able to get the desired behavior was using Javascript. The suggestions with the :active pseudo class definitely don't work, I think they misunderstand the problem. Strangely, :hover in Chrome works when the right mouse button is being held down and not when the left button is. Go figure.
The link turns red when I mouseover it using Chrome 17.0.948.0 (Developer Build 111321) Ubuntu 10.04, so you might want to update your Chrome.
On a related note, the :hover pseudo-class applies to an element being HOVERED by a mouse pointer. For a style to apply while the mouse button is held down while clicking the link, use the :active pseudo-class. I'm not sure why FF and IE behave differently.
When you're left mouse button is down, isn't the element supposed to be in the active state? The difference here is that Firefox and IE are allowing the active state to be inherited from the hover state, and Chrome is not. In CSS, the active state can be controlled using the :active pseudo-class. You need to explicitly set the style for the active state to ensure consistency between browsers.
Nowadays (2018), while the bug still persists in Chrome, you can work around it using HTML5 drag&drop's dragenter and dragleave events. If you have a nested dom-element you can apply a counter to mitigate the dragleave events that occur when the mouse gets over a child element.
var h1 = document.querySelector('h1')
var counter = 0
h1.ondragenter = _=> ++counter && h1.classList.add('dragover')
h1.ondragleave = _=> --counter || h1.classList.remove('dragover')
span { font-style:italic }
h1:hover { color:red }
h1.dragover { color:blue }
<h1>hover over me<span>, and me</span></h1>
<h2 draggable=true>drag me</h2>
You're looking for the :active pseudo-class. :hover will only activate when the node is being hovered over by the mouse. :active will only trigger when the node has been selected or clicked on.
Here's the jsFiddle: http://jsfiddle.net/RHGG6/21/
A live example can be seen here.
A red square (showing) is directly above a green square (hidden as overflow). Click on the square, and both colored squares are instantly made fully transparent. Additionally, the height of the red square is set to 0; this fires a transition, but the transition goes unseen because the red square is now transparent.
Before clicking the square again, examine the toggle function. Looking at the JavaScript, I would expect the height of the red square to be reset to its original value without firing a transition. The transition should be suppressed, because the transition property is temporarily set to none while the height is changed.
Now click on the square again. Both colored squares are instantly made fully opaque, but the red square slides down as its height transitions from 0 to the original value. It's as though the height set by the inline style wasn't removed by the toggle function until the element was visible, and by then the transition property had also been reset.
Triggering a reflow seems to force the change in height to be applied. (Uncomment the line containing offsetParent to test.) This behavior occurs across browsers (at least Chrome and Safari, Firefox, and Opera), so I'm wondering if it isn't part of some spec. I've checked the CSS Transitions Module without success. Any ideas why this behavior occurs, and why it's so consistent across implementations?
This really is a bizarre problem. I don't think you're doing anything wrong in your code—the current browser implementations are just buggy.
I've run into these kind of seemingly-obvious bugs before with CSS transitions, and they're a huge pain to deal with without resorting to byzantine hacks that are sure to break once the bug they're working around is fixed (in this case, my WebKit fix).
I really dug into this, but couldn't come up with a clean solution that worked in the three main transitions-supporting layout engines (WebKit, Gecko, and Presto). That said, here's what I did figure out—hopefully someone smarter than me (or just coming at this with fresh eyes) can take this answer and turn it into true solution.
Gecko and Presto (but not WebKit!)
It looks like (and I am not a browser engineer or familiar with the spec) that any current or previous value of a transition-property will continue to be rendered regardless of whether or not it needs to be. So even though you've changed the value of transition-property, the browser is still rendering the height transition in the background, and when you change the height back, you get the trailing end of that.
There is a solution though: create the transition in JavaScript (don't put it anywhere in the style sheet), remove it (after which there are no transition rules applied to #upper anywhere in the DOM), change the height, and then re-add it. Not perfect, but not a bug-reliant hack either.
http://jsfiddle.net/grantheaslip/e3quW/
JavaScript
upper.style.removeProperty('transition');
upper.style.removeProperty('-o-transition');
upper.style.removeProperty('-moz-transition');
upper.style.removeProperty('-webkit-transition');
upper.style.removeProperty('height');
// force a reflow
// if (upper.offsetParent) { /* empty */ }
upper.style['transition'] = 'height 1000ms';
upper.style['-o-transition'] = 'height 1000ms';
upper.style['-moz-transition'] = 'height 1000ms';
upper.style['-webkit-transition'] = 'height 1000ms';
Style sheet
#upper {
background-color: red;
}
WebKit (but not Gecko or Presto!)
Anything that only works because of a 1ms timeout probably should never go anywhere near production, but I think this is worth pointing out in case it helps someone get to the bottom of this problem.
My guess is that WebKit doesn't have the same issue as Presto or Gecko, but instead includes an optimization that gathers style changes applied in the same function and applies them all at once. Again, pure speculation from someone who's never gone near the WebKit source or CSS3 spec.
http://jsfiddle.net/grantheaslip/DFcg9/
JavaScript
window.setTimeout(function() {
upper.style.removeProperty('transition-property');
upper.style.removeProperty('-o-transition-property');
upper.style.removeProperty('-moz-transition-property');
upper.style.removeProperty('-webkit-transition-property');
upper.style.removeProperty('opacity');
lower.style.removeProperty('opacity');
}, 1);
Gecko, Presto, and WebKit
Here's both solutions combined. Again, because of the timeout hack, this really shouldn't be used.
http://jsfiddle.net/grantheaslip/N3NrB/
is there any reason why Internet Explorer (IE7 in my case) gets sluggish and eats up lots of CPU time when using the CSS :hover command or using onmouseover/onmouseout?
I'm really not doing anything complex, nor is my page particularly large.
When I move my mouse anywhere else on the page (where nothing is changing) iexplore.exe stays at 0%, but once I start moving across any element that has onmouseover/onmouseout or a CSS hover class attached to it, things get really slow and sluggish and CPU usage gets high.
The page works perfectly fine in Firefox, Chrome and Safari with not speed issues/sluggishness whatsoever.
Hints/Ideas?
Edit: The onmouseover/onmouseout is on <tr> tags (highlighting a row in a grid); the CSS:hover is used on <a> tags swapping a background-image url.
You need a non-flicker CSS rollover (which doesn't trigger continual 'hover' signals with every tiny mouse movement). Swapping images on hover generally doesn't work too well, especially in IE.
The best way to do this without a Javascript library is to have the desired 'hover' image as a background to the element beneath the one you're hovering over, and the non-hover image as a background to the element in front.
Then for the CSS :hover state of the element in front, set background-image: none; background-color: transparent; so that the desired 'hover' image in the underlying element is revealed.
Check the source code for this example non-flicker CSS rollover.
Depending on your markup, you may need to adjust the z-index value to get the top element 'in front' of the underlying one.
not doing anything complex
Well, what are you doing? I've seen this just from changing the background tr color. IE doesn't seem to be good at this.