Blog

38 posts 2009 16 posts 2010 50 posts 2011 28 posts 2012 15 posts 2013 7 posts 2014 10 posts 2015 5 posts 2016 4 posts 2017 7 posts 2018 2 posts 2019 17 posts 2020 7 posts 2021 7 posts 2022 11 posts 2023 7 posts 2024 4 posts 2025

“Appearances can be deceiving Mr. Anderson” - a.k.a. short code is not always fast code

2 min read 0 comments Report broken page

I used to take pride in my short, bulletproof and elegant String and Number type checks:

// Check whether obj is a Number
obj + 0 === obj

// Check whether obj is a String obj + ‘’ === obj

I always thought that apart from being short and elegant, they should be faster.

However, some quick tests gave me a cold slap in the face and proved my assertion to be entirely false. When comparing the following 4 methods for string and number type checking:

  1. “My” method (mentioned above)
  2. Object.prototype.toString method: Object.prototype.toString.call(obj) === '[object String]' or Object.prototype.toString.call(obj) === '[object Number]'
  3. Typeof method: typeof obj === 'string' or typeof obj === 'number'
  4. Contructor method: obj.constructor === String or obj.constructor === Number

It turned out that the Object.prototype.toString method was 50% faster than my method, and both typeof and constructor methods were a whopping 150% faster than my method! No wonder jQuery uses the typeof method for their String/Number tests.

Now that I think about it, it does actually make sense - my method converts obj to a String or Number, then concatenates/adds it with another String/Number, then compares value and type. Too much stuff done there to be fast. But I guess I was too innocent and subconsciously thought that it wouldn’t be fair if elegant and short code wasn’t fast too.

Of course the overall time needed for any of these tests was neglible, but it’s a good example of how much appearances can be deceiving - even in programming! ;)

The moral: Never assume. Always test.

So, which method is ideal for String/Number checks? (added afterwards)

The typeof method and my method fail for non-primitive String/Number objects, as you can easily observe if you type in the console:

typeof new String('foo') // 'object'
typeof new Number(5) // 'object'
new String('foo') + '' === new String('foo') // false

This can easily be solved if you also check the type via instanceof (the decrease in speed is negligible):

foo = new String('foo');
typeof foo === 'string' || foo instanceof String
foo + '' === foo || foo instanceof String

Don’t use instanceof alone, since it fails for String and Number primitives. The instanceof method also fails for Strings and Numbers created in another window, since their constructor there is different. Same happens with the Constructor method mentioned above.

It seems that if you need a bulletproof check the only method you can use is the Object.prototype.toString method and luckily, it’s one of the fastest (not the fastest one though), so I guess we can safely elect it as the ideal method for String and Number checks (and not only for arrays, as it was first made popular for).

PS: For anyone wondering what the quote in the title reminds him/her, its from the Matrix Revolutions movie.


Quick & dirty way to run snippets of JavaScript anywhere

1 min read 0 comments Report broken page

Ever wanted to run a snippet of JavaScript on a browser that doesn’t support a console in order to debug something? (for instance, IE6, Opera etc)

You probably know about Firebug Lite, but this either requires you to already have the bookmarklet, or include the script in the page. Although Firebug Lite is a great tool for more in depth debugging, it can be tedious for simple tasks (eg. “What’s the value of that property?”).

Fortunately, there is a simpler way. Do you remember the 2000 era and the javascript: URIs? Did you know that they also work from the address bar of any javascript-capable browser?

For instance, to find out the value of the global variable foo, you just type in the address bar javascript:alert(foo). You can write any code you wish after the javascript: part, as long as you write it properly to fit in one line.

Of course these URIs are a no-no for websites, but they can be handy for simple debugging in browsers that don’t support a console. ;)


20 things you should know when not using a JS library

5 min read 0 comments Report broken page

You might just dislike JavaScript libraries and the trend around them, or the project you’re currently working on might be too small for a JavaScript library. In both cases, I understand, and after all, who am I to judge you? I don’t use a library myself either (at least not one that you could’ve heard about  ;) ), even though I admire the ingenuity and code quality of some.

However, when you take such a brave decision, it’s up to you to take care of those problems that JavaScript libraries carefully hide from your way. A JavaScript library’s purpose isn’t only to provide shortcuts to tedious tasks and allow you to easily add cool animations and Ajax functionality as many people (even library users) seem to think. Of course these are things that they are bound to offer if they want to succeed, but not the only ones. JavaScript libraries also have to workaround browser differences and bugs and this is the toughest part, since they have to constantly keep up with browser releases and their respective bugs and judge which ones are common enough to deserve workaround and which ones are so rare that would bloat the library without being worth it. Sometimes I think that nowadays, how good of a JavaScript developer you are doesn’t really depend on how well you know the language, but rather on how many browser bugs you’ve heard/read/know/found out. :P

The purpose of this post is to let you know about the browser bugs and incompatibilities that you are most likely to face when deciding againist the use of a JavaScript library. Knowledge is power, and only if you know about them beforehand you can workaround them without spending countless debugging hours wondering “WHAT THE…”. And even if you do use a JavaScript library, you will learn to appreciate the hard work that has been put in it even more.

Some of the things mentioned below might seem elementary to many of you. However, I wanted this article to be fairly complete and contain as many common problems as possible, without making assumptions about the knowledge of my readers (as someone said, “assumption is the mother of all fuck-ups” :P ). After all, it does no harm if you read something that you already know, but it does if you remain ignorant about something you ought to know. I hope that even the most experienced among you, will find at least one thing they didn’t know very well or had misunderstood (unless I’m honoured to have library authors reading this blog, which in that case, you probably know all the facts mentioned below :P ) . If you think that something is missing from the list, feel free to suggest it in the comments, but have in mind that I conciously omitted many things because I didn’t consider them common enough.

DOM

  1. getElementById('foo') also returns elements with name="foo" in IE and older versions of Opera.
  2. getElementsByTagName('*') returns no elements in IE5.5 and also returns comment nodes in all versions of IE (In case you’re wondering: DOCTYPE declaration will count, Conditional comments will not).
  3. getElementsByClassName() in Opera (even Opera 10 Alpha) doesn’t match elements with 2 or more classes when the one you’re looking for is not the first but it’s also a substring of the first. Read the discussion between me and John Resig on the latter’s blog post mentioned below if this seems a bit unclear.
  4. There is no element.children collection in Firefox 3-. You have to create it yourself by filtering the childNodes collection if it doesn’t exist.
  5. If your code involves preformatted elements (for instance if you are making a syntax highlighter), beware when setting the innerHTML of those: IE won’t preserve line breaks (\r\n s) and whitespace. You have to use outerHTML, which will actually replace the element so you should find a way to obtain a reference to the newly created one in case you still need to perform stuff on it.
  6. To get the dimensions of the viewport, standard compliant browsers use window.innerWidth (and innerHeight) whereas IE uses document.documentElement.clientWidth (and clientHeight).
  7. To get the scroll offsets of the current page, standard compliant browsers use window.pageXOffset (and pageYOffset) whereas IE uses document.documentElement.scrollTop (and scrollLeft).
  8. To make matters worse, in both cases above, you need to use document.body instead of document.documentElement when in Quirks mode.

John Resig (of the jQuery fame), recently posted a great presentation, which summarized some browser bugs related to DOM functions. A few of the bugs/inconsistencies mentioned above are derived from that presentation.

Events

  1. When using IE’s attachEvent() the this reference inside the callback refers to the useless window object
  2. eventObject.target is eventObject.srcElement in IE
  3. eventObject.stopPropagation() is eventObject.cancelBubble = true; in IE
  4. eventObject.preventDefault() is eventObject.returnValue = false; in IE
  5. There are many more event object incompatibilities for specific events (the ones above are for all events). Take a trip to QuirksMode for more information.
  6. IE leaks horribly (especially IE6) in various cases.
  7. If you register the same event handler X times, IE fires it X times.
  8. Determining when the DOM is ready is a complete mess. Firefox and Opera 9+ support the DOMContentLoaded event, Safari doesn’t but you can check it’s document.readyState property and in IE document.readyState is unreliable and you should either inject a deferred script, either poll the DOM untill there are no errors or use an external behavior file. Of course you could always just put a script tag at the bottom of the page, just before the body closing tag, which will fire all attached handlers which is actually the best approach in terms of which way fires earliest (but not too early) according to my tests, but that hardly qualifies as unobtrusive…
  9. (edit, thanks Sobral!) The Event object is not passed as a parameter to the callback but resides in window.event in older versions of IE

Type detection

  1. The typeof operator is almost useless:

    • typeof null == 'object'
    • typeof new String('foo') == 'object'
    • typeof [] == 'object'

    Use Object.prototype.toString instead.

CSS

  1. Although most CSS properties are converted to their JavaScript equivalents in a standard way (characters after dashes are Uppercase, others are lowercase, the dashes get removed), float is an exception: It’s converted to cssFloat in most browsers and styleFloat in IE. Check which one exists and use that.
  2. Getting the current (computed) style of an element is another complete mess. IE uses element.currentStyle[propertyJS] whereas standard compliant browsers use document.defaultView.getComputedStyle(element, null).getPropertyValue(propertyCSS). And as if this wasn’t enough, there are various problems associated with specific properties or browsers, like:
    • IE returns the cascaded values and not the computed ones (for instance, it might return ems for a property that was specified in ems, and not pixels). Dean Edwards has thought a very clever hack to workaround this and didn’t even blog about it (it’s simply a comment in a blog post of Erik Arvidsson’s!).
    • Any hidden (via display:none;) element, yields a width/height/top/right/bottom/left value of zero.
    • auto or normal might be returned for properties that are left at their defaults. For instance, IE does this with width/height for elements that don’t have dimensions explicitly set via CSS.
    • In most browsers, shorthands (like border) will yield a blank string. You’d have to use the most specific property (for instance, border-left-width).
    • Colors will be returned in different formats across browsers. For instance, IE uses #RRGGBB whereas Mozilla uses rgb(red, green, blue).

So, what now?

Never, EVER use a browser detect to solve the problems mentioned above. They can all be solved with feature/object detection, simple one-time tests or defensive coding. I have done it myself (and so did most libraries nowadays I think) so I know it’s possible. I will not post all of these solutions to avoid bloating this post even more. You can ask me about particular ones in the comments, or read the uncompressed source code of any library that advertises itself as “not using browser detects”. JavaScript Libraries are a much more interesting read than literature anyway. :P

Are the facts mentioned above actually 20?

I’m not really sure to be honest, it depends on how you count them. I thought that if I put a nice round number in the title, it would be more catchy :P


Silent, automatic updates are the way to go

2 min read 0 comments Report broken page

Recently, PPK stated that he hates Google Chrome’s automatic updates. I disagree. In fact, I think that all browser vendors should enforce automatic updates as violently as Google Chrome does. There should be no option to disable them. For anybody.

But what about the user’s freedom of choice?

This might sound a bit facist at start, but imagine a world where all browsers would get automatically updated, without the possiblity of an opt-out. If you went online, you would be bound to have the very latest version, regardless of how computer (i)literate you were (Many — if not most — home users that don’t upgrade are like that because they think it’s too difficult for their computer expertise level). Sure, if you were a developer you wouldn’t be able to test a website in older browser versions. But why would you need to do so? If everybody had the latest browser version, you would only develop for the latest version and perhaps for the next one (via nightlies and betas, that could still be separate in that ideal world).

Imagine a world where your job wouldn’t have to involve tedious IE6 (and in a few weeks, no IE7 either), Firefox 2, Opera 9.5 and Safari 3.1- testing. A world where you would spend your work hours on more creative stuff, where you wouldn’t want to bang your head on the wall because you know you did nothing wrong but the ancient browser that you are currently testing in is just incompetent and YOU have to fix it’s sh*t. A world where the size of your Javascript code (and the JS libraries’ code) would be half its size and constantly decreasing as new browser versions come out. A world where you would only have 1 CSS file in most websites you develop. A world where you wouldn’t feel so bad because IE8 doesn’t support opacity, border-radius or SVG, because you would know that in 1-2 years everyone would have IE9 and it will probably support them. A world where designing a website would be as much fun as designing your personal blog.

Doesn’t such a world sound like a dream? Would it harm anyone? Users would browse a much lighter and beautiful web, with a more feature-rich and secure browser. Developers would work half as much to produce better results and they would enjoy their work more.

What about corporate intranets and abandoned sites that won’t keep up?

Oh come on, that isn’t a good enough reason to not make that dream come true! Companies and individuals could be allowed to have an older version of the browser installed as well. They still wouldn’t be able to opt out from the automatic upgrade, but they could apply somehow to have an older version of the browser in the same system as well. Similarly to what happens now with browser betas. People would use the older version to access corporate intranet applications and obsolete sites and the latest version to surf the web. I may be overly optimistic, but I think that if a user had both versions of a browser installed, (s)he would prefer the latest wherever (s)he can. Perhaps another step towards enforcing that would be if the OS prevented an older browser version from being set as the default browser, but I guess that would be too hard to do, especially if the browser in question is not the OS default one.

Other people who agree with me

What’s your opinion?


Bulletproof, cross-browser RGBA backgrounds, today

4 min read 0 comments Report broken page

UPDATE: New version

First of all, happy Valentine’s day for yersterday. :) This is the second part of my “Using CSS3 today” series. This article discusses current RGBA browser support and ways to use RGBA backgrounds in non-supporting browsers. Bonus gift: A PHP script of mine that creates fallback 1-pixel images on the fly that allow you to easily utilize RGBA backgrounds in any browser that can support png transparency. In addition, the images created are forced to be cached by the client and they are saved on the server’s hard drive for higher performance.

Browsers that currently support RGBA

These are:

  • Firefox 3+
  • Safari 2+
  • Opera 10 (still in beta)
  • Google Chrome

In these browsers you can write CSS declarations like:

background: rgba(255,200,35,0.5) url(somebackground.png) repeat-x 0 50%; border: 1px solid rgba(0,0,0,0.3); color: rgba(255,255,255,0.8);

And they will work flawlessly.

Internet Explorer

Surprisingly, it seems that Internet Explorer supported RGBA backgrounds long before the others. Of course, with it’s very own properietary syntax, as usual:

filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#550000FF, endColorstr=#550000FF);

And since nothing is ever simple with IE, IE8 requires a special syntax which has to be put before the first one to work properly in IE8 beta1:

-ms-filter: “progid:DXImageTransform.Microsoft.gradient(startColorstr=#550000FF, endColorstr=#550000FF)”;

The code above actually draws a gradient from rgba(0,0,255,0.33) to rgba(0,0,255,0.33) using a Microsoft-proprietary “extended” hex format that places the Alpha parameter first (instead of last) and in the range of 00-FF (instead of 0-1). The rest is a usual hex color, in that case #0000FF.

Caution: The “gradients” that are created via the gradient filter are placed on top of any backgrounds currently in effect. So, if you want to have a background image as well, the result may not be what you expected. If you provide a solid color as a background, it will also not work as expected (no alpha transparency), since the gradients created are not exactly backgrounds, they are just layers on top of backgrounds.

Problems with the filter method

  • Filters are bad for client-side performance.
  • Filters cause the text rendering to be aliased and especially when it’s bold and there is no background-color set it becomes completely unreadable. (the worst disadvantage if you ask me)
  • Filters only work with IE. What about Firefox 2- and Opera 9.6-?
  • Filters are lengthy (especially now that you have to include 2 different syntaxes) so they significantly increase the size of your CSS when used frequently.
  • You have to convert the red, green and blue values to hex to use that method.
  • To use a filter, the element has to have Layout. This is usually done via zoom:1. More non-standard clutter in your CSS.
  • Doesn’t play along well with other workarounds, since it doesn’t modify the background of the element.

So, personally, I only use that approach sparingly, in particular, only when “no/minimum external files” is a big requirement.

A bulletproof solution

My favored approach is to use rgba() for all RGBA-capable browsers and fallback pngs for the ones that don’t support RGBA. However, creating the pngs in Photoshop, or a similar program and then uploading them is too much of a fuss for me to bare (I get bored easily :P ). So, I created a small PHP script that:

  • Creates a 1-pixel png image with the parameters passed for red, green, blue and alpha. No need to convert to hex.
  • Supports named colors, to speed up typing even more for colors that you use commonly in a site (it includes white and black by default, but you may easily add as many as you like).
  • Stores the generated images on the server, so that they don’t have to be created every time (generating images on the fly has quite an important performance impact).
  • Forces the images to be cached on the browser so that they don’t have to be generated every time (even though their size is very small, about 73 bytes).

Here it is: rgba.php

You use it like this:

background: url(rgba.php?r=255&g=100&b=0&a=50) repeat; background: rgba(255,100,0,0.5);

or, for named colors:

background: url(rgba.php?name=white&a=50) repeat; background: rgba(255,255,255,0.5);

Browsers that are RGBA-aware will follow the second background declaration and will not even try to fetch the png. Browsers that are RGBA-incapable will ignore the second declaration, since they don’t understand it, and stick with the first one. Don’t change the order of the declarations: The png one goes first, the rgba() one goes second. If you put the png one second, it will always be applied, even if the browser does support rgba.

Before you use it, open it with an editor to specify the directory you want it to use to store the created pngs (the default is 'colors/') and add any color names you want to be able to easily address (the defaults are white and black). If the directory you specify does not exist or isn’t writeable you’ll get an error.

Caution: You have to enter the alpha value in a scale of 0 to 100, and not from 0 to 1 as in the CSS. This is because you have to urlencode dots to transfer them via a URI and it would complicate things for anyone who used this.

Edit: It seems that IE8 sometimes doesn’t cache the image produced. I should investigate this further.

IMPORTANT: If your PHP version is below 5.1.2 perform this change in the PHP file or it won’t work.

Why not data:// URIs?

Of course, you could combine the IE gradient filter, rgba() and data:// URIs for a cross-browser solution that does not depend on external files. However, this approach has some disadvantages:

  • All the disadvantages of filters mentioned above.
  • You can’t be spontaneous in your CSS and changes are difficult. Every time you want to use RGBA, you have to resort to some converter to create the png and it’s data:// URI. Unless you are some kind of a cyborg with an embedded base64 encoder/decoder in your head :P
  • Larger filesize (you have to use 4-5 declarations (the rgba() one, the data:// one, 2 filters, one for IE7- and one for IE8 and a zoom:1; to give the element “layout” so that filters can be applied) instead of 2, and the data:// URI has the same size as the png). Also, the data:// URI can not be cached so every time you use it, you increase the filesize even more.  Ok, you save an http request per use, but is it worth it?

and some advantages:

  • You will not see the site without a background for even a single millisecond. Since the png is embedded in the CSS, it’s loaded as soon as the CSS itself is loaded. If your site background is too dark and you rely on the RGBA background to make the content legible, you might want to consider this solution.
  • No external files, no extra http requests.
  • The filter method works in IE6- without the script for transparent PNGs.

Choose the method that fits your needs better. :)

RGBA is not only for backgrounds!

It’s also for every CSS property that accepts color values. However, backgrounds in most cases are the easiest to workaround. As for borders, if you want solid ones, you can simulate them sometimes by wrapping a padded container with an RGBA background around your actual one and giving it as much padding as your desired border-width. For text color, sometimes you can fake that with opacity. However, these “solutions” are definitely incomplete, so you’d probably have to wait for full RGBA support and provide solid color fallbacks for those (unless someone comes up with an ingenious solution in <canvas>, it’s common these days :P ).


CSS3 border-radius, today

4 min read 0 comments Report broken page

This is the first one from a series of articles I’m going to write about using CSS3 properties or values today. I’ll cover everything I have found out while using them, including various browser quirks and bugs I know of or have personally filed regarding them. In this part I’ll discuss ways to create rounded corners without images and if possible without JavaScript in the most cross-browser fashion.

I will not cover irregular curves in this article, since I’ve yet to find any person who actually needed them, even once, including myself and browser support for them is far worse.

Caution: The contents of a container with border-radius set are NOT clipped according to the border radius in any implementation/workaround mentioned below, and no, setting overflow to hidden won’t help (and even if it did, you’d risk text missing). You should specify a proper border-radius and/or padding to them if you want them to  follow their container’s curves properly. This could allow for some nice effects but most of the time it’s just a pain in the a$$.

Mozilla Firefox

Firefox supports rounded corners since version 2. However incomplete support in version 2 made designers sceptical to use them. The problem was that the rounded corners created were aliased back then, and also did not crop the background image, so if you had one, no rounded corners for you. This was fixed in FF3, so now more and more designers are starting to use them. The syntax is

-moz-border-radius: [Number][unit];

This is effectively a shorthand for:

-moz-border-radius-bottomleft: [Number][unit];
-moz-border-radius-bottomright: [Number][unit];
-moz-border-radius-topleft: [Number][unit];
-moz-border-radius-topright: [Number][unit];

You don’t need to specify all these properties though, even if you wan’t different measures per corner, as -moz-border-radius functions as a regular CSS shorthand, allowing us to specify all 4 corners at once. It can be used in the following ways:

-moz-border-radius: [Top-left and Bottom-right] [Top-right and bottom-left];
-moz-border-radius: [Top-left] [Top-right and bottom-left] [Bottom-right];
-moz-border-radius: [Top-left] [Top-right] [Bottom-right] [Bottom-left];

A good mnemonic rule for the order of the values is that they are arranged clockwise, starting from Top left.

Apple Safari

Safari also implements CSS3 border-radius, but in a quite different way. If you want to set all four corners to the same border-radius, the process is almost identical. The only thing needed is:

-webkit-border-radius: [Number][unit]

However, things start to get tricky when you want to specify different radiuses per corner. Webkit does not support a shorthand syntax, since it chose to implement the spec closely, sacrifycing clarity but allowing for more flexibility. To cut a long story short, Webkit supports irregular curves instead of just circle quarters on each corner, so if you try to add 2 values, the result will be  horrendous.

So, you have to specify all four properties (or less if you want some of them to be square). To make matters even worse, the way the names of the properties are structured is different. There is one more dash, and the position of the corner styled by each property is not at the end but before -radius:

-webkit-border-top-left-radius
-webkit-border-top-right-radius
-webkit-border-bottom-left-radius
-webkit-border-bottom-right-radius

Caution: If the dimensions of your element are not enough to accomodate the rounded corners, they will be square in Webkit-based browsers. Specify a min-width/min-height or enough padding to avoid this.

Google Chrome

Since Google Chrome is based on Webkit, its border-radius support is like Safari’s. However, it’s haunted by an ugly bug: It renders the rounded corners aliased. :(

Opera

The bad news is that Opera does not implement the CSS3 border-radius yet (it will in the future, confirmed). The good news is that it allows for SVG backgrounds since version 9.5. The even better news is that it supports data:// URIs, so you can embed the SVG in your CSS, without resorting to external files as someone recently pointed out to me. Alexis Deveria was clever enough to even create a generator for them, so that you could easily specify the background, border width and border-color and get the data URI instantly. This is a quite useful tool, but lacks some features (for instance you might want the background to be semi-transparent, like the one used in this blog). It’s ok for most cases though.

While Opera’s current lack of border-radius support is disappointing, you can utilize it pretty well with this method and if you know SVG well enough yourself you can create stunning effects.

Internet Explorer (aka “The Web designer’s nemesis”)

There’s no need to tell you that IE doesn’t support border-radius or SVG backgrounds, even in it’s latest version, right? You probably guessed already. There is some hope here though, a clever guy named Drew Diller carefully researched the MS-proprietary VML language and came up with a script that utilizes it to create rounded corners in IE. The bad news is that MS when releasing IE8 fixed some things and messed up others, so the script barely works on it. It also has some other shortcomings, but for most cases it can be a great tool (for IE7 and below, unless MS surprises us and fixes the VML regressions in IE8 before the stable). Also, if rounded corners are not crucial to your design and you don’t get too much traffic from IE users, you might consider ignoring IE altogether and having square corners in it. This way you’re also serving the greater good, since when IE users see your site in a supporting browser, they’ll conclude that “Oh, this browser shows the web nicer!” and the site will still be just as usable (in most cases rounded corners are not that crucial for usability, although they enchance it a bit).

Afterword

I hope this article helped you learn something new. If you found any mistakes or inaccuracies, don’t hesitate to leave a comment, I don’t know everything and I’m not god. :)

One thing I have in mind is creating a PHP script that takes care of all these incompatibilities for you and caches the result. I don’t know if I’ll ever find the time to write it though, especially before someone else does :P


Find the vendor prefix of the current browser

3 min read 0 comments Report broken page

As you probably know already, when browsers implement an experimental or proprietary CSS property, they prefix it with their “vendor prefix”, so that 1) it doesn’t collide with other properties and 2) you can choose whether to use it or not in that particular browser, since it’s support might be wrong or incomplete.

When writing CSS you probably just include all properties and rest in peace, since browsers ignore properties they don’t know. However, when changing a style via javascript it’s quite a waste to do that.

Instead of iterating over all possible vendor prefixes every time to test if a prefixed version of a specific property is supported, we can create a function that returns the current browser’s prefix and caches the result, so that no redundant iterations are performed afterwards. How can we create such a function though?

Things to consider

  1. The way CSS properties are converted their JS counterparts: Every character after a dash is capitalized, and all others are lowercase. The only exception is the new -ms- prefixed properties: Microsoft did it again and made their JS counterparts start with a lowercase m!
  2. Vendor prefixes always start with a dash and end with a dash
  3. Normal CSS properties never start with a dash

Algorithm

  1. Iterate over all supported properties and find one that starts with a known prefix.
  2. Return the prefix.
  3. If no property that starts with a known prefix was found, return the empty string.

JavaScript code

function getVendorPrefix()
{
	var regex = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/;

var someScript = document.getElementsByTagName(‘script’)[0];

for(var prop in someScript.style) { if(regex.test(prop)) { // test is faster than match, so it’s better to perform // that on the lot and match only when necessary return prop.match(regex)[0]; }

}

// Nothing found so far? return ‘’; }

Caution: Don’t try to use someScript.style.hasOwnProperty(prop). It’s missing on purpose, since if these properties aren’t set on the particular element, hasOwnProperty will return false and the property will not be checked.

Browser bugs

In a perfect world we would be done by now. However, if you try running it in Webkit based browsers, you will notice that the empty string is returned. This is because for some reason, Webkit does not enumerate over empty CSS properties. To solve this, we’d have to check for the support of a property that exists in all webkit-based browsers. This property should be one of the oldest -webkit-something properties that were implemented in the browser, so that our function returns correct results for as old browser versions as possible. -webkit-opacity seems like a good candidate but I’d appreciate any better or more well-documented picks. We’d also have to test -khtml-opacity as it seems that Safari had the -khtml- prefix before the -webkit- prefix. So the updated code would be:

function getVendorPrefix()
{
	var regex = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/;

var someScript = document.getElementsByTagName(‘script’)[0];

for(var prop in someScript.style) { if(regex.test(prop)) { // test is faster than match, so it’s better to perform // that on the lot and match only when necessary return prop.match(regex)[0]; }

}

// Nothing found so far? Webkit does not enumerate over the CSS properties of the style object. // However (prop in style) returns the correct value, so we’ll have to test for // the precence of a specific property if(‘WebkitOpacity’ in someScript.style) return ‘Webkit’; if(‘KhtmlOpacity’ in someScript.style) return ‘Khtml’;

return ‘’; }

By the way, if Webkit ever fixes that bug, the result will be returned straight from the loop, since we have added the Webkit prefix in the regexp as well.

Performance improvements

There is no need for all this code to run every time the function is called. The vendor prefix does not change, especially during the session :P Consequently, we can cache the result after the first time, and return the cached value afterwards:

function getVendorPrefix()
{
	if('result' in arguments.callee) return arguments.callee.result;

var regex = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/;

var someScript = document.getElementsByTagName(‘script’)[0];

for(var prop in someScript.style) { if(regex.test(prop)) { // test is faster than match, so it’s better to perform // that on the lot and match only when necessary return arguments.callee.result = prop.match(regex)[0]; }

}

// Nothing found so far? Webkit does not enumerate over the CSS properties of the style object. // However (prop in style) returns the correct value, so we’ll have to test for // the precence of a specific property if(‘WebkitOpacity’ in someScript.style) return arguments.callee.result = ‘Webkit’; if(‘KhtmlOpacity’ in someScript.style) return arguments.callee.result = ‘Khtml’;

return arguments.callee.result = ‘’; }

Afterthoughts

  • Please don’t use this as a browser detection function! Apart from the fact that browser detects are a bad way to code 99.9% of the time, it’s also unreliable for IE, since Microsoft added a vendor prefix in IE8 only. Before that it followed the classic attitude “We have a large market share so standards and conventions don’t apply to us”.
  • There are some browsers that support multiple prefixes. If that is crucial for you, you may want to return an array with all prefixes instead of a string. It shouldn’t be difficult to alter the code above to do that. I’ll only inform you that from my tests, Opera also has Apple, Xn and Wap prefixes and Safari and Chrome also have Khtml.
  • I wish there was a list somewhere with ALL vendor prefixes… If you know such a page, please leave a comment.

Extend Math.round, Math.ceil and Math.floor to allow for precision

2 min read 0 comments Report broken page

Math.round, Math.ceil and Math.floor are very useful functions. However, when using them, I find myself many times needing to specify a precision level. You don’t always want to round to an integer, you often just want to strip away some of the decimals.

We probably all know that if we have a function to round to integers, we can round to X decimals by doing Math.round(num*Math.pow(10,X)) / Math.pow(10,X). This kind of duck typing can get tedious, so usually, you roll your own function to do that. However, why not just add that extra functionality to the functions that already exist and you’re accustomed to?

Let’s start with Math.round. It’s the most needed one anyway.

Firstly we’ll have to store the native function somewhere, since we’re going to replace it. So we do something along the lines of:

Math._round = Math.round;

Now let’s sigh replace the native Math.round with our own:

Math.round = function(number, precision)
{
	precision = Math.abs(parseInt(precision)) || 0;
	var coefficient = Math.pow(10, precision);
	return Math._round(number*coefficient)/coefficient;
}

And guess what? It still works the old way too, so your old scripts won’t break.

So now, let’s go to Math.ceil and Math.floor. If you notice, the only thing that changes is the function name. Everything else is the same. So, even though we could copy-paste the code above and change the names, we would end up with triple the size of the code that we need and we would have also violated the DRY principle. So we could put the names of the functions in an array, and loop over it instead:

(function(){
	var MathFns = ['round', 'floor', 'ceil' ];
	for(var i = MathFns.length; i>-1; i--)
	{
		Math['_' + MathFns[i]] = Math[MathFns[i]];
		Math[MathFns[i]] = function(number, precision)
		{
			precision = Math.abs(parseInt(precision)) || 0;
			var coefficient = Math.pow(10, precision);
			return Math['_' + MathFns[i]](number*coefficient)/coefficient;
		}
   }
})();

Why the closure? To allow us to be free in defining our variables without polluting the global namespace. In case Array.prototype.forEach() was cross-browser or if you have mutated the Array prototype to add it for non-supporting ones, you could easily do that:

['round', 'floor', 'ceil' ].forEach(function(funcName){
	Math['_' + funcName] = Math[funcName];
	Math[funcName] = function(number, precision)
	{
		precision = Math.abs(parseInt(precision)) || 0;
		var coefficient = Math.pow(10, precision);
		return Math['_' + funcName](number*coefficient)/coefficient;
	}
});

No closures and much easier to read code.

However, nothing comes without a cost. In this case, the cost is performance. In my tests, the new function takes about twice the time of the native one. Adding a conditional to check if the precision is falsy and use the native function directly if so, doesn’t improve the results much, and it would slow the function down for precision values > 0. Of course the speed would be just as much if the function was a normal one and not a replacement for Math[something], that doesn’t have anything to do with it.


JS library detector

1 min read 0 comments Report broken page

Ever wondered which JavaScript library (if any) is hidden beneath the bells & whistles of each site you gazed at? Since I am a curious person, I find myself wondering every time, so after a bit of research, I wrapped up a little bookmarklet that instantly told me the answer every time.

The logic behind it is that every JavaScript library creates at least one global variable with an easily recognizable name. For most JavaScript libraries, this is simply their name (Prototype, jQuery, DOMAssistant, MooTools, dojo). For some others, its something close enough to their name (YAHOO for YUI, Scriptaculous for script.aculo.us, Ext for ExtJS). So if you check the precence of this global variable, you are effectively checking for the precence of the related framework. Most of them also contain a property with their version (which is usually named ‘version’ or ‘Version’ or ‘VERSION’ (in YUI)) - in fact the only library that did not contain such a property was DOMAssistant. So, after a sneak peek at their code, I could easily set up some conditionals that check whether a certain library exists in the page and if so, alert its name and version. If multiple libraries exist at the same page, multiple popups will appear.

So, here is the bookmarklet:

JS library detector

Just drag it to your bookmarks toolbar and it’s ready.

And here is the human-readable code:

if('Prototype' in window)
{
	var ret = 'Prototype ' + Prototype.Version;
	if('Scriptaculous' in window) ret += ' with script.aculo.us ' + Scriptaculous.Version;
	alert(ret);
}
if('jQuery' in window) alert('jQuery ' + jQuery.fn.jquery);
if('MooTools' in window) alert('MooTools ' + MooTools.version);
if('YAHOO' in window) alert('YUI ' + YAHOO.VERSION);
if('dojo' in window) alert('Dojo ' + dojo.version);
if('Ext' in window) alert('ExtJS ' + Ext.version);
if('DOMAssistant' in window) alert('DOMAssistant');

Am I nuts? Certainly. Has it been useful to me? Absolutely.


Check whether a CSS property is supported

1 min read 0 comments Report broken page

Sometimes when using JavaScript, you need to determine whether a certain CSS property is supported by the current browser or not. For instance when setting opacity for an element, you need to find out whether the property that the browser supports is opacity, -moz-opacity (MozOpacity), -khtml-opacity (KhtmlOpacity) or the IE proprietary filter.

Instead of performing a forwards incompatible browser detect, you can easily check which property is supported with a simple conditional. The only thing you’ll need is a DOM element that exists for sure. A DOM element that exists in every page and is also easily accessible via JS (no need for getElementsByTagName), is the body element, but you could use the <head> or even a <script> tag (since there is a script running in the page, a <script> tag surely exists). In this article we’ll use document.body, but it’s advised that you use the head or script elements, since document.body may not exist at the time your script is run.

So, now that we have an element to test at, the test required is:

if('opacity' in document.body.style)
{
	// do stuff
}

Of course you’d change document.body with a reference to the element you’d like to test at (in case it’s not the body tag)  and 'opacity' with the name of the actual property you want to test. You can even wrap up a function to use when you want to check about the support of a certain property:

function isPropertySupported(property)
{
	return property in document.body.style;
}

The only thing you should pay attention to, is using the JavaScript version of the CSS property (for example backgroundColor instead of background-color)

Wasn’t it easy?