Monthly Archives: August 2011

Facebook Icon in CSS Using a Single Div

I was inspired by the idea that you can make a wide range of shapes using only CSS on a single div after reading this css-trics.com page. I created the Facebook Icon using a single div:



#f {
width: 100px;
height: 80px;
background-color: #3B5998;
border-bottom: 20px solid #6d84b4;
position: relative;
}
#f:before {
position: absolute;
top: 15px;
right: 15px;
border: 15px solid #fff;
border-bottom: none;
border-right: none;
border-top-left-radius: 15px;
width: 15px;
height: 65px;
content: "";
}
#f:after {
position: absolute;
top: 44px;
left: 43px;
height: 15px;
width: 42px;
background-color: #fff;
content: "";
}

It works in Firefox 5, Chrome 13, and Safari 5.1. It works in IE8, but the “f” is not rounded. See the JS Fiddle version.

Browser Rendering – Getting Computed Style is Hard

Recently I was looking into how libraries like jQuery get the compute style of an element. I found that in its simplest form, getting computed style is one step:

function getStyle(el, prop) {
return el.currentStyle ?
el.currentStyle[prop] : // IE
document.defaultView.getComputedStyle(el, "")[prop];
}

IE stores computed properties on the element’s `currentStyle` and the other browsers use the method `document.defaultView.getComputedStyle`. But there are two things that make a robust implementation difficult: (1) shorthand properties don’t work and (2) each browser returns different values. What I mean by shorthand properties are things like border which is made up of border-top-width, border-top-style, border-top-color, border-right-width, border-right-style, border-right-color, etc. Calling `getStyle(el, ‘border’)` returns undefined; you have to call ‘borderTopWidth’, ‘borderTopStyle’, and ‘borderTopColor’ and the other 9 properties for the other 3 sides. This is understandable but may not be intuitive when the css declares the border shorthand property.

And then each browser returns different things. Here are some observations of Firefox 5, Webkit (Chrome 13 and Safari 5.1), and IE8 based on my handful of tests on Windows 7.

  • If given units in em, Webkit and Firefox convert to px, but IE8 will leave as em. So an implementation that computes the width of a 30em-wide element, for example, will have to convert em to px for IE8. Note also that Firefox will return fractions of px for any property.
  • When given a color by name or by hex notation, Webkit and Firefox both convert to rgb while IE8 will keep the given value. So a robust implementation must be able to convert “yellow” to “rbg(255,255,0)”, for example.
  • When using the default font, Firefox returns “serif”, Webkit returns “‘Times New Roman'” with the apostrophes and IE8 returns “Times New Roman” without quotes.
  • Firefox calculated a font size of 0.9em to be 14.4px, Webkit 14px, and IE8 keeps 0.9em. jQuery returns 14px in all cases with its `css` method.
  • All browsers normalize a mixed-case values like `DOTted` to the lowercase `dotted`.

One rendering difference too with a thick dotted border. IE8 renders the dots as circles and spaces them evenly so that there will be no partial circles. Firefox also renders dots as circles but keeps them a fixed distance apart so that the corners usually have artifacts. Webkit renders the dots as squares and, like firefox, overlaps dots in the corners. IE8 renders the background color behind the border and the other browsers do not.

The following CSS renders like the picture below with Firefox 5 on the left, Chrome 13 in the center and IE8 on the right.

#subject {
width: 16em;
height: 17.75em;
border: 1em DOTted #ddd;
background-color: YELlow;
font-size: 0.9em;
line-height: 135%;
}

Browser Comparisons

Also see my JsFiddle version if you want to play around and maybe try other properties. It also shows the results of jQuery’s `css` method.

Caution For JavaScript Global Variables

Recently on Twitter Thomas Aylott (@SubtleGradient) recommended using `location` instead of `window.location`. I disagree. Yes, `location` is a global variable, but the problem is that it can be easily overwritten. A careless dev might use a global variable `location`. The same goes for `window.top`, `window.parent`, `window.self`, and `window.history`. Basically I say use `window.` for anything that could be a common variable name.

Fork a Process in PHP

The other day I ran into a need to “fork” a process in a web app. Basically I needed to trigger a long-running process but immediately show the user a screen that said “running”. I used a version of the following.


function forkExec($command) {
if(stripos(PHP_OS, 'win') !== false) {
$command = "start /b $command";
}
else {
$command .= ' > /dev/null &';
}
return pclose(popen($command, 'r'));
}

In windows `start /b` starts the given command in the background. On Linux, `> /dev/null` supresses output and `&` runs the given command in the background.

You Are Using SPDY and Don’t Even Know It

igvita.com explains what SPDY is, how it works and where it is used. As you may remember, Google proposed an add-on to HTTP that was faster because of multiplexing, server pushing and better compression including compression of headers and the use of a pre-defined dictionary.

I heard about SPDY when Google announced it in 2009 but hadn’t heard much since. For all I knew it was something that never took off like Google Go. But it turns out that Google has been serving pages in SPDY to Chrome for several months now. As you use Chrome you may notice that unlike other browsers chrome does not display “http://” at the beginning of the location bar. Part of the reason is because Gmail, Google Docs and other Google services are actually running on “spdy://”. So you don’t even know it: you are using SPDY.

There is a ticket filed for Firefox but it doesn’t look like SPDY will be implemented anytime soon. I couldn’t find anything about plans for SPDY for Safari or Internet Explorer.

UPDATE (2 April 2012): Firefox 11 implements SPDY as an option (search for “spdy” on about:config), and according to this Mazillazine thread, Firefox 13 will enable SPDY by default. That thread also mentions an add-on that shows an icon when a site is using SPDY (Search for “spdy” on addons.mozilla.org).

Extending Host Objects: Evil; Extending Native Objects: Not Evil But Risky

Kangax has a good article on extending JavaScript native objects and host objects. He begins by clarifying that extending host objects (e.g. Element) is truly evil. Host objects do not have strong specs and have no rules and extending them risks collisions. Kangax has an older post talking about extending objects. There he says that Prototype JS’s biggest mistake was extending Element. I find that particularly interesting since Kangax was an influential voice in the Prototype JS community.

I completely agree; problems with Element was one of the top reasons I stopped using Prototype JS. When Chrome 1.0 came out, for example, it was apparent that extending Element was far from future proof, because, for one, Chrome 1.0 sometimes created elements that didn’t inherit from Element.

So back to my first point: the difference between native objects and host objects. Extending native objects such as Array is not necessarily evil. Shimming methods on native objects is OK if you carefully follow spec. But that means adding your own methods to Array.prototype is bad. Prototype JS’s Array.prototype.map function is a great example: it was created before the spec for Array.prototype.map was created. Now that Array.prototype.map has been implemented in most browsers, Prototype JS is overriding the proper version with its own version. That is damaging.

But yes, shims are OK. Technically. It is OK to define JSON or Array.prototype.indexOf for browsers that lack them as long as you follow spec. Just remember that following spec is hard. It is so hard in fact, that you probably shouldn’t use shims.

It’s best in principal and practice to avoid extending objects you don’t own. In the special case of using shims, extending native objects is OK as long as you use well-researched, well-tested shims. In practice it’s very hard to find good implementations, so it is safest to avoid extending object natives altogether.

I recommend just staying away from altering prototypes of all objects you don’t own and leave it at that.