Auto margin is normally used to center an element horizontally. Basically, set margin to auto will cause margin-left and margin-right to be set by browser so that the element is centered horizontally in its containing block. An exception is that margin-left can not be less than 0 in this automatic setting, thus margin-left will not go negative if the width of the element is larger than the width of the containing block.
Auto margin can also be used to center element vertically. This is much rarer though. This happens when the element is absolutely positioned and when top and bottom are set. If that is the case, then the element will be centered both horizontally and vertically in its positioning parent. The difference is that margin-top can be negative but margin-left can not. In other words, when its positioning parent is narrower than itself in width, then it won't be centered horizontally, just as the discussion in previous paragraph. However, when its positioning parent is shorter than itself in height, it will still be centered vertically, by having a negative margin-top. This is useful when you want to have a image background that is always centered even if the view port size is small, as used in the second CSS trick in this article. Notice that the trick in the article has the flaw that when the window is very narrow in width, the background will no longer be centered due to non-negative margin-left discussed above, while it is still fine for the vertical centering no matter how short the window is.
Monday, March 10, 2014
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.
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.
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.
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.
Wednesday, January 29, 2014
Random JavaScript Tips (1)
After learning JavaScript for 2 days, there are quite a bit of difference between it and Java. One big difference that I am stilling getting used to is the omission of block scope.
In JavaScript, all variable declaration are hoisted to the top of enclosing function or the global script, where as in Java the best practice is to declare variables in the nearest enclosing block. According the creator of JavaScript, Brendon, this design choice is due to short of time when they developed it: a relevant question on StackOverflow.
A more important fact is the implementation of a full Closure in JavaScript. The closure a nested function, together with the reference to local variables of all its outer functions. This is very similar to how Java handle nested classes, where inner class can access the instance variables and methods of (the instance of) it outer class. However, Java don't have a function level closure. For example, the anonymous inner class or local class can only access local variables of enclosing method that are declared final. So this is not real closure.
In JavaScript, all variable declaration are hoisted to the top of enclosing function or the global script, where as in Java the best practice is to declare variables in the nearest enclosing block. According the creator of JavaScript, Brendon, this design choice is due to short of time when they developed it: a relevant question on StackOverflow.
A more important fact is the implementation of a full Closure in JavaScript. The closure a nested function, together with the reference to local variables of all its outer functions. This is very similar to how Java handle nested classes, where inner class can access the instance variables and methods of (the instance of) it outer class. However, Java don't have a function level closure. For example, the anonymous inner class or local class can only access local variables of enclosing method that are declared final. So this is not real closure.
Thursday, December 12, 2013
Leetcode OJ: Recover Binary Search Tree
Recover Binary Search Tree
Recover the tree without changing its structure.
An O(n) space algorithm is straight-forward. One can write the in-order traversal of the BST to a linear array, then find the two swapped elements and swap them back.
A better solution is to not explicitly write the in-order traversal to an array. In fact, we can just do an in-order traversal on the BST itself and find the swapped elements in the process. Notice that if we exchange two adjacent (in terms of in-order) nodes, then the logic to find swapped elements is a little different, but this is handled subtly in the code.
However, since the previous solution uses recursion, then the worst case space complexity is the depth of the tree, which could be as bad as O(n).
A tree O(1) space solution requires the used of Threaded Binary Tree, which I learned from other's solution. A threaded binary tree allows one to truly traverse a binary tree with constant space. In our case, we want a forward traversal, so the right child of any node who doesn't have a right child points to its in-order successor. Since we want to preserve the structure, we make that pointing on the fly and recover it after that pointing after use. A threaded binary tree solution is as follows. Notice that we need to find the in-order predecessor of each node twice. The total complexity of finding in-order predecessor of all nodes is O(n), since it's easy to see that every edge is traversed only once. So it is not too bad.
Saturday, December 7, 2013
LeetCode OJ: Wildcard Matching
Implement wildcard pattern matching with support for
'?'
and '*'
.'?' Matches any single character. '*' Matches any sequence of characters (including the empty sequence). The matching should cover the entire input string (not partial). The function prototype should be: bool isMatch(const char *s, const char *p) Some examples: isMatch("aa","a") → false isMatch("aa","aa") → true isMatch("aaa","aa") → false isMatch("aa", "*") → true isMatch("aa", "a*") → true isMatch("ab", "?*") → true isMatch("aab", "c*a*b") → false
A typical DP. However, a naive O(N^3) time, O(N^2) space solution can not path large test cases. So 3 optimizations are used.
(1) Suppose s and p are of length n and m respectively, then we want to compute a m by n boolean matrix F, where F(i, j) is true if the first i letters of the pattern matches the first j letters of the string. However, we do not need to store then entire matrix, as we can compute the matrix row by row, where the computation of any row only relies on the previous row. Only 2 rows are needed at any time and the space complexity is reduced to O(2*N)
(2) It's easy to see that the '*' is the cause of the O(N^3) complexity, so a simple optimization is to collapse all adjacent '*' into one, which will not change the language represented by the pattern.
(3) When N is very large, like tens of thousand, then even O(N^2) is too slow. We say a non '*' character in the pattern as a hard character, as it must match at least one character from the input string. If we have k hard characters among first i characters of the pattern, then we know F(i, j) must be false if j < k. In this way, we can find a lower and upper bound of j between which F(i, j) can be true for any fixed i. This optimization is especially useful when the pattern is very long, but most of characters in the pattern are hard.
An solution using the above three optimizations is as follows.
Subscribe to:
Posts (Atom)