Getting around IE9 CSS limits

When having to use a decent portion of Bootstrap’s components, plus my theme and some additional vendor CSS, the number of CSS lines really start to add up. Since IE9 has a line limit, I’ve added csssplit-grunt to my workflow to break up my sheets. Therefore, a second stylesheet is being produced.

In libs/scripts.php, under dev, I’ve changed, 'css' => '/assets/css/main.css' to 'css' => '/assets/css/main_page_1.css' and added wp_enqueue_style('roots-extra_css', get_template_directory_uri() . '/assets/css/main_page_2.css', false, null); to list.

Is there some better, optimal way to accommodate IE9’s CSS limit besides me being smarter about how I write my CSS rules?

Also, my poor fix above only satisfies the dev build, not the production build.

I’ll post my one experience with IE9 CSS limits, welcoming feedback (using roots as of 1b333d6). I decided to use a single main css file for non-IE browsers (to avoid the extra http requests of split stylesheets), then conditionally load separate IE9 stylesheets as needed.

Gruntfile – I don’t develop in IE, so I only created IE9 styles in the grunt ‘build’ task (not ‘dev’). I created a duplicate stylesheet for IE9 with less:build, then treated the IE9 stylesheet separately with autoprefixer and split it with grunt-bless (I’m on v 0.1.1). I adjusted the definition of the ‘build’ task to include the IE9 stuff. Here are relevant selections from my Gruntfile, with many line breaks removed to reduce space here:

grunt.initConfig({
  jshint: { ... },
  less: {
    dev: { ... },
    build: {
      files: {
        'assets/css/main.min.css': [ 'assets/less/main.less' ],
        'assets/css/main-ie9.min.css': [ 'assets/less/main.less' ]
      },
      options: { compress: true } 
    }
  },
  concat: { ... },
  uglify: { ... },
  autoprefixer: { ...
    build: {
      options: { browsers: ['last 2 versions',
        'android 2.3', 'android 4', 'opera 12'], },
      src: 'assets/css/main.min.css' },
    build_ie9: {
      options: { browsers: ['ie 9'] },
      src: 'assets/css/main-ie9.min.css' }
  },
  bless: { css: { files: { 'assets/css/main-ie9.min.css':
    'assets/css/main-ie9.min.css' } } },
  modernizr: { ... },
  version: { ... files: { 'lib/scripts.php':
    'assets/{css,js}/{main,main-ie9,scripts}.min.{css,js}' } ... },
  watch: { ... }
});

// Register tasks
...
grunt.registerTask('build', [ 'jshint', 'less:build',
  'autoprefixer:build', 'autoprefixer:build_ie9', 'uglify',
  'modernizr', 'bless', 'version' ]
);

lib/scripts.php – I enqueued the IE9 styles with conditional stylesheets. Selections from lib/scripts.php:

function roots_scripts() {
...
if (WP_ENV === 'development') {
  ...
} else {
  ...
  $assets     = array(
    'css'         => '/assets/css/main.min.css?' . $assets['assets/css/main.min.css']['hash'],
    'css-ie9-1'   => '/assets/css/main-ie9-1.min.css?' . $assets['assets/css/main-ie9-1.min.css']['hash'],
    'css-ie9-2'   => '/assets/css/main-ie9-2.min.css?' . $assets['assets/css/main-ie9-2.min.css']['hash'],
    ...
  );
}

// see http://discourse.roots.io/t/enqueue-respond-script-conditionally-for-ie8-under-grunt/217
wp_enqueue_style('roots_css', get_template_directory_uri() . $assets['css'], false, null);
wp_enqueue_style('roots_css_ie9-1', get_template_directory_uri() . $assets['css-ie9-1'], false, null);
wp_enqueue_style('roots_css_ie9-2', get_template_directory_uri() . $assets['css-ie9-2'], false, null);

$wp_styles->add_data( 'roots_css', 'conditional', '!IE' ); // see also my_downlevel_revealed()
$wp_styles->add_data( 'roots_css_ie9-1', 'conditional', 'IE 9' );
$wp_styles->add_data( 'roots_css_ie9-2', 'conditional', 'IE 9' );
...
}

lib/extras.php – I used a downlevel-revealed conditional comment to only load the main stylesheet when not IE9. I added this function to my theme – corresponding to the $wp_styles->add_data( 'roots_css', ...) from lib/scripts.php above.

/**
 * Put main stylesheet load in "Downlevel Revealed" conditional comments
 *   Later priority so that this will process AFTER the soil plugin
 */
add_filter('style_loader_tag', 'my_downlevel_revealed', 11, 2);
function my_downlevel_revealed ($tag, $handle) {
  if ($handle !== 'roots_css')
    return $tag;
  return '<!-->' . $tag . '<!--';
}

templates/head.php – I added an empty conditional comment to prevent blocked downloads. Below is the top of templates/head.php. Maybe the empty comment should have come before the doctype.

<!doctype html>
<!--[if IE]><![endif]-->
<html class="no-js" <?php language_attributes(); ?>>

oldIE – The above has no styles for IE8 and older, so adjust accordingly (could make your IE9 styles just apply to all IE lte IE 9). For my website in question, viewers were likely to be corporate folks stuck on old IE versions, so I actually also built an oldIE css file too (in addition to the IE9 styles), subjected it to the above procedures, giving it special treatment in LESS (e.g., to use px and not rems, handle opacity, simulate rgba, etc.), and also stripped media queries with grunt-stripmq.

2 Likes

Thanks a bunch @fullyint. IE—a thorn in our side for what seems like an eternity.

Any chance you could drop your complete working Gruntfile in? The above seems to have some errors. Having trouble getting mine to split the file without various issues. A gist would be ideal.

Thanks!

Disclaimer. I haven’t used this approach in production because I haven’t had enough css to require it. However, it appeared successful when I was testing about 9 months ago.

Gist of my Gruntfile is here.

Correction to lib/scripts.php in post above. Taking a closer look before posting this gist, I see that grunt-bless @imports any split files into your primary IE css file. So, lib/scripts.php only needs a single instance of main-ie9 instead of the multiple numbered versions I listed in my post above (e.g., css-ie9-1, css-ie9-2, etc). For example, grunt-bless could create a main-ie9.min.css file like this…

@import url('main-ie9.min-blessed3.css?z=1420576331715');
@import url('main-ie9.min-blessed2.css?z=1420576331715');
@import url('main-ie9.min-blessed1.css?z=1420576331715');
[ remaining css would appear here, minified into a single line ]

Note for testing. If you’re also using grunt-stripmq (e.g., for lte ie8), you may want to temporarily disable it while testing grunt-bless. It “Cleans the CSS with clean-css, by merging selectors and properties”. So, if your method of testing grunt-bless is to paste in many repeated properties (like the Bless CSS example file), grunt-stripmq would merge/strip the duplicates and you may think grunt-bless failed to split the file when in fact it never saw enough lines of css to require splitting.

1 Like