Created
December 5, 2025 05:50
-
-
Save rndme/2acd64fafe0ef828c3657311cecbdee8 to your computer and use it in GitHub Desktop.
css parser formatter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // dan's naive css formatter for editors | |
| // reliably parses and formats css using browser's CSS engine: | |
| // sorts properties in rules, removes property repeats (and fallbacks), removes vendor-specific syntax, and removes comments. | |
| // punctuationReplacements are executed while quoted strings are removed, making rule content predictable | |
| //////////////////// | |
| // DOES NOT SUPPORT NESTED RULES - MAINLY TO FORMAT SNIPPETS IN A TEXT EDITOR - NOT PRODUCTION MACHINERY!!!! | |
| //////////////////// | |
| function formatCSS(strCSS, punctuationReplacements) { | |
| var reps = {}, pr = punctuationReplacements; | |
| function processRuleText(s) { // note: already parsed and cleaned-up by browser at this point | |
| s = s.replace(/\\"/g, "❤️") // kill quotes so we can ignore thier complex processing demands | |
| .replace(/"([^"]+?)"/g, function(j, a) { | |
| var id = "~" + Math.random().toString(36).slice(-8) + "~"; | |
| reps[id] = a; | |
| return id; | |
| }); | |
| // now there are no comments or quoted strings that could look like rules but aint | |
| s = s.replace(/([;,])\s+/g, "$1"); // space around punctiaion | |
| s = s.replace(/rgba?\(([\d,\.]+)\)/g, function(j, a) { // compress color | |
| var or = a.split(","); | |
| r = or.map(Number).map(x => ("00" + x.toString(16)).slice(-2)); | |
| if(r[3]) r[3] = ("00" + Math.floor(or[3] * 255).toString(16)).slice(-2); | |
| if(r[0][0] == r[0][1] && r[1][0] == r[1][1] && r[2][0] == r[2][1] && (!r[3] || r[3][0] == r[3][1])) r = [r[0][0], r[1][0], r[2][0], r[3] || ""]; | |
| return "#" + r.join(""); | |
| }); | |
| s = s.split(/[\{\}]/g); // need upgraded to support nested rules | |
| s[1] = s[1].trim().split(";").sort().filter(String).join(";")+";"; | |
| return s[0]+"{"+s[1]+"}"; | |
| } //end processRuleText() | |
| function iterateRules(rules) { | |
| var buff = []; | |
| [...rules].forEach(function(a, b, c) { | |
| if(a.cssRules?.length) return buff.push(...iterateRules(a.cssRules)); | |
| buff.push(processRuleText(a.cssText)); | |
| }); | |
| buff = buff.join("").replace(/\s?\{\s?/g, "{"); | |
| if(pr) Object.keys(pr).forEach(k => buff = buff.replaceAll(k, pr[k])); // apply user-provide transformation replacements | |
| Object.keys(reps).forEach(k => buff = buff.replace(k, '"' + reps[k] + '"').replace(/❤️/g, "\\\"")); // restore quotes | |
| return buff.trim(); | |
| } // end iterateRules() | |
| var st = document.createElement("style"); | |
| st.disabled=true; | |
| document.body.appendChild(st); | |
| st.innerHTML = strCSS; | |
| var buff = iterateRules(st.sheet.cssRules); | |
| st.remove(); | |
| return buff; | |
| } | |
| /* | |
| // example usage to make fairly compressed css: | |
| formatCSS( strYourCSS ); | |
| // example usage to make maximally compressed css: | |
| formatCSS( strYourCSS, {": ":":"}); | |
| // example usage to make pretty css: | |
| formatCSS( strYourCSS, { | |
| "{": " {\n\t", | |
| "}": "}\n\n", | |
| ";": ";\n\t", | |
| ": ": ": ", | |
| "\t}": "}", | |
| ",": ", " | |
| }); | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment