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

This comment has been minimized.

Show comment Hide comment
@korny

korny Mar 13, 2012

Automatic splitting for compass.rb:

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

/via @joschka

korny commented Mar 13, 2012

Automatic splitting for compass.rb:

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

/via @joschka

@ChristianPeters

This comment has been minimized.

Show comment Hide comment
@ChristianPeters

ChristianPeters Apr 16, 2012

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

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

@10thfloor

This comment has been minimized.

Show comment Hide comment
@10thfloor

10thfloor Jul 12, 2012

Thank you for this, came in very handy.

Thank you for this, came in very handy.

@kennyma603

This comment has been minimized.

Show comment Hide comment
@kennyma603

kennyma603 Aug 22, 2012

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

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

@peschee

This comment has been minimized.

Show comment Hide comment
@peschee

peschee 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?

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

This comment has been minimized.

Show comment Hide comment
@jhilden

jhilden Jan 12, 2013

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

jhilden commented Jan 12, 2013

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

@t22james

This comment has been minimized.

Show comment Hide comment
@t22james

t22james 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?

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?

@todesstoss

This comment has been minimized.

Show comment Hide comment
@todesstoss

todesstoss Oct 24, 2014

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.

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

This comment has been minimized.

Show comment Hide comment
@kweij

kweij 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

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

@benlwilliams

This comment has been minimized.

Show comment Hide comment
@benlwilliams

benlwilliams Oct 16, 2015

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

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