12

We were adapting a method posted here highlight a DOM element on mouse over, like inspect does to NOT use jQuery.

We came up with this solution so far: http://jsfiddle.net/pentium10/Q7ZQV/3/

This seams to work on Chrome and Firefox, but doesn't work as expected on IE.

  1. On IE9 for example the highlight doesn't occur on minor elements like the tag line eg: javascript, html, dom or the top line like: chat, meta, faq

    When I mouse over the javascript tag the big div is highligthed and this is wrong and it should be like we see in Firefox

  2. On IE8 and 7 it doesn't start, so that is another problem we need to fix

Community
  • 1
  • 1
Pentium10
  • 204,586
  • 122
  • 423
  • 502
  • See: http://www.quirksmode.org/js/events_order.html – Diodeus - James MacFarlane Jun 15 '12 at 15:20
  • In IE9, the highlight does occur on the JavaScript tag. Start at the left side, and move to the right, in the direction of the tags. Then, the tags are highlighted. It seems that the overlay is prevents the "hover event" from being propagated in IE9 and 10. – Rob W Jun 17 '12 at 09:01

5 Answers5

12

I think I found the problem in your implementation. But before we get to that, you might want to cure yourself of the global-scope-leak you present in line 45. There is a semicolon, where you probably want a comma:

var target = e.target,
    offset = findPos(target),
    width = target.offsetWidth;//target.outerWidth(),
    height = target.offsetHeight;//target.outerHeight();

You might also be interested in knowing Array#indexOf is supported since IE9 so ~no.indexOf(e.target) would fail in IE8 and below.

Now to your problem. Current Browsers (including Firefox) know pointer-events:none. Even IE10's support is still unknown. Any browser not supporting pointer-events will never fire the mouseenter event on elements that are covered by your overlay.

With IE7+ supporting document.elementFromPoint() you could bind to mousemove, hide the layer, detect the element below the cursor, fire the mouseover if necessary. If you go down this road, please consider throttling your mousemove events (see limit.js).

Something like this.

Update:

I haven't done any performance comparison of document.elementFromPoint() vs pointer-events:none. Current browsers (Firefox, Chrome, …) can deal with both, Internet Explorer can only work with the document.elementFromPoint() approach. To keep things simple I did not implement the alternate pointer-events:none route for modern browsers.

rodneyrehm
  • 13,442
  • 1
  • 40
  • 56
  • It turns out the client wants this to work on mobile/tablets also. Just for opinion, is there a way we could track somehow the finger move on tablets? – Pentium10 Jun 19 '12 at 17:24
  • Your client is aware of the fact that with touch screen devices *you cannot hover over things*, right? So you'll have to hook into a "tap" (I'd still call it a click, but, well…). Look into [pointer.js](https://github.com/borismus/pointer.js) for a library that even helps with gestures – rodneyrehm Jun 19 '12 at 17:51
  • a quick thought on performance: `document.elementFromPoint()` is (a lot) slower then using `pointer-events:none;`. In addition to this, there are some cross browser issues, pointed out [here](http://help.dottoro.com/ljctoqhf.php), guess which browser is being obtuse? – Elias Van Ootegem Jun 20 '12 at 11:59
  • I've tested http://jsfiddle.net/jefferyto/Q7ZQV/7/show/ with IE9, Firefox and Safari in various zoom levels. The elementFromPoint() approach works fine – rodneyrehm Jun 20 '12 at 15:12
9

It turns out that in IE, elements that have no background (i.e. background: transparent) and the Gradient filter set do not receive mouse events. Demo

This is a happy coincidence, since you're using a RGBa background colour for your overlay and one of the workarounds for RGBa colours in IE is the Gradient filter.

By setting these styles on the overlay (for IE):

background: transparent;
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#7F000000,endColorstr=#7F000000)"; /* IE8 */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#7F000000,endColorstr=#7F000000);   /* IE6 & 7 */
zoom: 1;

mouse events pass through the overlay and onto the underlying elements, so inner / minor elements are highlighted correctly.

Other issues that are present in IE7/8:

  • When using element.attachEvent, the event name needs to be prefixed with "on":

    document.body.attachEvent('onmouseover', function(e) { ... })
    
  • To find the target of the event, you need to access event.srcElement instead of event.target.

  • As rodneyrehm mentioned, Array.indexOf isn't supported.

So here's a version of your solution that also works in IE 7-9: http://jsfiddle.net/jefferyto/Q7ZQV/7/

(BTW The highlighting is wrong for inline elements that span more than one line, e.g. the "ask your own question" link in the "Browse other questions..." line.)

Jeffery To
  • 11,836
  • 1
  • 27
  • 42
2

Using a special routine for Internet Explorer (tested in IE9, not tested in IE8), I have come up with this. However, it is not perfect, yet. When moving the mouse inside the same element, flickering occurs as the routine is run multiple times (and sometimes the overlay disappears completely). I hope to perfect this soon.

Routine:

  • I specifically checked if the browser was IE and performed the following actions:
  • I assigned the mousemove event to a function that uses document.elementFromPoint(x, y).
  • I assigned mouseover to a clearing function, that removes the overlay immediately. (This causes the flickering and a possible complete overlay removal, even though the mouse is still on the element.)

Element From Point Function

function ep(e)
{
    var ev = {target:document.elementFromPoint(e.clientX, e.clientY)};
    handler(ev);
}

Clearing Function

function clear(e)
{
   cur = null;
   overlay.style.display='none';
}

Feedback and suggestions are welcome. I am still working on this, and I will post updated JSFiddle links.

Evan Mulawski
  • 54,662
  • 15
  • 117
  • 144
  • You can use spoon.net to test in different browsers. IE8 gives this: http://screencast.com/t/RFWr9VrT `Message: 'clientX' is null or not an object Line: 59 Char: 5` – Pentium10 Jun 17 '12 at 15:33
  • According to http://msdn.microsoft.com/en-us/library/ie/ms533567(v=vs.85).aspx, it is supported in IE4 and above. – Evan Mulawski Jun 17 '12 at 15:35
1

You could avoid the mouse events being intercepted by the overlay by changing its properties, namely by making it transparent and relying on outline or, with size calculation adjustments, border:

background:transparent;
outline:1px dotted red;

Fiddle'd

Alternatively, you could not rely on an overlay but instead toggle a class on the element itself whenever "moused over". If you cache the reference to it, you could then remove the class when "moused out", rinse, repeat. I'll fiddle with the idea for a little bit more to see how viable it is.

Oleg
  • 24,465
  • 8
  • 61
  • 91
  • If you altered the background of an element, wouldn't any `background:inherit` of contained elements adjust accordingly? this could look confusing… – rodneyrehm Jun 18 '12 at 09:19
  • @rodneyrehm: initial value for color is `transparent` - and there are few scenarios where `inherit` would be a preferable choice. – Oleg Jun 18 '12 at 10:04
  • I'm aware of that, I'm just pointing out that there *are* situations where this approach might break. I like the `background:transparent` idea on the overlay, though. I'm not sure if performs better than `display:none`. Currently no idea how to benchmark that reliably :/ – rodneyrehm Jun 18 '12 at 10:48
0

I had a quick look at your fiddle, and forked a version that works on IE8, to be found here. As it turns out, indexOf, especially in combination with the bitwise ~ is something IE doesn't seem to be all that fond of, so the quickest fix seems to be a simple for(i=0;i<no.length;i++){}.

As pointed out before, e.target won't work in IE, as JScript calls this property srcElement. This makes sense, since IE events always bubble up to the document, so all events have a source, rather then a target.

The biggest difference is to be found in your CSS: again IE is a pain: MS believes that rgba is no good for some reason. It seems they prefer writing CSS's that no human on earth can make sense of:

filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0.3,startColorstr='#4c333333', endColorstr='#4c666666');

gives you a semi-transparent grey overlay. To be honest, I found this piece of my answer here.

When it comes to the pointer events, the only way round this, AFAIK, is another event listener, that handles the onclick event:

function noClick(e)
{
    e = e || window.event;
    if (e.preventDefault)
    {
        e.preventDefault();
        e.stopPropagation();
        return false;
    }
    e.returnValue = false;
    e.cancelBubble = true;
    return false;
}

Hope this helps you on your way...

Community
  • 1
  • 1
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149