Detecting IE6 with jQuery (sort of)

…and not using $.browser.

Or how to do a dirty deed with IE’s own quirks

Okay, so I admit two things. First, I hate MSIE6 with a passion; IE7 isn’t much better; IE8 is an improvement (unless it’s in quirks mode, but let’s not talk about that). Second, I came upon this after my initial searching turned up nothing. Once I got this trick to work, I was convinced this shouldn’t work and that there had to be a better way of doing it. So, I did a little more digging and then stumbled upon the very last response to a similar predicament on Stack Overflow. The poster obviously didn’t check their reply, because two fragments that look like they should have had example code are blank. It’s worth reading, though, and it gave me comfort in knowing that someone else was doing the same naughty things I was!

Either way, it didn’t matter–I figured out a separate way to trick MSIE without having to litter the page with new CSS classes or make any unusual modifications to the DOM. Better yet, my solution gives you some programmatic control. It does rely on a similar trick, however, and should probably be taken with a grain of salt. Of course, there’s about a dozen different ways you could do this, including many more that others have undoubtedly pointed out over the years (the earliest reference I’ve found in my searches goes back to 2008, but good luck finding them through Google).

Here it is:

<script type="text/javascript">
var ie6 = false;
$(document).ready(function(){
    // Do your stuff here.
 
    if (ie6) {
        // Do IE6-specific stuff here.
    }
});
</script>
<!--[if IE 6]>
<script type="text/javascript">
ie6 = true;
</script>
<![endif-->

Obligatory Disclaimer

Obviously, this isn’t the best solution. If you’re having to do weird things specifically to support a browser that is well on its way out of this world, you’re probably doing it wrong. There probably is a better solution (really!), but I can think of a handful of legitimate use cases where some trick like this is a necessity. For instance: Displaying some fancy code for people still running MSIE6 telling them to upgrade. Maybe even displaying a virtual sympathy card for being a corporate user chained to the dark past… :)

This has nothing to do with…

…jQuery? Nope, it doesn’t. I’m aware of that. However, because there are so many similar questions (“how do I detect browser X…”) related to jQuery and very few answers that actually provide a working solution that doesn’t include the deprecated $.browser methods, I figured that it couldn’t hurt to write something that has the words “detect,” “ie6,” and “jQuery” all in the same post title.

No comments.
***

Force Font Smoothing in Chrome on Windows (Hack)

Update: May 2nd, 2012

This post remains for historical reasons, but what it was intended to fix is no longer applicable. All versions of Chrome since the latter v12 releases or early v13 releases should display smooth fonts of any size under Windows. If they don’t, you might need to adjust your OS’s font settings.

Update: June 21st, 2011

This trick no longer appears to work as of the latest Chrome release (12.0.741.100 as of this writing). In the comments below, Flix suggested using -webkit-transform instead to shift rendering to the GPU, but the effect is identical to the CSS hack listed here as far as I can tell. That is, neither works. Using a standard visible drop shadow does work, however.

Consider the rest of this post (mostly) useless and archived. The only way to achieve the desired result is to use drop shadows with no alpha. To illustrate the examples originally included in this post in addition to the suggestion below–and for historical value?–here is a screenshot:

You will notice that there is no marked difference between the first three. Only the fourth appears to be smoothed; it is also the only one with a visible drop shadow.

Twas fun while it lasted!

Original hack as I wrote it back in March–note that this trick no longer works:

I discovered something a couple months ago that was a curio, but it wasn’t until recently that I decided to experiment with it to see if I could (ab)use it. The best part is: It’s not hard, nor does it require any scripting at all. It’s still a hack, and I’ll explain why toward the end of this post. The solution? Use text-shadow; this appears to trick Chrome’s font rendering engine into smoothing the font, but you must use the blur radius:

.smooth {
    text-shadow: 0px 0px 1px rgba(0,0,0,0);
}

There. That’s all. Now you can enjoy (reasonably) smooth fonts across major platforms, provided your users are using Chrome. If you care to know a little bit more about how I discover this, keep reading. If reading is something you’re allergic to, you can continue on to something else.

The rest of the story

Obligatory disclaimer: I’m not much of a designer. I enjoy writing back ends more than I do UIs, but I do occasionally dabble in the world of web-facing user interfaces in addition to various UI libraries like jQuery and its myriad plugins. Sometimes, though, there is an intersection between the world of server software and user interfaces. Occasionally, I notice things that I haven’t read elsewhere; of course, this is such a rare circumstance that I tend more often than not to simply assume I’ve completely lost my mind and go about tending to other chores.

So, let’s talk about font smoothing in Chrome. If you haven’t discovered this already or haven’t read the musings of someone else who has, I’ll quickly share the basic premise. Simply put, larger font sizes look ugly in Chrome (Windows). I don’t know the technical aspects behind this, and Chromium on other platforms isn’t susceptible to the same shortcomings, but if you’ve carefully designed a site on some Unix-like OS like Mac OS X or some flavor of Linux with sub-pixel smoothing enabled, you’re going to be sorely disappointed with the fonts on Windows. While this hack doesn’t work for other browsers–Firefox 4 appears to smooth all fonts and MSIE 8 just ignores what we’re going to do–it does work exceptionally well for Google Chrome.

The trick? Use text-shadow. As it turns out, dropping a shadow behind a particular snippet of text forces Chrome to smooth the font. Here’s a before and after sample with a fairly standard drop shadow (text-shadow: 1px 1px 1px #ccc):

Now, obviously, it’s inappropriate to have a drop shadow on everything. Sure, you can match the drop shadow with the background color of the parent(s) containing the text, but what happens if the background contains a gradient or an image? Worst case, your text ends up with a halo; best case, it just looks a little fuzzier than normal. Here’s an illustration of the halo effect using bright red as the drop shadow (text-shadow: 0px 0px 1px #f00):

Ah, yes, you say. But you don’t need the blur radius argument!

I’m glad you suggested that. Let’s try turning it off (text-shadow: 0px 0px 0px #f00):

Whoops. Here we encounter a problem–the only way to force font smoothing in Chrome is to enable the blur radius. Without it, the fonts appear just as jagged as before. (Note: This occurs regardless of the X and Y offsets. Try it–you can move the drop shadow anywhere, and the text will still remain as it was without a shadow.)

Fortunately, there’s a trick you can use to fib the font smoothing without background bleed. In this example, I have created a CSS class as follows:

.smooth {
    text-shadow: 0px 0px 1px rgba(255,0,0,0);
}

Using RGB plus alpha, we get this result with absolutely no bleed through of the drop shadow. Yes, even with bright red:

Of course, my cautious inclinations suggest to me that it’s best to match the colors to your background anyway, but for browsers that honor text-shadow, support for rgba() is included as well and as such, the text shadow will never appear.

This trick is a hack, because it appears to coerce Chrome’s font rendering engine into smoothing fonts that it would ordinarily ignore. Comparing other Webkit-based browsers on Windows (Arora and Safari, specifically) appears to suggest that Chrome uses a hybrid rendering scheme that is a cross between a built-in rendered and Windows’ default. For instance, Safari will render everything as a jagged text if the default (Windows rendering) is selected but will switch to smooth font rendering if any other mechanism is selected. Arora provides no such option, nor do many non-Webkit browsers like Opera. Obviously, you should only apply text shadows to text that you intend to use a drop-shadow on or other similar visual effect, and using this trick on small fonts (~12pt) will produce text that is almost unreadable. While there’s nothing inherently wrong with (ab)using text-shadow, you’re probably much better off using it as it was intended!

This trick does not work for any other browser on any other platform than Google Chrome for Windows. Tested with Chrome v10.0.648.151.

6 comments.
***

Annoyances: vBulletin 4 Template Hooks

I’ve been doing commercial software development for vBulletin 3.x (and, by extension, 4.x) off and on now for a couple of years. While there are some things that irritate the crap out of me about both of these products, vBulletin (both versions) have features that just aren’t found in other bulletin board packages. Admittedly, many of these exclusive features are provided by an extensive library of 3rd party software, but the point still stands–as much as I hate to admit it. Few other message boards have a plugin system that’s easy to develop for, and fewer still have the vast library of plugins available. phpBB doesn’t even come close. vBulletin still has its shortcomings for developers, but I’ll save my complaints for a later installment.

What I’m going to write about tonight is something that bit me, and I know it’s going to bite someone else out there: Template hooks have been the bane of my existence in vB4 for the majority of this weekend, and once you start adding a few yourself, you’ll grow to appreciate the manic schizophrenia that is the vBulletin 4.x template system in all its unadulterated glory. I hope to save you from the onset of severe insanity, so keep reading for my story and my solution.

Side note: You might also want to make this a summer project, because you’ll be bald by the time you’re finished, and I understand that bald heads get cold quite quickly. If you’re already bald, accept my apologies and tear something else out–like the upholstery stuffing in your desk chair. Don’t have a chair? Reach for the carpet. Don’t have carpet? Well, you’re on your own.

Template Hooks: They Work–But not When You Want Them To

I’ve written a couple of plugins that rely on the various forumhome_wgo_pos* template hooks for both vBulletin 3.x and 4.x. These hooks work perfectly for most use cases, regardless of when your plugin fires, and are almost foolproof. Don’t be lulled into a false sense of security, though. The moment you do anything unusual with template hooks in vBulletin 4.x, you’ll be bitten by the what-the-heck-happened-to-my-output surprise.

To reproduce the ailment that has been afflicting my sanity for the better part of this last Sunday, I direct you to a simple test:

  1. Create a new product, complete with its very own plugin.
  2. Set the plugin to fire on the global_start plugin hook.
  3. Add the following code to the plugin:
    $template_hook['footer_test_hook'] = '<b>Hi!</b>';
  4. Add the following code to your footer template:
    {vb:raw template_hook.footer_test_hook}
  5. Run it!

You should notice that you now have a nice, shiny string containing Hi! at the bottom of your page in the footer code. Now, let’s break it:

  1. Add a template, such as break_my_footer to your product XML (optional; you could use any other template if you like)
  2. Call this template from your plugin using something like:
    $tpl = vB_Template::create('mytemplate');

    Or, if you decided to use an existing (small) template:

    $tpl = vB_Template::create('option');
  3. Then modify your template hook code appropriately:
    $template_hook['footer_test_hook'] = htmlentities($tpl->render());
  4. Watch in horror as nothing appears in your footer.

Try as I might, I spent a good hour or two trawling various vBulletin support sites for answers. Rather than make a post somewhere and risk having one of their ill-tempered devs explain “Well, this is how it’s supposed to work, didn’t you use the search?” when the built in search generally sucks and Google doesn’t always pick up their help threads, I decided that this issue became personal. That is to say, this code insulted my mother, my father, my nonexistent siblings, and each of my ancestors going back 1,500 years.

After performing various blind tests I concluded that somehow the call to the vB_Template::create() factory method was effectively wiping the contents of $template_hook–or ignoring it, or purging it, or performing an exorcism on it with tremendous glee while I steamed with fury in front of my monitor. I then decided that I’d had enough, and so I searched for the footer template to determine where it was being called, prepared, and possibly rendered in the code. My hunch was that the footer was being generated separately from the forumhome cruft that so happily seemed to work no matter where I used it or what I did with it (and indeed it is generated separately). Yet my own template hook refused to work.

Then I came across this code in includes/class_bootstrap.php:

 $templater = vB_Template::create('footer');
                        $templater->register('admincpdir', $admincpdir);
                        $templater->register('ad_location', $ad_location);
                        $templater->register('cronimage', $cronimage);
                        $templater->register('languagechooserbits', $languagechooserbits);
                        $templater->register('modcpdir', $modcpdir);
                        $templater->register('quickchooserbits', $quickchooserbits);
                        $templater->register('template_hook', $template_hook);
                        $templater->register('facebook_footer', $facebook_footer);
                $footer = $templater->render();

Pay careful attention to the line $template->register('template_hook', $template_hook);. Clearly, the footer is processing the template hook here–so I thought to myself, perhaps there’s a nearby hook that I could attach my plugin to so I can guarantee I know that the content of $template_hook won’t be interfered with.

I scrolled up and found a hook that probably should have been fairly obvious to me from the start. But hey, it’s the weekend. What more can you expect?

($hook = vBulletinHook::fetch_hook('parse_templates')) ? eval($hook) : false;

Sheepishly, I changed my plugin to use the parse_templates plugin hook instead of global_start, and it worked! So the upshot is: If you’re going to try using custom template hooks and you discover that they won’t work the moment you load a template, try changing the plugin hook to parse_templates. It might just fix the problem.

Now, this was admittedly all my fault for not realizing that parse_templates may be the correct solution; I really should have examined the vBulletin sources more closely. Shame on me. In my defense, though, the vBulletin documentation is pretty poor, much of it is outdated, and even less of it focuses on issues specific to 4.x. However, I have one particular bone to pick: It’s puzzling to me that whatever is in $template_hook will work fine up until the moment you decide to call vB_Template::create(). There’s a comment under the create() method that indicates something to do with $template_hook and treating it as a special case for the purpose of various globals or some such, along with a reference to a bug tracker ID. I think that’s more coincidental than anything else, and certainly if I wanted to find out what was happening, I could run a trace with XDebug, but I’m not that desperate–or bored (yet). My guess is that, somehow, subsequent calls to vB_Template::create() clobber the contents of $template_hook by the time vBulletin gets around to rendering the footer; I may be wrong–I probably am–but this is an example of bizarre code suffering from manic schizophrenia.

Frankly, the vBulletin sources are so stupidly convoluted it’s a miracle the software works as well as it does. I’ll save that for another rant much later this week or next. In short, remember: If you’re toying with custom template hooks, you might just break your code. If you do, try changing the plugin you’re writing for template rendering purposes to hook into parse_templates. You’re almost guaranteed to have little to no interference with the contents of $template_hook and the parse_templates hook is nearest to the templates that are most likely to be affected.

Toodles for now. Expect to see a whiny rant soon!

3 comments.
***