├── README.md ├── css.html ├── css ├── index.html ├── script.js └── test.css ├── html.html ├── test.css └── test.html /README.md: -------------------------------------------------------------------------------- 1 | MiniMinifier 2 | == 3 | 4 | A collection of super tiny minifiers more efficient than most of the other online minifiers 5 | 6 | --- 7 | 8 | 128b CSS Minifier: 9 | === 10 | 11 | ```` 225 | 250 | 251 | 252 | 253 | 254 | -------------------------------------------------------------------------------- /css/script.js: -------------------------------------------------------------------------------- 1 | var code = p.value, 2 | 3 | string = url = attr = 0, 4 | string_back = url_back = attr_back = 0, 5 | strings = []; 6 | urls = []; 7 | attrs = []; 8 | 9 | p.innerHTML = 10 | 11 | code 12 | 13 | // Remove charset rule 14 | .replace(/@charset (".*?"|'.*?');/g, "") 15 | 16 | // Remove comments /* ... * / 17 | .replace(/\/\*[^]*?\*\//g,'') 18 | 19 | // Compress spaces/tabs/line breaks as 1 space 20 | .replace(/\s+/g,' ') 21 | 22 | // Tokenize urls 23 | .replace(/url\(.*?\)/g, z=>{urls[url] = z; return `&&&${url++}&&&`}) 24 | 25 | // Tokenize strings to keep them unaltered 26 | .replace(/"(\\"|.)*?"|'(\\'|.)*?'/g, z=>{strings[string] = z; return `&&${string++}&&`}) 27 | 28 | // Remove spaces,tabs,line breaks around ~ ; , ( ) { } / @ ! < > = <= >= ' " 29 | .replace(/ *([~;,(){}\/@!<>='"]+) */g,'$1') 30 | 31 | // Isolate at-rules 32 | .replace(/(^|\{|\})@[^{}]+?(?=\{)/g, a => { 33 | return a 34 | .replace(/ ?([*:]) ?/g,'$1') // remove spaces around : in at-rules 35 | }) 36 | 37 | // Isolate selectors 38 | .replace(/(^|\{|\})[^{}]+?(?=\{)/g, a => { 39 | return a 40 | .replace(/ ?([+-]) ?/g,'$1') // remove spaces around + and - 41 | .replace(/(^|,|}) ([*:])/g,'$1$2') // keep spaces before * and :, except if they follow ^ or , or } 42 | .replace(/([^{},]*)(,(\1)(?=[,{]))*/g, "$1") // Avoid repetitions of selectors 43 | }) 44 | 45 | // Isolate rules 46 | .replace(/{[^{}]*}/g, a => { 47 | return a 48 | .replace(/ ?([*:]) ?/g,'$1') // remove spaces around * and : 49 | .replace(/ #/g, "#") // Remove spaces before hex colors 50 | 51 | }) 52 | 53 | // Tokenize case insensitive attr selectors 54 | .replace(/\[[^\]]* i\]/g, z=>{attrs[attr] = z; return `&&&&${attr++}&&&&`}) 55 | 56 | // Lowercase all the rest 57 | .toLowerCase() 58 | 59 | // Put back tokenized attr selectors 60 | .replace(/&&&&\d+&&&&/g, z=>attrs[attr_back++]) 61 | 62 | // Remove spaces between ":" and "rgb()" 63 | .replace(/: rgb/g, ":rgb") 64 | 65 | // Remove all unnecessary ; 66 | .replace(/;+}/g, '}') 67 | .replace(/{;+/g, '{') 68 | 69 | // Remove all unnecessary * in selectors 70 | .replace(/(^|,|}| )\*:/g,'$1:') 71 | 72 | // Remove "+" and leading zeroes after space or ":" or "/" or "*" and before any other number 73 | .replace(/([ :*\/])\+?0*(\d)/g, "$1$2") 74 | 75 | // Remove ".0" in decimal numbers 76 | .replace(/(\d)\.0(\D)/g, "$1$2") 77 | 78 | // Remove lone zeros before "." 79 | .replace(/(\D)0\.(\d)/g, "$1.$2") 80 | 81 | // Remove trailing zeroes in decimal numbers (ex: "1.230") 82 | .replace(/(\.[1-9]+)0*(\D)/g,"$1$2") 83 | 84 | // Remove "-" before zero 85 | .replace(/-0(\D)/g, "0$1") 86 | 87 | // Remove units after zero 88 | .replace(/([ :*\/(])0([a-z]+)/g,"$10") 89 | 90 | // Remove "+", "-" and "." in "-.0" and "+.0" and ".0" 91 | .replace(/(\D)[-+.]?\.?0(?=\D)/g,"$10") 92 | 93 | // Remove % after zero, except in parenthesis (ex: hsl(123,0%,0%)) and keyframes (ex: 0%{...}) 94 | .replace(/(\D)0%(?!\{)(?![^(]*\))/g,"$10") 95 | 96 | // Convert rgba colors in rgb (ex: rgba(255, 0, 0, 1) => rgb(255, 0, 0)) 97 | .replace(/rgba\((\d+,\d+,\d+),1(\.0)?\)/g, "rgb($1)") 98 | .replace(/hsla\(([^,]+,[^,]+,[^,]+),1(\.0)?\)/g, "hsl($1)") 99 | 100 | // Convert rgba(0,0,0,0) in transparent 101 | .replace(/rgba\(0,0,0,0\)/g, "transparent") 102 | 103 | // Convert rgb colors in hex (ex: rgb(255, 0, 0) => #FF0000) 104 | .replace(/rgb\((\d+),(\d+),(\d+)\)/g, (a,b,c,d)=>{ 105 | return "#" + ("0"+(+b).toString(16)).slice(-2) + ("0"+(+c).toString(16)).slice(-2) + ("0"+(+d).toString(16)).slice(-2); 106 | }) 107 | 108 | // Minify 6-digit hex colors to 3-digit hex colors if possible (ex: #FF0000 => #F00) 109 | .replace(/#([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3/g, "#$1$2$3") 110 | 111 | // Replace hex colors with shorter names (ex: #F00 => red) 112 | .replace(/#[0-9a-f]+/g, a=>{ 113 | return { 114 | "#f0ffff": "azure", 115 | "#f5f5bc": "beige", 116 | "#ffe4c4": "bisque", 117 | "#a52a2a": "brown", 118 | "#ff7f50": "coral", 119 | "#ffd700": "gold", 120 | "#808080": "gray", 121 | "#008000": "green", 122 | "#4b0082": "indigo", 123 | "#fffff0": "ivory", 124 | "#f0e68c": "khaki", 125 | "#faf0e6": "linen", 126 | "#800000": "maroon", 127 | "#000080": "navy", 128 | "#808000": "olive", 129 | "#ffa500": "orange", 130 | "#da70d6": "orchid", 131 | "#cd853f": "peru", 132 | "#ffc0cb": "pink", 133 | "#dda0dd": "plum", 134 | "#800080": "purple", 135 | "#fa8072": "salmon", 136 | "#a0522d": "sienna", 137 | "#c0c0c0": "silver", 138 | "#fffafa": "snow", 139 | "#d2b48c": "tan", 140 | "#008080": "teal", 141 | "#ff6347": "tomato", 142 | "#ee82ee": "violet", 143 | "#f5deb3": "wheat", 144 | "#f00": "red" 145 | }[a] || a; 146 | }) 147 | 148 | // Remove empty rules and empty media queries 149 | .replace(/(^|\{|\})[^{}]+?\{\}/g, "$1") 150 | .replace(/@[^{}]+?\{\}/g, "") 151 | 152 | // Replace font-weight values (normal => 400, bold => 500) 153 | .replace(/(font(-weight)?:[^;]*)normal/g, "$1400") 154 | .replace(/(font(-weight)?:[^;]*)bold/g, "$1700") 155 | 156 | // Simplify nth-of-type and nth-child 157 | .replace(/:nth-child\(1\)/g, ":first-child") 158 | .replace(/:nth-of-type\(1\)/g, ":first-of-type") 159 | .replace(/nth-child\(even\)/g, ":nth-child(2n)") 160 | .replace(/:nth-of-type\(even\)/g, ":nth-of-type(2n)") 161 | .replace(/:nth-child\(2n[+-]1\)/g, ":nth-child(odd)") 162 | .replace(/:nth-of-type\(2n[+-]1\)/g, ":nth-of-type(odd)") 163 | 164 | // Rename ":root" in "html" 165 | .replace(/:root/g, "html") 166 | 167 | // Rewrite margin/padding/border-width/border-radius shorthands with less attributes 168 | .replace(/((margin|padding|border-width|border-radius):)([^ ;}]+?) \3 \3 \3([;}])/g, "$1$3$4") 169 | .replace(/((margin|padding|border-width|border-radius):)([^^ ;}]+?) ([^ ;}]+?) \3 \4([;}])/g, "$1$3 $4$5") 170 | .replace(/((margin|padding|border-width|border-radius):)([^ ;}]+?) ([^ ;}]+?) ([^ ;}]+?) \4([;}])/g, "$1$3 $4 $5$6") 171 | 172 | // Convert units (except: 3pt = 4px ; 25.4mm = 96px = 1in ; 16px = 1pc) 173 | .replace(/([: {(-])360deg/g,"$11turn") // 360deg = 1turn 174 | .replace(/([: {(-])720deg/g,"$12turn") // 720deg = 2turn 175 | .replace(/([: {(-])(\d+)000ms/g,"$1$2s") // 1000ms = 1s 176 | .replace(/([: {(-])(\d+)(\d)00ms/g,"$1$2.$3s") // 100ms = .1s 177 | .replace(/([: {(-])(\d*)(\d\d)0ms/g,"$1$2.$3s") // XY0ms = .XYs 178 | .replace(/([: {(-])(\d+)0mm/g,"$1$2cm") // 10mm = 1 cm 179 | 180 | // Put back tokenized urls 181 | .replace(/&&&\d+&&&/g, z=>urls[url_back++]) 182 | 183 | // Remove "https?:" and quotes in urls 184 | .replace(/url\(('|")?(https?:)?(.*?)('|")?\)/g, "url($3)") 185 | 186 | // Put back tokenized strings 187 | // TODO? => if a string is between quotes, and contains an escaped quote, and no double quote, surround it with double quotes and unescape rhe quote (and vice versa) 188 | .replace(/&&\d+&&/g, z=>strings[string_back++]) 189 | 190 | // Remove quotes around [a-zA-Z]* names in font / font-family /... (but not content!) (may affect strings) 191 | .replace(/(content:[^;}]*)|'([a-zA-Z-_ ]+)'|"([a-zA-Z-_ ]+)"/g, "$1$2$3") 192 | 193 | // Avoid repetitions of properties 194 | .replace(/([^{}:;]*:[^{}:;]*)(;(\1)(?=[;}]))*/g, "$1") 195 | 196 | // Avoid repetitions of rules 197 | .replace(/([^{]*{[^}]*})(\1)*/g, "$1") 198 | 199 | // Remove trailing containers 200 | .replace(/["']?\)?}?}?}?$/, "") 201 | 202 | // Debug 203 | //.replace(/}+/g, "}\n"); -------------------------------------------------------------------------------- /css/test.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /* 4 | Remove all CSS comments 5 | */ 6 | 7 | /* Tokenize strings */ 8 | 9 | *{content:"...";font-family:'...'} 10 | *{content:"...\"";font-family:'..\''} 11 | 12 | /* 13 | Remove all unnecessary spaces, tabs and line breaks (leading, trailing, and around + > ~ ; : , ( ) { } / * @) 14 | NB: Keep spaces before : and * in selectors 15 | NB: Keep spaces around + and - in calc(...) (but not in nth-child and nth-of-type) 16 | */ 17 | 18 | @media ( max-width : 500px ) { 19 | #a, .b .c, 20 | d ~ e, 21 | f + g, 22 | .h + .i, 23 | .k:nth-child(2n + 1), 24 | .l:nth-of-type( - 2n + 1), 25 | :hover, *:hover, * :hover, 26 | body * { 27 | color : red !important; 28 | width : calc ( (2vh - 2px + 2cm) / 2 * 4 ) 29 | } 30 | } 31 | 32 | /* Remove all unnecessary semicolons */ 33 | *:hover, a *:hover, *:active { 34 | /* color: blue */; 35 | color: red; 36 | /* width: 100% */; 37 | } 38 | 39 | /* Remove all unnecessary * in CSS selectors */ 40 | *:hover, a *:hover, *:active, * *:hover { 41 | color: red; 42 | } 43 | 44 | /* Keep one space around space-separated values */ 45 | .digits { margin: 0 -2px 0% 0 ; box-shadow: 0 2px #000 inset ; } 46 | 47 | /* Remove all unnecessary "-", "+", "." and "0" in numbers */ 48 | .numbers { 49 | margin: 11.0px 0.11px 0.011px 0.0px; 50 | margin: -0 +0 -0px +0px; 51 | margin: -0.0 +0.0 -0.0px +0.0px; 52 | margin: -0.01 +0.01 -0.01px +0.01px; 53 | margin: -.0px +.0px -.0 +.0; 54 | margin: 0011.1100px; 55 | font: 0.1/1.0 arial; 56 | } 57 | 58 | /* Remove spaces before hrx colors */ 59 | .hex { border-color: #111 #222 #333 #444 } 60 | 61 | /* remove units after zero */ 62 | @media screen and (min-resolution : 0dpi) { 63 | .zero_unit { 64 | width: 0px; 65 | width: 0in; 66 | width: 0cm; 67 | width: 0mm; 68 | width: 0em; 69 | width: 0rem; 70 | width: 0pt; 71 | width: 0pc; 72 | width: 0ex; 73 | width: 0ch; 74 | width: 0vw; 75 | width: 0vh; 76 | width: 0vmin; 77 | width: 0vmax; 78 | width: 0deg; 79 | width: 0rad; 80 | width: 0grad; 81 | width: 0turn; 82 | width: 0%; 83 | } 84 | } 85 | /* don't remove "%" after "0" in these cases */ 86 | @keyframes zero_percent { 87 | 0% { background: hsl(111, 0%, 0%); } 88 | 100% { background: hsl(222, 0.0%, 1.0%); } 89 | } 90 | 91 | /* Convert rgba colors in rgb or transparent*/ 92 | .rgba { color: rgba(11,22,33,.5); color: rgba(11,22,33,1); background: RGBA(33,22,11,1.0); } 93 | .hsla { color: hsla(11,22,33,.5); color: hsla(11,22,33,1); background: HSLA(33,22,11,1.0); } 94 | .transparent { color: rgba ( 0, 0, 0, 0 ) } 95 | 96 | /* Convert rgb colors in hexadecimal */ 97 | .rgb { color: rgb(2, 11, 222); background: RGB(111, 22, 3) ; } 98 | 99 | /* Minify haxadecimal colors (if possible) */ 100 | .hexadecimal { color: #123456; background: #113355 } 101 | 102 | /* Replace hex with color names (if possible) */ 103 | .azure { color: #F0FFFF; color: #f0ffff; } 104 | .beige { color: #f5f5dc } 105 | .bisque { color: #ffe4c4 } 106 | .brown { color: #a52a2a } 107 | .coral { color: #ff7f50 } 108 | .gold { color: #FFD700; } 109 | .gray{ color: #808080; } 110 | .grey { color: #808080; } 111 | .green { color: #008000 } 112 | .indigo { color: #4b0082 } 113 | .ivory { color: #fffff0 } 114 | .khaki { color: #f0e68c } 115 | .linen { color: #faf0e6 } 116 | .maroon { color: #800000 } 117 | .navy { color: #000080 } 118 | .olive { color: #808000 } 119 | .orange { color: #FFA500 } 120 | .orchid { color: #DA70D6 } 121 | .peru { color: #CD853F } 122 | .pink { color: #FFC0CB } 123 | .plum { color: #DDA0DD } 124 | .purple { color: #800080 } 125 | .red { color: #FF0000; } 126 | .red { color: #F00; } 127 | .salmon { color: #FA8072 } 128 | .sienna { color: #A0522D } 129 | .silver { color: #C0C0C0 } 130 | .snow { color: #FFFAFA } 131 | .tan { color: #D2B48C } 132 | .teal { color: #008080 } 133 | .tomato { color: #FF6347 } 134 | .violet { color: #EE82EE } 135 | .wheat { color: #F5DEB3 } 136 | 137 | /* chaining: RGBA => RGB => HEX6 => HEX3 => name */ 138 | .red { color: rgba(255, 0, 0, 1) } 139 | 140 | /* Remove empty rules / media queries */ 141 | .empty { /* nothing */ ; /* nothing */ ; } 142 | 143 | @media (min-resolution: 100dpi) { } 144 | 145 | @media (min-resolution: 100dpi) { 146 | .empty { } 147 | } 148 | 149 | /* Replace bold names with numbers */ 150 | .normal { font-weight: normal } 151 | .bold { font: bold 15px arial } 152 | 153 | /* Simplify counters */ 154 | a:nth-child(1) { color: #fff } 155 | a:nth-of-type(1) { color: #fff } 156 | a:nth-of-type(even) { color: #fff } 157 | a:nth-child(even) { color: #fff } 158 | a:nth-of-type(2n+1) { color: #fff } 159 | a:nth-child(2n+1) { color: #fff } 160 | a:nth-of-type(2n-1) { color: #fff } 161 | a:nth-child(2n-1) { color: #fff } 162 | 163 | /* Replace :root with html */ 164 | :root { color: red } 165 | 166 | /* Simplify sorthands */ 167 | .shorthands { 168 | margin: 1px 2px 3px 4px; 169 | margin: 0px 0px 0px 0px; 170 | padding: 0px 5px 0px 5px; 171 | border-width: 0px 5px 10px 5px; 172 | } 173 | 174 | /* Convert some units */ 175 | .deg { transform: rotate(360deg); } 176 | .deg { transform: rotate(-720deg); } 177 | .ms { transition: 15000ms; } 178 | .ms { transition: 1500ms; } 179 | .ms { transition: 150ms; } 180 | .ms { transition: 11150ms; } 181 | .mm { margin: 100mm -100mm; } 182 | 183 | /* Remove URL/font-family quotes, but not content */ 184 | .url { background: url('//test.com/test.png') } 185 | .url { background: url("https://test.com/test.png") } 186 | .url { background: url('./test.png') } 187 | .url { background: url("test.png") } 188 | .font { font-family: "Arial", "Times New Roman" } 189 | .content:after { content: "Hi" } 190 | 191 | /* More tests */ 192 | h2 { 193 | font-size: min(var(--fontSize), 10px); 194 | } 195 | @media (width >= 600px) { 196 | html { 197 | background: lime; 198 | } 199 | } 200 | 201 | 202 | /* Remove trailing containers ( ' " ) } ) */ 203 | @media ( screen ) { 204 | @keyframes animation { 205 | 0% { background: url("image.png") } 206 | } 207 | } 208 | 209 | /* Remove trailing spaces */ 210 | 211 | -------------------------------------------------------------------------------- /html.html: -------------------------------------------------------------------------------- 1 |

128b HTML minifier

2 |