fsprojects / FsReveal

FsReveal parses markdown and F# script file and generates reveal.js slides.
http://fsprojects.github.io/FsReveal
258 stars 102 forks source link

Ugly flicker when tooltip overlaps parent element #96

Closed rmunn closed 8 years ago

rmunn commented 8 years ago

Note: This is the same bug report as tpetricek/FSharp.Formatting#405, and it has the same fix. If you've already looked at that bug report, you can skip reading this one.

When FsReveal generates HTML markup with F# tooltips, the tooltips look fine if they don't overlap their parent element. But if, due to their positioning on the page or the CSS used to style them, they end up overlapping their parent element, some ugly flicker is visible as the mouse pointer moves over the parent element. Here's a visual example from the sample presentation:

bad

The mouse cursor failed to show up in this animated screen capture, but I was moving it back and forth between the name factorial and the let just to the left.

The cause of this issue is that when the tooltip element appears, it naturally lies above its parent element in z-index order and thus the browser considers it to be what the mouse cursor is currently pointing to. When the element appears, as long as the cursor hasn't moved yet, no mouseover or mouseout events will fire. But the moment the cursor moves even one pixel, the browser sees it as over a new element: it was over the parent span, and now it's over the tooltip div. So the browser fires a mouseout event on the parent span (which causes the tooltip to be hidden) and a mouseover event on the tooltip div (which does nothing). And now the tooltip is hidden, so the next time the cursor moves, a mouseout will fire on the tooltip div (doing nothing) and a mouseover will fire on the parent span (showing the tooltip again). And that cycle repeats all over again, causing the tooltip div to alternate between shown and hidden with every update of the mouse pointer. Result: highly-annoying flickering.

There are two possible solutions to this issue. One is to take advantage of the little-known pointer-events CSS property. An element with pointer-events: none will be ignored for the purpose of mouseover and mouseout events (and other mouse events as well). This is the simplest solution since it only involves adding a single line of CSS to the .tip class, and it works on modern versions of all browsers. It does not, however, work on IE versions 10 or earlier; only IE 11+ will honor pointer-events: none properly on HTML elements, according to the http://caniuse.com/#feat=pointer-events chart.

That solution produces the following result:

good

It's not quite obvious in that animated GIF, but the tooltip disappears as soon as the mouse moves off the word factorial. It would be more obvious if I had moved the mouse more slowly, but the tooltip can disappear while the mouse cursor is still over the tooltip, as long as the cursor has moved off the parent element (in that example, the span containing the word factorial).

Another possible solution would be to change the logic of the tooltips in Javascript: instead of disappearing when the mouse leaves the parent element, make the tooltip stay visible as long as the mouse is inside the parent element or inside the tooltip. In other words, the tooltip would behave like this:

also-good

Again, it may not be obvious, but here the tooltip stays visible even when the mouse cursor has left the parent span.

The drawback of this approach is that if the code in question has a lot of invocations of common functions like List.reduce or Seq.ofList, the tooltips for List and Seq will tend to be quite large -- and it's possible that someone trying to hover the mouse pointer over reduce will accidentally brush it over the name List first, and then have to move the pointer quite far away before they get off the tooltip. At which point getting back to the word reduce can become an exercise in frustration, as any module name becomes a landmine the mouse pointer has to avoid.

Therefore, I would suggest the CSS fix (adding pointer-events: none to the tooltip CSS). Its only drawback is that it won't work in IE versions before 11. But if anyone is running IE 10 or earlier, they really should upgrade anyway, so I don't find that to be a major issue. Therefore, my recommendation would be to use the CSS fix rather than the Javascript fix.

rmunn commented 8 years ago

Fixed in FsReveal 1.3.

forki commented 8 years ago

:heart: