Author Archive

“But The Client Wants IE 6 Support!�





 



 


Frequently, when I discuss CSS3 with other developers, the issue of stubborn clients comes up. They tell me that even though they personally don’t think a website should look the same in all browsers and they’re eager to try all of these new techniques, their clients insist that their website should look the same, so the developers are stuck with the same Web development techniques that we used five to ten years ago. Their clients just don’t “get� graceful degradation.

Is this really the issue? Are our clients incapable of understanding these things? Is the problem that our clients don’t “get� the Web and need to be educated? I don’t think so. We got ourselves into this. We are the ones who caused this problem for our industry. We are the ones giving ourselves this trouble and making our profession less creative and enjoyable than it could be. It’s entirely our fault and no one else’s.

Wait, What?

If we choose to make a website pixel-perfect in Internet Explorer 6 to 8, then we are doing up to 100% more work. No matter how many frameworks, polyfills and other scripts we use to ease our pain, we will always be doing at least 30% more work for those browsers. How many of us actually charge 30-100% extra for this work? I haven’t heard of many who do. Clients get this kind of extra work for free, so of course they will say that they want IE 6 support. If I was a client, maybe I’d say so, too, especially if I didn’t know how these technologies work. They won’t care about our extra time if we don’t care enough ourselves to charge for it accordingly.

Of course, faster download times and better SEO are compelling arguments, but let’s face it: one of the biggest advantages of the new CSS features and new JavaScript APIs is the huge chunk of development time they save us, including making maintenance easier and quicker. As long as that doesn’t translate to reduced costs, clients will not care. And that’s perfectly understandable and natural.

Money always wins.
Money always wins the argument. (Image: HikingArtist)

I don’t do much client work these days, but every time I’ve taken on a client project in my career, I’ve always presented options for browser support to my client. They want pixel perfection in IE 7? It will cost them more. They want IE 6 support? It will cost double. I explain to them that this is because I will have to do double as much work for this browser. I’ve never had a single client opt to pay more to fully support older browsers. If it doesn’t come free, you’d be surprised at how many don’t care about it as much as you think. But even if they do, at least I will have enough motivation to do it without hating them, my job, browser makers and the universe. It’s fairer for everyone, including me.

“They’ll Just Go To Another Professional Who Doesn’t Charge Extra�

Whatever you do, don’t let the client think that you are charging extra for doing the same work as another professional. Not only will that look bad, but it’s also inaccurate. Explain to them that you just want to give them options and not decide on your own which browsers to support and charge for accordingly, without ever involving them in the process and letting them have a say about it.

How Much More?

You might have noticed that I implied above that supporting old Internet Explorers requires 30 to 100% more time. That’s a huge range, isn’t it? Actually, it should be even wider. I remember a case of a client coming to me with a CSS challenge that his developers weren’t able to solve. Making something that worked in modern browsers took me half an hour, then an hour to make it work in IE 8, and then three(!) more hours to get it to work in IE 7. Who knows how much longer it would’ve taken if I had to support IE 6, too! And that wasn’t the only occasion when it took me very little time to build a prototype that works in modern browsers and then a grossly disproportionate amount of extra time to make it work the same way in old Internet Explorers. If you’ve been in the field for more than a year, I’m sure this has happened to you, too.

On the other hand, if you don’t use any modern technology and you stick to CSS 2.1, then I guess you would only have to face the old IE bugs, which would take some extra time but not double. Or, if you used a ton of frameworks and polyfills, you would still have to spend some time making them work together and debugging potential conflicts, but still not double the time. 30% was an estimate for cases like those.

As you can see, the range is huge and depends on a number of different factors, including but not limited to the following:

  • You
    How modern are your development techniques? The more cutting-edge they are, then the more effort you will need to put into making good fallbacks or coming up with alternative techniques for old Internet Explorers (but less effort to make the original prototype)
  • The project
    If it’s a brochure website, the main thing that will need extra effort in order to work in old IEs is the styling. If it’s a Web application, it gets way trickier (and more time-consuming).
  • Level of support
    Supporting a browser is not black and white, either no support or full support. How good your fallbacks need to be will greatly determine how much extra time you have to spend on them.

So, I’m sorry but I can’t tell you how much extra you will need to charge to support old Internet Explorers. You’ll have to decide yourself, case by case, taking all relevant factors into consideration.

“But What If They Just Want To Pay For Firefox?�

Of course, there is a baseline of browser support that I won’t go below, even if the client doesn’t want to pay for it. We have a responsibility to ourselves and to the Web to follow the principle of universality. Even if a client wants to pay only for Firefox support, for example, my responsibility is to ensure that the website is still functional in the other browsers. Even if they are not willing to pay for mobile support, my responsibility as a Web developer is to at least add some media queries and make it decent there. Even if they don’t care about accessibility, my responsibility is to make the website somewhat accessible. These things don’t take up much time anyway, and they should be factored into even your lowest price.

So, What To Do With Old IEs?

So, what do I do for those wise clients who don’t want to pay for support of old Internet Explorers? Usually, I try to keep graceful degradation in mind and provide decent fallbacks for old browsers, so that at least the content is accessible in them. But in cases of really naughty browsers, like IE 6 and 7, sometimes even graceful degradation doesn’t work very well. Then, what I usually do is split my CSS into three files:

  • base.css
    Fonts, basic colors, etc.
  • screen.css
    Everything specific to the screen. Most of the CSS goes here.
  • print.css
    Print-specific styles, such as for hiding contact forms, etc.

Then, I just don’t serve screen.css to IE 7 and below. They get something like a print style sheet, without the hidden elements. It’s not very pretty, and it’s not modern, but at least they get the content. The same could be done with JavaScript. Check whether an API is present before using it, or simply don’t serve those script files to old Internet Explorers. If you’ve coded your JavaScript properly and it’s unobtrusive and all, then old browsers won’t get that extra functionality, but they won’t get JavaScript errors and broken functionality either. All of those require minimal effort on your part.

“Does That Mean I Always Have To Charge Less For Using Modern Stuff?”

While discussing my point of view with another developer, he asked me, “So, you’re saying that I shouldn’t charge more if I use responsive design and add a bunch of media queries?� Absolutely not! I’m not saying we should feel sorry for being cutting-edge or punish ourselves for that with less income! What I’m barely advocating is the common-sense idea of charging more for more hours of work. If you code some JavaScript that does the same thing that media queries do, then of course you should charge more for the JavaScript, because it will take you more time. But if you weren’t going to do anything like that, and the media queries were icing on the cake, then of course you should charge them more than you would for a non-responsive version of the website.

Conclusion

We may love what we do, but we certainly don’t love catering to the whims of old browsers. We do a lot of extra work to hide their incompetence, and that work needs to be compensated for properly. You don’t have to work for free, especially on something you don’t like doing. Explain the situation to your clients and they’ll understand how it goes, I promise. After all, “extra work = higher costs� is an established rule in every industry. The concept is not hard to grasp, and it makes the benefit of modern Web technologies much more tangible for technologically unsavvy clients.

What do you think?

How do you account for browser support in the pricing of your work? Do you charge extra for legacy browsers or do you provide a basic version of the design to legacy browsers? Let us know and leave a comment!

(al)


© Lea Verou for Smashing Magazine, 2011.


Optimizing Long Lists Of Yes/No Values With JavaScript





 



 


Very frequently in Web development (and programming in general), you need to store a long list of boolean values (yes/no, true/false, checked/unchecked… you get the idea) into something that accepts only strings. Maybe it’s because you want to store them in localStorage or in a cookie, or send them through the body of an HTTP request. I’ve needed to do this countless times.

The last time I stumbled on such a case wasn’t with my own code. It was when Christian Heilmann showed me his then new slide deck, with a cool feature where you could toggle the visibility of individual slides in and out of the presentation. On seeing it, I was impressed. Looking more closely, though, I realized that the checkbox states did not persist after the page reloaded. So, someone could spend a long time carefully tweaking their slides, only to accidentally hit F5 or crash their browser, and then — boom! — all their work would be lost. Christian told me that he was already working on storing the checkbox states in localStorage. Then, naturally, we endlessly debated the storage format. That debate inspired me to write this article, to explore the various approaches in depth.

Using An Array

We have two (reasonable) ways to model our data in an array. One is to store true/false values, like so:

[false, true, true, false, false, true, true]

The other is to store an array of 0s and 1s, like so:

[0, 1, 1, 0, 0, 1, 1]

Whichever solution we go with, we will ultimately have to convert it to a string, and then convert it back to an array when it is read. We have two ways to proceed: either with the old Array#join() (or Array#toString()) and String#split(), or with the fancier JSON.stringify() and JSON.parse().

With the JSON way, the code will be somewhat shorter, although it is the JavaScript equivalent of slicing bread with a chainsaw. Not only there is a performance impact in most browsers, but you’re also cutting down browser support quite a bit.

The main drawback of using array-based strings is their size in bytes. If you go with the number method, you would use almost 2 characters per number (or, more precisely, 2N − 1, since you’d need one delimiter per number, except for the last one):

[0, 1, 1, 0, 0, 1, 1].toString().length // 13, for 7 values

So, for 512 numbers, that would be 1023 characters or 2 KB, since JavaScript uses UTF-16. If you go with the boolean method, it’s even worse:

[false, true, true, false, false, true, true].toString().length // 37, also for 7 values

That’s around 5 to 6 characters per value, so 2560 to 3072 characters for 512 numbers (which is 5 to 6 KB). JSON.stringify() even wastes 2 more characters in each case, for the opening and closing brackets, but its advantage is that you get your original value types back with JSON.parse() instead of strings.

Using A String

Using a string saves some space, because no delimiters are involved. For example, if you go with the number approach and store strings like '01001101010111', you are essentially storing one character per value, which is 100% better than the better of the two previous approaches. You can then get the values into an array by using String#split:

'01001101010111'.split(''); // ['0','1','0','0','1','1','0','1','0','1','0','1','1','1']

Or you could just loop over the string using string.charAt(i) — or even the string indexes (string[i]), if you don’t care about older browsers.

Using Bitfields

Did the previous method make you think of binary numbers? It’s not just you. The concept of bitfields is quite popular in other programming languages, but not so much in JavaScript. In a nutshell, bitfields are used to pack a lot of boolean values into the bits of the boolean representation of a number. For example, if you have eight values (true, false, false, true, false, true, true, false), the number would be 10010110 in binary; so, 150 in decimal and 96 in hex. That’s 2 characters instead of 8, so 75% saved. In general, 1 digit in the hex representation corresponds to exactly 4 bits. (That’s because 16 = 24. In general, in a base2n system, you can pack n bits into every base2n digit.) So, we weren’t lucky with that 75%; it’s always that much.

Thus, instead of storing that string as a string and using 1 character per value, we can be smarter and convert it to a (hex) number first. How do we do that? It’s no more than a line of code:

parseInt('10010110', 2).toString(16); // returns '96'

And how do we read it back? That’s just as simple:

parseInt('96', 16).toString(2); // returns  '10010110'

From this point on, we can follow the same process as the previous method to loop over the values and do something useful with them.

Can We Do Better?

In fact, we can! Why convert it to a hex (base 16) number, which uses only 6 of the 26 alphabet letters? The Number#toString() method allows us to go up to base 36 (throwing a RangeError for >= 37), which effectively uses all letters in the alphabet, all the way up to z! This way, we can have a compression of up to 6 characters for 32 values, which means saving up to 81.25% compared to the plain string method! And the code is just as simple:

parseInt( '1001011000', 2).toString(36); // returns 'go' (instead of '258', which would be the hex version)
parseInt('go', 36).toString(2); // returns  '1001011000'

For some of you, this will be enough. But I can almost hear the more inquisitive minds out there shouting, “But we have capital letters, we have other symbols, we are still not using strings to their full potential!� And you’d be right. There is a reason why every time you open a binary file in a text editor, you get weird symbols mixed with numbers, uppercase letters, lowercase letters and whatnot. Every character in an UTF-16 string is a 2 bytes (16 bits), which means that if we use the right compression algorithm, we should be able to store 16 yes/no values in it (saving 93.75% from the string method).

The problem is that JavaScript doesn’t offer a built-in way to do that, so the code becomes a bit more complicated.

Packing 8 Values Into One Character

You can use String.fromCharCode to get the individual characters. It accepts a numerical value of up to 65,535 and returns a character (and for values greater than that, it returns an empty string).

So, we have to split our string into chunks of 16 characters in size. We can do that through .match(/.{1,16}/g). To sum up, the full solution would look like this:

function pack(/* string */ values) {
    var chunks = values.match(/.{1,16}/g), packed = '';
    for (var i=0; i < chunks.length; i++) {
        packed += String.fromCharCode(parseInt(chunks[i], 2));
    }
    return packed;
}

function unpack(/* string */ packed) {
    var values = '';
    for (var i=0; i < packed.length; i++) {
        values += packed.charCodeAt(i).toString(2);
    }
    return values;
}

It wasn’t that hard, was it?

With these few lines of code, you can pack the aforementioned 512 values into — drum roll, please — 32 characters (64 bytes)!

Quite an improvement over our original 2 KB (with the array method), isn’t it?

Limitations

Numbers in JavaScript have limits. For the methods discussed here that involve an intermediate state of converting to a number, the limit appears to be 1023 yes/no values, because parseInt('1111…1111', 2) returns Infinity when the number of aces is bigger than 1023. This limit does not apply to the last method, because we’re only converting blocks of bits instead of the whole thing. And, of course, it doesn’t apply to the first two methods (array and string) because they don’t involve packing the values into an integer.

“I Think You Took It A Bit Too Far�

This might be overkill for some cases. But it will definitely come in handy when you want to store a lot of boolean values in any limited space that can only store strings. And no optimization is overkill for things that go through the wire frequently. For example, cookies are sent on every single request, so they should be as tiny as possible. Another use case would be online multiplayer games, for which response times should be lightning-fast, otherwise the games wouldn’t be fun.

And even if this kind of optimization isn’t your thing, I hope you’ve found the thought process and the code involved educational.

(al)

Thanks to Eli Grey and Jonas Wagner for their advice and corrections

Image on front page created by Ruiwen Chua.


© Lea Verou for Smashing Magazine, 2011.


PrefixFree: Break Free From CSS Prefix Hell





 



 


Editor’s note: This article is the first piece in our new series introducing new, useful and freely available tools and techniques presented and released by active members of the Web design community. Lea Verou is well-known for her experiments with CSS and JavaScript and in this post she presents her recent tool, prefixfree which will hopefully help you break free from the CSS prefix hell.

So What’s the Problem With Prefixes?

I’m sure we all agree that CSS3 is pretty cool and that it enables us to do things that were previously impossible. But those of us who use CSS3 a lot have surely experienced prefix hell, as seen in the snippet below (from a real style sheet!):

.download {
   position: absolute;
   top: 1em;
   left: -1.5em;
   width: 6em;
   height: 6em;
   padding: 1em 0;
   background: #80A060;
   background-image: -webkit-linear-gradient(transparent, rgba(0,0,0,.3));
   background-image: -moz-linear-gradient(transparent, rgba(0,0,0,.3));
   background-image: -o-linear-gradient(transparent, rgba(0,0,0,.3));
   background-image: -ms-linear-gradient(transparent, rgba(0,0,0,.3));
   background-image: linear-gradient(transparent, rgba(0,0,0,.3));
   color: white;
   line-height: 1;
   font-size: 140%;
   text-align: center;
   text-decoration: none;
   text-shadow: .08em .08em .2em rgba(0,0,0,.6);
   -webkit-border-radius: 50%;
   -moz-border-radius: 50%;
   border-radius: 50%;
   -webkit-box-shadow: .1em .2em .4em -.2em black;
   -moz-box-shadow: .1em .2em .4em -.2em black;
   box-shadow: .1em .2em .4em -.2em black;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
   -ms-transform: rotate(15deg);
   -webkit-transform: rotate(15deg);
   -moz-transform: rotate(15deg);
   -o-transform: rotate(15deg);
   -ms-transform: rotate(15deg);
   transform: rotate(15deg);
   -webkit-animation: none;
   -moz-animation: none;
   animation: none;
}

I’m not saying that prefixes are bad. We need them. But the reality is that, in most cases, they cause maintenance troubles, they bloat CSS files, and they make it harder to tweak values (because you have to do it five times or more).

A Solution: prefixfree

The code I write in my live demo slides and presentations doesn’t have any prefixes, even for things like @keyframes or the transition property, which aren’t yet supported anywhere prefix-less. To be able to do this, I wrote a script that detects the prefix of the current browser and adds it where needed. Recently, I thought, why not adapt the script to process all of the CSS code on a page, so that the CSS in my style sheets is as elegant as the code in my demos? Shortly after, prefixfree was born.

prefixfree

The script essentially does everything in JavaScript’s power to allow you to completely forget about vendor prefixes. It processes linked style sheets (except the ones in @import rules), embedded style sheets, inline styles, even CSS added afterwards (such as in new elements, CSSOM property changes and lookups). And if, in rare cases, you want to use a different definition for a different engine (for example, because one’s implementation is buggy), you can still use prefixed CSS.

The good thing about prefixfree is that once the browser vendors drop their prefixes for CSS3 properties, you can just remove the script and your CSS will still work. Your code will continue to be valid CSS3 (so valid that it will even pass a CSS validator). Your code does not depend on it (unlike CSS preprocessors); rather, it functions more like a polyfill, smoothing out browser differences for the time being.

Another useful feature is that the script auto-detects which properties need prefixing. Its code has no property list. It detects which properties are supported and which of them are supported only with a prefix. Values, selectors and @rules are based on predefined lists, but they are still prefixed only when needed. No browser sniffing is involved; everything is based on feature detection.

prefixfree

Unlike other solutions, prefixfree adds the current prefix at runtime, so the user downloads a much smaller CSS file. Some might argue that pre-processed CSS is faster because no client-side processing is involved. To some extent, this is true, but in my experiments there was no significant lag. With the borderline exception of Opera, it was hardly noticeable.

Also, there are a few server-side solutions, but there are two main issues with those. Firstly, the file size of the CSS file is still huge, as it has to contain all the prefixes (and the unprefixed versions). And secondly, the server-side script has to maintain lists of properties at all times, because they cannot be automatically detected, like with prefixfree.

So, what does the rule above become with prefixfree? It becomes this beauty:

.download {
   position: absolute;
   top: 1em;
   left: -1.5em;
   width: 6em;
   height: 6em;
   padding: 1em 0;
   background: #80A060;
   background-image: linear-gradient(transparent, rgba(0,0,0,.3));
   color: white;
   line-height: 1;
   font-size: 140%;
   text-align: center;
   text-decoration: none;
   text-shadow: .08em .08em .2em rgba(0,0,0,.6);
   border-radius: 50%;
   box-shadow: .1em .2em .4em -.2em black;
   box-sizing: border-box;
   transform: rotate(15deg);
   animation: none;
}

Download the Script on GitHub!

You can download prefixfree from GitHub. The minified version is less than 5 KB, which becomes less than 2 KB after Gzip’ing. Please keep in mind that it’s still a very early beta and might have bugs. You can help fix them, or at least report them in the issues tracker. Have fun!

(al)


© Lea Verou for Smashing Magazine, 2011.


Help The Community: Report Browser Bugs


  

You’re developing a new website and have decided to use some CSS3 and HTML5, now that many of the new specifications are gaining widespread support. As you’re coding the theme and thinking of how much easier these new technologies are making your job, you decide to stop for a while and test in other browsers, feeling a bit guilty for getting carried away and having forgotten to do so for a while. “Please work,� you whisper to your computer, while firing up all of the browsers you have installed. Browser A, check. You smile, feeling a bit relieved. Browser B, check. Your smile widens, and you start to feel better already. Browser C, “FFFFUUUUUUUUUUU…!�

Sound familiar? You might be surprised to hear that this is not necessarily your fault. With the competition in the browser market these days and the fast pace at which the new specifications are developing, browser makers are implementing new stuff in a hurry, sometimes without properly testing it. CSS3 and HTML5 are much more complex than their predecessors. The number of possible combinations of new features is huge, which leads to the most common cause of bugs: two (or more) things that weren’t tested together. As a result, developers these days stumble upon browser bugs much more frequently than they used to.

Why Should I Bother Reporting Bugs?

If you don’t, perhaps no one else will. Maybe the bug you’ve discovered is so rare that no one else will stumble on it. Or maybe they will, but they won’t know how to report it. They might think that it’s their fault, just as you originally did. Besides, if you’ve used these new technologies in a way that triggers the bug now, you will likely do so again in the future as well, so you would directly benefit from the bug getting fixed. And in the process, you’d be helping thousands of other developers avoid the frustration you’ve faced.

You might think that reporting the bug would be pointless, because it would take ages to fix, and would take even longer for users to upgrade to the fixed version. However, for all browsers except Internet Explorer (IE), this is not true anymore. Users of Firefox, Opera, Safari and Chrome upgrade really quickly these days, because the software pushes them to do so or (in the case of Chrome) doesn’t even give them a choice. Also, some bugs get fixed quite quickly, especially the ones that come with a decent report. Keep reading, and your own bug reports will likely fall in this latter category.

Making A Reduction

The first step is to reduce the problem to its bare minimum. If it turns out to be a browser bug, you will need to include this “reduction� in your bug report. Also, this will help you figure out a potential workaround until the browser vendor fixes it. Even if it’s not actually a browser bug, doing this will help you realize what you did wrong and fix it. Lastly, it’s a valuable aid in debugging in general.

Here is the process I follow to create reductions:

  1. Make a copy of your project. If it includes server-side code, then first save the rendered page locally; the rest of the process will be identical from this point on.
  2. Start removing CSS and JavaScript files. Eventually, you’ll find that removing one makes the problem go away. Add that one back and remove the others (except any files it depends on). In some rare cases, you might find that the bug persists even after removing all CSS and JavaScript code. In these cases, the bug is more than likely HTML-related.
  3. Now you need to find the exact code in the file that triggers the problem. Start commenting out parts of the code until the problem goes away (being careful not to introduce any new problems in the process). I find that the quickest way to do this is like doing a binary search: first, comment out around half of the code; if the bug persists, then remove that code and comment out half of the remaining code, and so on; if the bug disappears, then remove the uncommented code and proceed with that. You might find that deleting and undoing is quicker than commenting and uncommenting. Sometimes you have to do this process twice in the same file, because some bugs can be reproduced only with a particular combination of different code parts.
  4. Put the remaining CSS and JavaScript code inline by transferring it from the external file to a <style> or <script> element in the HTML document. This will make the reduction even simpler because it will be contained in only one file.
  5. Now, simplify the HTML. For example, if it’s a CSS bug, then remove everything that CSS rules don’t apply to. If the rules apply to a nested element, try applying them to the <body> instead and see whether the bug reproduces. If it is, then remove all of the <body>’s descendants.
  6. Change the document’s <title> to something relevant to the bug. Check the whole thing carefully for details that you wouldn’t want other people to see, because you usually can’t edit it after attaching it to your bug report. (I learned this the hard way.)

Now that you have your reduction, examine the code. Is it actually correct? Browser makers can’t be held accountable for the way their products handle invalid code — except for HTML5 markup, which has strictly defined error-handling. Validating the code might help, but take its output with a grain of salt. (Note that CSS vendor prefixes are valid, even if the CSS validator disagrees.)

If you have some time and want to be extra nice, here are some other things you can do to make an even better reduction:

  • Test to see whether the bug is more general than the case you have discovered. For example, if you discovered that an engine doesn’t handle border-radius: 50% correctly, then test whether the same thing happens with other percentage-based values. Or if a CSS gradient from black to transparent does not display correctly, see whether the same thing happens when you use a transition from background-color: transparent to background-color: black; if it does, then that would mean the problem stems from general interpolation and is not limited to CSS gradients. Even if you find that it’s not more general than the case you originally stumbled on, do mention your experiments in the bug description, so that the developers don’t have to repeat them.
  • Try to find a workaround. Can you change or add something in the code to make the bug go away? This could be as easy as converting ems to pixels or as hard as adding a whole new declaration. Be sure to mention the workaround in the bug report.
  • Make it function like a test case, or create an additional test case. These are the special kinds of reductions that QA engineers make for automated testing systems. Such tests show the color green in browsers that don’t have the bug and red in the ones that do. Other colors may be shown, but not red and green at the same time. This is an easy task with some bugs, and incredibly hard with others.

Sometimes the nature of the problem is quite obvious, so creating a simple test case from scratch is quicker. I’ve found JSFiddle to be an invaluable aid in this. However, bear in mind that browser vendors usually prefer that you upload your own simple HTML files rather than provide JSFiddle links. If you do decide to use JSFiddle, then uncheck the “Normalized CSS� setting, remove any JavaScript libraries (unless your bug needs them to be reproduced), and append /show to the URL, so that it leads only to your test case, without the rest of the JSFiddle UI.

If you don’t have the time to make a reduction, reporting the bug is still a good idea. A bad bug report is better than none at all, and the same goes for reductions. In this case, the browser developers will have to create the reduction themselves. The difference is that they’re burdened with doing this for many more bugs than you can imagine. You only have to do it for one: yours.

Should I Report It?

There are many reasons why you might not need to report the problem as a bug after all:

  • It turns out it’s not really a bug,
  • It has already been fixed in the latest nightly build,
  • It has already been reported.

Let’s tackle these one by one.

Is It Really a Bug?

In most cases, when you isolate the problem to a simple reduction, it’s fairly obvious whether it’s a browser bug or not. However, there are some caveats to this.

A while ago, I realized that even though outline-color: invert was in the CSS specification, it didn’t work in all browsers that support outlines. In particular, it didn’t work in Webkit browsers or Firefox. Those browsers didn’t drop the declaration, but just treated it as though it was currentColor. So, I went ahead, created a reduction, and filed bug reports with both browsers. After a while, I was informed that a footnote in the specification actually permits user agents to do this, so it wasn’t actually a bug. The moral of the story is to check the specification carefully — not just the table that is included in every CSS property, but the whole thing. Knowing these details will make you a better developer anyway.

On another occasion, I was reading the “CSS3 Backgrounds and Borders� module and found that it allowed percentages to be used for border-width, unlike CSS 2.1. I tested it, and it didn’t work in any browser. So, I filed bug reports in some of them, only to be informed that this was dropped in the “dev� version (i.e. the not-yet-published version) of the specification. The moral of this story is that, for specs still under development, don’t check the published specifications to determine whether your issue is actually a bug. Instead, look at dev.w3.org, where the most up-to-date versions of the specs reside.

Of course, in many cases, a bug is not really a bug or a lack of understanding of the spec, but just one of those stupid mistakes that we all do (aka brain farts). I remember once how distraught I was over my JavaScript not working at all in Safari, even though it gave no errors. After a while of struggling to make a reduction, I realized that I had previously disabled JavaScript in that browser to test how a website worked without it and had forgotten to enable it.

Likewise, a few days ago, my SVGs weren’t displaying as backgrounds in Firefox, even though they displayed when I opened them in new tabs. I then realized that I had two background images in the same declaration, the other one being a CSS gradient, and I had forgotten to add the -moz- version.

The one I’m most embarrassed about is when I actually reported a bug to Opera about pointer-events not working in <select> menus and was then informed that Opera hadn’t implemented pointer-events in HTML elements at all. D’oh!

In some rare cases, the bug is indeed a bug but not a browser bug. Specifications have their fair share of bugs, too. If the spec defines something other than what happens or if it defines something that conflicts with the rest of the spec, then it most likely has a bug. Such bugs should be reported in the relevant mailing list (www-style for CSS) or the W3C bug tracker. Even if this is the case, many of the guidelines mentioned below still apply.

Is It Reproducible in the Latest Nightly Builds?

If you haven’t already installed the nightlies of browsers, you should. These are the latest (potentially unstable) versions of browsers. Download them from these links:

Obviously, if your bug is not reproducible in the latest nightly of the browser, then you don’t have to report it. Just wait until the build propagates to a stable release. In other words, all you need is patience, young Padawan.

Has It Already Been Reported?

If after checking the specifications and the latest nightly, you’re still confident that it is a bug, then you need to search whether it has already been reported. Your best bet is to use the search engine of the relevant bug tracker. Don’t forget to search all statuses, because the default on some bug-tracking systems is to search only confirmed and open bugs (excluding unconfirmed and fixed or otherwise closed ones).

Be vague in your search, especially if the bug affects a feature that’s not very popular. For example, for this Webkit bug, a search for “multiple file� would show the bug, whereas a search for “input file multiple dom property� would not; I was inexperienced when I filed it and didn’t know the exact terminology at the time. If the bug tracker is public, sometimes searching on Google also helps (adding site:url-of-bug-tracker after your keywords).

If your issue has indeed been reported, some bug trackers allow voting. Mozilla’s Bugzilla gives every user a limited number of votes (the limit is in the thousands), which the user can use on any bug they wish. Also, Chrome’s bug tracker features a star in the top-left corner, which you can click to indicate that you consider the bug important. I’m not yet sure whether the developers take this into account, but voting certainly doesn’t hurt.

Different Engines, Different Bug Trackers

Every browser has its own bug-tracking system (BTS).

Safari and Chrome share the same engine (Webkit), so bugs that can be reproduced in both should be reported in Webkit’s BTS. Chrome has its own BTS as well, intended for bugs that are reproducible only in it. Also, if you’re dealing with a JavaScript bug in Chrome, report it to the V8 bug tracker.

You will need to create a free account to file bugs with any of these bug trackers (except Opera’s Wizard). But it’s a one-time thing, and it’s useful because it allows you to easily track bugs that you’ve reported.

All of the browsers’ bug trackers are public, with one exception: Opera’s. You can report Opera bugs through the public form I linked to above, but to access the BTS and to discuss your bug and monitor its progress, you will need to become an Opera volunteer (or an employee!) and sign an NDA. Volunteering is by invitation only, but if you submit a lot of good bug reports, there’s a good chance you’ll be invited.

Filing A Good Bug Report

The most important part of a good bug report (and the one most commonly done wrong) is the reduction. Hopefully, you’ve done that already, so the hardest part is over with. The rest probably won’t take you more than five minutes.

Providing a Good Summary

A good summary is the second-most important part of a bug report. Don’t be afraid to be verbose, if it actually adds something (don’t just babble). To take one from an actual report,

Background image disappears when body{display:table} is used (common CSS hack for correct centering + scrolling in Firefox)

… is better than “Background image disappears when body{display:table} is used,� which in turn is better than “Disappearing background image.� Of course, all three are better than “CSS broke. Please fix!!!!11�

Sometimes you may want to add keywords to the beginning of the summary to make the report more findable. For example, if your bug is about CSS3 gradients, you could prepend the summary with “[css3-images].� To get an idea of the exact tags used in a module, look at other bug reports. It will usually be the same as the id of the specification, which is located at the end of its URL path. For example, for the CSS3 module “Backgrounds and Borders,� the URL is http://www.w3.org/TR/css3-background/, and the spec’s id is css3-background. Also, these summary “tags� can be OS-specific. For example, if your bug is reproducible only in Mac OS X, then prepend your summary with “[Mac].� If the bug is about something that used to work fine in previous versions, then prepend your summary with “[Regression],� or add “regression� as a keyword if the BTS has such a feature.

Categorizing the Bug

The category to which your bug belongs is usually quite obvious, provided you take a few seconds to check them all. For CSS bugs, these are the most common candidates:

  • Internet Explorer: “CSS and HTMLâ€�;
  • Firefox: “Style System (CSS),â€� all the “Layoutâ€� components;
  • Opera Wizard: “Web page problemâ€�;
  • Webkit: “CSS, Layout and Renderingâ€�;
  • Chrome: doesn’t let you categorize bugs (its developers do it for you).

John Resig suggests some ways to categorize JavaScript bugs.

Other Fields

  • You can be as verbose in the “Descriptionâ€� field as you need to be. Explain the bug in detail (what you expected to see, what was actually displayed, etc.) and any interaction needed to reproduce it. Then mention any workarounds you found, how other browsers handle the case, and any other notable observations. But don’t start babbling about what you were doing when you discovered the bug, no matter how funny or interesting you think it is. QA time is precious; please don’t waste it with irrelevant detail.
  • The “Productâ€� will usually be “Core.â€� If you have a choice between “Coreâ€� and the browser’s name, choose “Core,â€� because bugs filed under the browser’s name are usually for the UI.
  • Regarding “Platformâ€� and “OS,â€� try to test in other operating systems if you can. (You do test your websites in different operating systems, right?) If the bug is reproducible in all OS’, then select “All.â€� If it’s reproducible in only one, then mention that in your description and/or summary.
  • Avoid changing the “Severityâ€� or “Priorityâ€� fields, because you will tend to overestimate.
  • Most people who report bugs don’t fill in the “CCâ€� field. But if you know someone who works for a given browser vendor, especially someone who frequently replies to similar bug reports (browse the reports if you’re not sure), then cc’ing them might help the bug get noticed more quickly. In some cases, this could mean the difference between a bug report getting noticed in a few days and one going unnoticed for months.
  • If you have the time to take a screenshot, by all means do so, especially if the bug is reproducible in only one OS.

What Not to Do

Never, ever report multiple bugs in the same report. Handling these is very hard for browser developers. Think about it: what status should they assign to a report if they fix one bug, but the other turns out to be a duplicate? Or only one of the two turns out to be a bug? You get the idea.

I can understand that you might be frustrated from having had to deal with that bug, but being rude won’t help. Stay polite, and keep thoughts like “I can’t believe you can’t even get this right, you morons!� to yourself.

Some Examples

Example 1: Reducing the Original Problem, Realizing It Was Your Mistake

While developing twee+, a handy little app for posting long tweets (and my entry in the 10K Apart contest), I found out that even though it worked in mobile Safari for reading, it crashed when you tried to make an edit. I had no idea what might have been causing this, so I made a copy and started reducing. After commenting out parts of the JavaScript, I found that if I removed the onresize event handler, the problem stopped occurring. And then it made total sense: I adjust the rows of the textarea when the user resizes the window. However, in Mobile Safari, this triggered a resize event, resulting in a dreaded infinite loop. So I removed the resize event handler for mobile. It’s not like the user can resize the window there anyway.

Example 2: Making a Reduction From Scratch, Filing a Bug

A big part of my upcoming CSS3 workshop in Amsterdam is hands-on challenges. Attendees will download my slide deck (which is essentially an HTML + CSS + JavaScript app) and try to solve some 5- or 10-minute challenges on everything taught. A challenge slide would look like this:

I prepared a lot of the slides in Chrome. When I opened them in Firefox, I was greeted with this ugly sizing of the textarea:

In this case, I didn’t follow the reduction process laid out above, because I had a hunch that the bug was related to the way I sized the textarea. So, I fired up JSFiddle and made this simple example, in which the bug could still be reproduced. I then tested it in Opera and observed that it behaved like Firefox, so it was probably Webkit that was buggy. I tested it in the Webkit nightlies and saw that it hadn’t yet been fixed.

Before going any further, I tried to see whether the bug was more generic. Does it happen only with textareas or with all replaced elements? I went ahead and tested <img> and <input> and found that it happens only with form fields. I did another test to see whether it also happened with top/bottom rather than left/right. It did not. I also tested on Windows, and it’s reproducible there as well.

The specification confirmed that it was indeed a bug: “The used value of ‘width’ and ‘height’ is determined as for inline replaced elements.� After a bit of searching on Google, I found this blog post, which describes the bug but does not mention an official bug report. So, I searched Webkit’s bug tracker for “textarea absolute,� “textarea positioned� and “input positioned� and couldn’t find anything relevant. It was bug-reporting time!

I went ahead and created this bug report. Let’s hope it goes well.

What Happens Next?

At some point, usually after a few days or weeks, someone will modify your bug’s status. If it turns out to be a “duplicate,� don’t feel bad: it happens to the best of us, even employees of the browser vendors themselves. If the status gets “confirmed� (usually with the status “new�), this is a good indication that it is indeed a bug and that you did the right thing by reporting it. Last but not least, if the new status is “assigned,� it means someone is actively working on the issue (or plans to do so soon), so it has a high chance of getting fixed soon.

When your bug gets a status of “resolved,� check the “resolution� field. If it says “wontfix,� it means that they’re not planning to rectify the issue, for reasons usually stated in detail in an accompanying comment. The reason is usually either that it’s not a bug (in which case, the most appropriate resolution status is “invalid�) or that they just don’t want to work on it for the time being. If the latter, you could argue your case and explain why the bug is important, but don’t get your hopes up. Last but not least, if it’s “fixed,� you can congratulate yourself on doing your part to make the Web a better place.

Further Reading

Thanks a lot to David Storey, Divya Manian, Paul Irish, Elika Etemad and Oli Studholme for their helpful tips and reviews.

Front Cover: Image source

(al)


© Lea Verou for Smashing Magazine, 2011.


  •   
  • Copyright © 1996-2010 BlogmyQuery - BMQ. All rights reserved.
    iDream theme by Templates Next | Powered by WordPress