Thursday, February 27, 2014

Ignoring Mouse Event on DOM Element Using CSS 'pointer-events' Property

Yesterday, I was trying to write my simple Javascript tooltip library that can handle customized feature such as tooltip width, orientation of appearance, and also support arbitrary div content. An example page is here.

Basically, the tooltip div element is positioned absolutely and it shall fade in and out when the trigger text's mouseenter and mouseleave events are fired.

The first difficulty is when the trigger text, say a span, span across multiple lines, such as example two. In CSS term, this span has more than one bounding boxes. This is not a problem if the trigger is a block element as a block element has exactly one bounding box. The desired effect is that the tooltip shall appear next to the bounding box that the mouse enters. This can be solved using the getClientRects method to get all the bounding rectangles of an inline element and decide which of them is entered by the mouse.

The second difficulty, which I want to record here, is as follows. Sometime, due to resizing of browser window, the tooltip will cover part of the trigger text. In extreme case, the tooltip will cover up the entire trigger. As a result, when the tooltip covers the trigger, mouseleave event will be fired on the trigger, even if the mouse is still "on" the trigger. Then the tooltip will fade out and the mouseenter will be fired again... Of course, due to browser event handle time, this will not repeat indefinitely, but it still causes an unpleasant glitch, as show in this JS fiddle. After having some discussion on StackOverflow, I finally found the solution, then "pointer-events" CSS property, which can be used to disable any pointer event on the tooltip and let the event go through to the trigger underneath it, as shown in this JS fiddle. This saved my day.

More info can be found here or here.

Sunday, February 23, 2014

Synchronize YouTube videos

Recently, I created a website to synchronize YouTube videos. The idea is that there is a master video and all other videos (called slave videos)  will be synchronized to the master one, in the sense that all playback action on the master video will be reflected on slave videos. This is useful when you want to watch a clip with friends on the other side of the Internet and want to keep your videos play synchronously, even if you pause or seek.

The master page send all playback actions to the web server for temporary storage using standard Ajax. The slave page, on the other hand, need to get these event updates from the server. This is a problem because in the HTTP paradigm, web clients are supposed to send queries to web server, not the other way around. The technology used here is called Comet, which is also called reverse Ajax. The idea of Comet is to allow server to push data to the client. There are multiple methods and framework to achieve Comet. The method I chose is called long polling. As its name suggests, the client need to poll the server continuously with high frequency to ask for update. This is normally done by send a new XMLHttpRequest at the end of the onload callback of the previous XMLHttpRequest. In my code, I add some rate limit so about 2 polling are executed per second. This seems to work but will be harder to scale as the server is being queried continuously, even if there is no event to update.

Saturday, February 1, 2014

Keep the same heights for multi-column layouts in CSS

When having a multiple column layout using float, it is sometimes important to ensure that the columns all having the same height. This is especially important when the columns have backgrounds that are different from the background of the container.

There are quite a few way ensure identical heights: .

Among those, my favorite one is the Flexbox Method by Paul Irish. The flexbox method make use of very large padding and is a pure CSS solution.

Suppose we have a div "container", whose direct children are the columns, then the flexbox only requires extra-large padding and negative margin with the same magnitude, as follows:

HTML
CSS

The mechanism is simple, since the column has a very large bottom padding, the background extends downwards almost infinitely. Then a negative margin make sure that the effective height of the column is not affected. The container will automatically cut of the extra backgrounds so nothing pokes out.