Skip to content

Instantly share code, notes, and snippets.

@medialwerk
Forked from ChristianPeters/css_splitter.rake
Created March 8, 2012 11:09
Show Gist options
  • Save medialwerk/2000484 to your computer and use it in GitHub Desktop.
Save medialwerk/2000484 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. Fix bug when there is no charset. Always write first partial o
require 'rake'
require Compass::AppIntegration::Rails.root.to_s + '/lib/compass/css_splitter'
namespace :css do
desc 'split css files'
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
desc 'count css files'
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, new_rule_0 = rules.first.partition(/^\@charset[^;]+;/)[1,2]
rules[0] = new_rule_0 if new_rule_0 > ''
return if rules.nil?
filename = File.join(outdir, File.basename(infile, File.extname(infile)) + "_*" + File.extname(infile))
FileUtils.rm(Dir.glob(filename))
file_id = 1
selectors_count = 0
output = next_file(file_id, infile, outdir, charset_statement)
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
output = next_file(file_id, infile, outdir, charset_statement)
# Reset count with current rule count
selectors_count = rule_selectors_count
end
output.write rule if output
end
end
def self.next_file(file_id, infile, outdir, charset_statement)
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
output
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment