Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
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)
end
task :count_selectors do
css_file = ENV['css_file'] || raise("missing css file")
CssSplitter.count_selectors(css_file)
end
end
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 = File.new(filename, "w")
output.write charset_statement
# Reset count with current rule count
selectors_count = rule_selectors_count
end
output.write rule if output
end
end
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."
end
end
def self.count_selectors_of_rule(rule)
rule.partition(/\{/).first.scan(/,/).count.to_i + 1
end
end

korny commented Mar 13, 2012

Automatic splitting for compass.rb:

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

/via @joschka

Owner

ChristianPeters commented Apr 16, 2012

There is a follow up gist with a SprocketsEngine for integration with the Rails Asset pipeline: https://gist.github.com/2398394

Thank you for this, came in very handy.

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

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?

jhilden commented Jan 12, 2013

FYI: This gist has been turned into a gem here: https://github.com/zweilove/css_splitter

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 */
  th.hidden-lg,
  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?

Hello.
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" />
<!--<![endif]-->
<!-- 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" />
<![endif]-->

If you have same issues check my gist, it works perfect:
https://gist.github.com/todesstoss/1c3ac8310de7714a65e6

Thanks.

kweij commented May 18, 2015

Hi,

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

I'm having same media query split problem.as @t22james

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