Skip to content

Instantly share code, notes, and snippets.

Created August 8, 2011 10:22
Show Gist options
  • Save ChristianPeters/1131536 to your computer and use it in GitHub Desktop.
Save ChristianPeters/1131536 to your computer and use it in GitHub Desktop.
Split CSS files so that there are no more than a given number of selectors in one style sheet. This is a tool to cope with Internet Explorer's limitation of max. 4095 selectors per stylesheet.
require 'rake'
require 'css_splitter'
desc 'split css files'
namespace :css do
task :split do
infile = ENV['infile'] || raise("missing infile")
outdir = ENV['outdir'] || File.dirname(infile)
max_selectors = ENV['max_selectors'] || 4095
CssSplitter.split(infile, outdir, max_selectors)
task :count_selectors do
css_file = ENV['css_file'] || raise("missing css file")
module CssSplitter
def self.split(infile, outdir = File.dirname(infile), max_selectors = 4095)
raise "infile could not be found" unless File.exists? infile
rules = IO.readlines(infile, "}")
return if rules.first.nil?
charset_statement, rules[0] = rules.first.partition(/^\@charset[^;]+;/)[1,2]
return if rules.nil?
# The infile remains the first file
file_id = 1
selectors_count = 0
output = nil
rules.each do |rule|
rule_selectors_count = count_selectors_of_rule rule
selectors_count += rule_selectors_count
# Nothing happens until the selectors limit is reached for the first time
if selectors_count > max_selectors
# Close current file if there is already one
output.close if output
# Prepare next file
file_id += 1
filename = File.join(outdir, File.basename(infile, File.extname(infile)) + "_#{file_id.to_s}" + File.extname(infile))
output =, "w")
output.write charset_statement
# Reset count with current rule count
selectors_count = rule_selectors_count
output.write rule if output
def self.count_selectors(css_file)
raise "file could not be found" unless File.exists? css_file
rules = IO.readlines(css_file, '}')
return if rules.first.nil?
charset_statement, rules[0] = rules.first.partition(/^\@charset[^;]+;/)[1,2]
return if rules.first.nil?
rules.inject(0) {|count, rule| count + count_selectors_of_rule(rule)}.tap do |result|
puts File.basename(css_file) + " contains #{result} selectors."
def self.count_selectors_of_rule(rule)
rule.partition(/\{/).first.scan(/,/).count.to_i + 1
Copy link

korny commented Mar 13, 2012

Automatic splitting for compass.rb:

on_stylesheet_saved do |path|
  CssSplitter.split(path) unless path[/\d+$/]

/via @joschka

Copy link

There is a follow up gist with a SprocketsEngine for integration with the Rails Asset pipeline:

Copy link

Thank you for this, came in very handy.

Copy link

where to put css_splitter.rake and css_splitter.rb files? would be good if there is some instruction. thanks.

Copy link

peschee commented Nov 20, 2012

I'm kind of lost. Any points on where these files should go to integrate with the compass compile / watch or sass build workflow?

Copy link

jhilden commented Jan 12, 2013

FYI: This gist has been turned into a gem here:

Copy link

t22james commented Oct 5, 2014

This does appear to have a bug, in that it will split in the middle of a media query... Discovered this at the top of my second of split files...

@charset "UTF-8";

  /* line 8, ../scss/global/_mixins.scss */
  tr.hidden-lg {
    display: table-row !important;

  /* line 9, ../scss/global/_mixins.scss */
  td.hidden-lg {
    display: table-cell !important;

Note the hanging bracket which is closing a media query which was opened in the first of the split css files.... Anyone able to factor this case into the snippet?

Copy link

I'm not familiar with ruby, but i tried to fix this tool to suit my needs:
IE have limits not only on selector count but also *.css file size, sometimes fat stylesheets files can throw errors in IE (something like: Out of memory at line XXX.) So we need to split first 4095 selectors in separate file too and include them instead of full css file.
for example:

<!-- ie 10 and above and all other browsers -->
<!--[if gt IE 9]><!-->
<link type="text/css" rel="stylesheet" media="all" href="css/screen.css" />
<!-- only ie 9 and below -->
<!--[if lte IE 9]>
  <link type="text/css" rel="stylesheet" media="all" href="css/screen_1.css" />
  <link type="text/css" rel="stylesheet" media="all" href="css/screen_2.css" />

If you have same issues check my gist, it works perfect:


Copy link

kweij commented May 18, 2015


Has anyone overcome the issue of media queries that t22james has ran into? This issue seems like a mayor bug and reason not to use this script to me, but since it's about 4 years old by now, maybe someone has already fixed it.

Thanks in advance

Copy link

I'm having same media query split @t22james

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment