Welcome to AboutHalf

menu - http://abouthalf.com

Updated IE9 gradients with rounded corners

Update to the update: I’ve made a slight modification to the HTC script to handle mouse-over / hover events better. By “better” I mean “it handles them now.” Thanks to the reader who suggested it.


Some time ago I wrote up a hacky way to work around an annoying IE9 bug.

The full write-up has the details, but in short, Internet Explorer 9 doesn’t play well with CSS3 border radius rules (for rounded corners on boxes) and IE’s proprietary gradient filter. The gradient pokes out from underneath the rounded corners. Unsightly.

Since IE9 has full support for SVGs, you can substitute an SVG for a gradient background on any arbitrarily sized HTML element.

Supporting both CSS3 gradients plus MS gradient filters and an extra SVG image plus supporting CSS is clunky at best. CSS hacks are best when they’re invisible.

With a little experimentation I learned one could extract the gradient details from MS’ gradient filter and build an SVG with those details. IE9 has robust support for data URIs in CSS, which means I could base64 encode the constructed SVG and use it as a background image.

Blammo.

What you have here is an HTC (HTML Component) which, on “contentready”, extracts gradient filter data, builds an SVG, base64 encodes that SVG, creates a stylesheet and style rule to hold that encoded data, and then applies the new background style to the element in question, and caches all this info so the next element with the same gradient definition just inherits the new style rule.

Screen capture of gradient bug and fix

Because each gradient is defined in a style rule, and then reused as needed, it’s pretty fast.

An example with many gradients.

Download the zipped HTC file and .htaccess file.

You can enable the filter in your IE9-targeted CSS in an HTML document like so:

<!--[if ie 9]>
	<style type="text/css" media="screen"> 
		.filter 
		{ 
			behavior: url(ie9-gradient-fix.htc); 
		} 
	</style> 
<![endif]-->

This HTC doesn’t sniff out the version of IE, so it should be included in a conditional stylesheet.

IE9 is more strict with HTCs than previous versions. You’ll need to make sure your web server is sending HTC files with the correct mime type, otherwise IE9 will ignore it. If you’re hosting on Apache, add the following to your .htaccess file or host configuration:

AddType text/x-component .htc

I’m pretty sure that Windows servers will take care of this automatically, but I don’t care.

Details

HTC files are basically a way to attach JavaScript event handlers to HTML elements via CSS selectors. In the following example, event handlers defined in behavior.htc are attached to all paragraph elements that are contained within a DIV element having the CSS class name “foo”.

div.foo p {behavior: url(behavior.htc);}

It’s like a primitive jQuery. Event handlers are defined and attached to elements at the beginning of the HTC document:

<PUBLIC:ATTACH EVENT="oncontentready" ONEVENT="myOnContentReadyHandler()" />

Later in the document a javascript function is defined with the same signature: myOnContentReadyHandler(). Within that function the JS keyword “this” refers to the element the event handler is attached to. So my example function could make all the <p> tags in a <div> with a class of “foo” disappear like so:

function myOnContentReadyHandler() 
{ 
	this.style.display = "none";
}

The gradient fix theory of operation

Here’s how the IE9 gradient fix works:

  1. Determine if the current element has both at least one rounded corner via CSS border-radius and a gradient filter applied. If so, continue.
  2. Determine if the current filter gradient has already been processed and cached. If not, continue building the background SVG
  3. Extract the starting color, ending color, and direction (horizontal or vertical) for the gradient from the filter css rule using the element’s currentStyle property
  4. If the colors are using #AARRGGBB format (a proprietary form of RGBA color) – extract the alpha value and convert to a decimal value from 0 to 1 for use in the SVG.
  5. Using the extracted colors, opacity, and gradient direction. Build an SVG graphic with a single gradient definition and a single rectangle filled with that gradient.
  6. Base64 encode the SVG
  7. Create a style rule with a unique classname selector defining a background image using the encoded SVG image in a data uri and removing the filter definition (e.g. removing the original gradient background).
  8. Append the style rule to a dynamically created stylesheet.
  9. Cache the class name of the new style rule in a globally accessible object using the filter rule definition as a key (this should be reasonably unique)
  10. Apply the class name to the element.

In step #2, if the filter definition exists in the cache, we skip to step #10 and apply the cached class name to the element. This way gradients are only created once per page request and reused throughout the page.

Below are some gotchas or other considerations.

Assumptions/Conditions

  1. HTC files only work when javascript is enabled.
  2. Elements with filter gradients have no other MS filters.

Creating a stylesheet within an HTC

HTC files, once loaded by IE, have their own document namespace. If you want to build a stylesheet dynamically from within an HTC, you’ll need to reference the ‘window.document’ namespace.

window.document.createStyleSheet();

CSS is tricky

The SVG background is applied via a CSS classname – the CSS rule corresponding to that class name is added to a new stylesheet, which should appear last in the list of stylesheets for the document. The declaration which unsets the original filter background uses an !important rule. So the new background image styles should override any previously defined background styles. However, your CSS may not play nicely with this dynamically created style rule. If the gradient pokes through your nicely rounded corners, consult IE9’s dev tools and make sure that you don’t have a CSS rule that’s overriding the dynamic rule.

Base64

I didn’t write my own base64 encoding function. I’m no dummy. I used the JavaScript class provided by WebTookKit.info.

Related posts

  • Default system fonts on mobile platforms

    Tinytype is a great resource, charting all the system fonts available on major mobile platforms.

  • Conditional comments unsupported in IE11‘s emulator

    Since version 9, Internet Explorer has included some very good developer tools, including an emulator which allowed you to view a web page using an earlier version. This allowed for you to do quick and dirty testing of your site in various versions of IE. However, IE 11’s emulator does not support conditional comments. “Conditional […]

  • Understanding CSS pixel measurements

    In CSS, “px” is not an angular measurement and it is not non-linear.

  • Chris Bowler compares Cloud.typography and Typekit

    Chris Bowler compares the major features of Adobe’s Typekit web font service and Cloud.typography from H&FJ. The verdict: Typekit may be somewhat better suited to the personal or smaller site. Both are great. H&FJ is proud of their Screensmart Fonts. via Shawn Blanc.

  • Font Custom

    This small ruby program takes a folder full of SVG files and creates an icon font for use on the web. Neat!

  • Orientation media query challenges in Android browsers

    When the software keyboard is displayed in Chrome for Android or the stock Android Browser[1] the browser window is resized, which triggers a window.resize event and a window.orientationchange event in JavaScript as well as possibly causing CSS media queries to be reapplied. In iOS, the software keyboard is overlaid over the browser window, so this […]

  • EMs in CSS media queries

    CSS3 width and height media queries work best with relative units Skip the details, show me the code In CSS the “@media” rule defines a block style rules which only apply to a given medium like print or on screen. /* These styles apply when the web page is printed */ @media print { body […]

  • No. No tables weren’t easier.

    I ran across this funny tweet in my timeline the other day. <table> <tr> <td> <h1>1999 <div class=“container”> <div class=“row”> <div class=“span6”> <h1>2010 via @bobearth I’m not going to lie; I LOLed. But, it stuck in my mind like a pebble stuck in my sock. Because, while anyone who actually made websites in the 90’s […]

  • Laura Kalbag discusses “display: none;” and responsive design

    display: none; Or The things you think are common knowledge but really they aren’t..

  • Less is more CSS

    One of my last duties at my previous job was to migrate the site’s CSS into the Bootstrap CSS framework. By “duty” I mean “project I pitched and advocated for a whole lot”. Bootstrap is eerily similar to the CSS framework I had cobbled together over my time there, only much better written (Bootstrap has […]