├── min ├── parent-selector.min.js ├── prev-selector.min.js ├── closest-selector.min.js ├── aspect-ratio.min.js ├── ancestor-selector.min.js ├── scoped-eval.min.js ├── xpath-selector.min.js ├── container-queries.min.js ├── elder-selector.min.js ├── auto-expand.min.js └── reprocss.min.js ├── test ├── parent-selector-mixin.html ├── prev-selector-mixin.html ├── elder-selector-mixin.html ├── scoped-eval-mixin.html ├── aspect-ratio-mixin.html ├── container-queries-mixin.html ├── xpath-selector-mixin.html ├── auto-expand-mixin.html ├── ancestor-selector-mixin.html ├── closest-selector-mixin.html ├── index.html └── element-queries.html ├── minify.sh ├── mixins ├── parent-selector.js ├── prev-selector.js ├── aspect-ratio.js ├── closest-selector.js ├── scoped-eval.js ├── ancestor-selector.js ├── xpath-selector.js ├── elder-selector.js ├── container-queries.js └── auto-expand.js ├── LICENSE ├── package.json ├── reprocss-logo.svg ├── reprocss.js ├── README.md └── index.html /min/parent-selector.min.js: -------------------------------------------------------------------------------- 1 | /* parent-selector / Tommy Hodgins / MIT License / version 0.0.10 */ 2 | function parent(selector,rule){var tag=document.querySelectorAll(selector);var style="";var count=0;for(var i=0;i 2 | 3 | 4 | Parent Selector mixin for reproCSS 5 | 6 |

Parent Selector Mixin Test

7 | 8 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/prev-selector-mixin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Prev Selector mixin for reproCSS 5 | 6 |

Prev Selector Mixin Test

7 | 8 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /min/ancestor-selector.min.js: -------------------------------------------------------------------------------- 1 | /* ancestor-selector / Tommy Hodgins / MIT License / version 0.0.10 */ 2 | function ancestor(selector,ancestor,rule){var tag=document.querySelectorAll(ancestor);var style="";var count=0;for(var i=0;i ./min/reprocss.min.js; 10 | uglifyjs reprocss.js >> ./min/reprocss.min.js; 11 | 12 | # Minify Mixins 13 | echo "Minifying mixins..."; 14 | cd mixins; 15 | for f in *.js; 16 | do 17 | echo "/* ${f%.*} / Tommy Hodgins / MIT License / version 0.0.10 */" > ../min/"${f%.*}.min.js"; 18 | uglifyjs ./"$f" >> ../min/"${f%.*}.min.js"; 19 | done -------------------------------------------------------------------------------- /min/scoped-eval.min.js: -------------------------------------------------------------------------------- 1 | /* scoped-eval / Tommy Hodgins / MIT License / version 0.0.10 */ 2 | function scoped(selector,rule){var tag=document.querySelectorAll(selector);var style="";var count=0;for(var i=0;i 2 | 3 | 4 | Elder Selector mixin for reproCSS 5 | 6 |

Elder Selector Mixin Test

7 | 8 |
    9 |
  • item 1 10 |
  • item 2 11 |
  • item 3 12 |
  • item 4 13 |
  • item 5 14 |
15 | 16 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /min/xpath-selector.min.js: -------------------------------------------------------------------------------- 1 | /* xpath-selector / Tommy Hodgins / MIT License / version 0.0.10 */ 2 | function xpath(selector,rule){var tag=new Array;var style="";var count=0;var result=document.evaluate(selector,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);for(var i=0;i 2 | 3 | 4 | Scoped Eval() mixin for reproCSS 5 | 6 |

Scoped Eval() Mixin Test

7 | 8 |
25%
9 |
50%
10 |
100%
11 | 12 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /min/container-queries.min.js: -------------------------------------------------------------------------------- 1 | /* container-queries / Tommy Hodgins / MIT License / version 0.0.10 */ 2 | function container(selector,test,childSelector,rule){var tag=document.querySelectorAll(selector);var style="";var count=0;for(var i=0;i 2 | 3 | 4 | Aspect Ratio mixin for reproCSS 5 | 6 |

Aspect Ratio Mixin Test

7 | 8 |
Aspect Ratio Test
9 | 10 | 11 | 12 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/container-queries-mixin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Container Queries mixin for reproCSS 5 | 6 |

Container Queries Mixin Test

7 | 8 |
Hello there
9 | 10 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/xpath-selector-mixin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | XPath Selector mixin for reproCSS 5 | 6 |

XPath Selector Mixin Test

7 | 8 |

This is an H2

9 |

This H2 :has(span)

10 | 11 |
Test
12 | 13 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/auto-expand-mixin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Auto Expand mixin for reproCSS 5 | 6 |

Auto Expand Mixin Test

7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/ancestor-selector-mixin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ancestor Selector mixin for reproCSS 5 | 6 |

Ancestor Selector Mixin Test

7 | 8 |
9 | 10 |
    11 |
  • item 1 12 |
  • item 2 13 |
  • item 3 14 |
15 | 16 |
    17 |
  • item 1 18 |
  • item 2 example 19 |
  • item 3 20 |
21 | 22 |
    23 |
  • item 1 24 |
  • item 2 25 |
  • item 3 26 |
27 | 28 |
29 | 30 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/closest-selector-mixin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Closest Selector mixin for reproCSS 5 | 6 |

Closest Selector Mixin Test

7 | 8 |
target 9 |
10 |
11 |
12 |
13 |
target 14 |
15 |
16 |
17 |
start
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /min/auto-expand.min.js: -------------------------------------------------------------------------------- 1 | /* auto-expand / Tommy Hodgins / MIT License / version 0.0.10 */ 2 | function autoExpand(selector,direction){var tag=document.querySelectorAll(selector);for(var i=0;i 2 | 3 | 4 | reproCSS test 5 | 6 |

reproCSS Tests

7 | 8 | 16 | 17 |

JS interpolation inside content:;

18 | 19 |
This is
20 | 21 | 24 | 25 | 33 | 34 |

Live Textarea Styles

35 | 36 | 37 | 38 | 47 | 48 | 53 | 54 |

Element Queries (max-characters: 0)

55 | 56 | 61 | 62 | -------------------------------------------------------------------------------- /mixins/closest-selector.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | # Closest Selector Mixin for reproCSS 4 | ## version 0.0.10 5 | 6 | This mixin lets CSS authors apply styles to the nearest element matching a CSS selector to another element matching a given CSS selector. You can use this to find the nearest matching ancestor. 7 | 8 | ### Syntax 9 | 10 | closest(selector, ancestor, rule) 11 | 12 | - `selector` is a CSS selector 13 | - `ancestor` is a CSS selector 14 | - `rule` is one or more CSS declarations separated by semicolons 15 | 16 | ### Example 17 | 18 | closest('#start', '.target', `border-color: lime`) 19 | 20 | - https://github.com/tomhodgins/reprocss 21 | 22 | Author: Tommy Hodgins 23 | 24 | License: MIT 25 | 26 | */ 27 | 28 | function closest(selector, ancestor, rule) { 29 | 30 | var tag = document.querySelectorAll(selector) 31 | var style = '' 32 | var count = 0 33 | 34 | for (var i = 0; i < tag.length; i++) { 35 | 36 | var attr = (selector+ancestor).replace(/\W+/g, '') 37 | 38 | tag[i].closest(ancestor).setAttribute('data-closest-' + attr, count) 39 | 40 | style += '\n/* ' + selector + ':closest(' + ancestor + ') */\n' 41 | + '[data-closest-' + attr + '="' + count + '"] {\n' 42 | + ' ' + rule + '\n' 43 | + '}\n' 44 | 45 | count++ 46 | 47 | } 48 | 49 | return style 50 | 51 | } 52 | -------------------------------------------------------------------------------- /mixins/scoped-eval.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | # Scoped JS Interopation Mixin for reproCSS 4 | ## version 0.0.10 5 | 6 | Evaluate JavaScript from the context of each HTML element that matches the supplied CSS selector list. 7 | 8 | ### Syntax 9 | 10 | scoped(selector, rule) 11 | 12 | - `selector` is a comma-separated string of one or more CSS selectors 13 | - `rule` is one or more CSS declarations separated by semicolons 14 | 15 | ### Example 16 | 17 | scoped('div', 'height: eval(this.offsetWidth / (16/9))px') 18 | 19 | - https://github.com/tomhodgins/reprocss 20 | 21 | Author: Tommy Hodgins 22 | 23 | License: MIT 24 | 25 | */ 26 | 27 | function scoped(selector, rule) { 28 | 29 | var tag = document.querySelectorAll(selector) 30 | var style = '' 31 | var count = 0 32 | 33 | for (var i=0; i < tag.length; i++) { 34 | 35 | var attr = selector.replace(/\W+/g, '') 36 | 37 | tag[i].setAttribute('data-scoped-' + attr, count) 38 | 39 | var scopedRule = rule.replace(/eval\((.*)\)/g, function(string, match){ 40 | 41 | var func = new Function('return ' + match) 42 | 43 | return (func.call(tag[i]) || '') 44 | 45 | }) 46 | 47 | style += '\n/* Scope: ' + selector + ' */\n' 48 | + '[data-scoped-' + attr + '="' + count + '"] {\n' 49 | + ' ' + scopedRule + '\n' 50 | + '}\n' 51 | 52 | count++ 53 | 54 | } 55 | 56 | return style 57 | 58 | } 59 | -------------------------------------------------------------------------------- /mixins/ancestor-selector.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | # Ancestor Selector Mixin for reproCSS 4 | ## version 0.0.10 5 | 6 | This mixin lets CSS authors apply styles to all ancestor elements matching a CSS selector to another element matching a given CSS selector. You can use this to style all matching ancestors. 7 | 8 | ### Syntax 9 | 10 | ancestor(selector, ancestor, rule) 11 | 12 | - `selector` is a CSS selector 13 | - `ancestor` is a CSS selector 14 | - `rule` is one or more CSS declarations separated by semicolons 15 | 16 | ### Example 17 | 18 | ancestor('#start', '.target', `border-color: lime`) 19 | 20 | - https://github.com/tomhodgins/reprocss 21 | 22 | Author: Tommy Hodgins 23 | 24 | License: MIT 25 | 26 | */ 27 | 28 | function ancestor(selector, ancestor, rule) { 29 | 30 | var tag = document.querySelectorAll(ancestor) 31 | var style = '' 32 | var count = 0 33 | 34 | for (var i=0; i 500', 'span', 'background: lime') 20 | 21 | - https://github.com/tomhodgins/reprocss 22 | 23 | Author: Tommy Hodgins 24 | 25 | License: MIT 26 | 27 | */ 28 | 29 | function container(selector, test, childSelector, rule) { 30 | 31 | var tag = document.querySelectorAll(selector) 32 | var style = '' 33 | var count = 0 34 | 35 | for (var i=0; i < tag.length; i++) { 36 | 37 | var attr = (selector+test).replace(/\W+/g, '') 38 | 39 | var func = new Function('return ' + test) 40 | 41 | if (func.call(tag[i])) { 42 | 43 | tag[i].setAttribute('data-container-' + attr, count) 44 | 45 | var container = '[data-container-' + attr + '="' + count + '"]' 46 | 47 | style += '\n/* ' + selector + '(' + test + ') ' + childSelector + ' */\n' 48 | + container + ' ' + childSelector + ' {\n' 49 | + ' ' + rule + '\n' 50 | + '}\n' 51 | 52 | count++ 53 | 54 | } else { 55 | 56 | tag[i].setAttribute('data-container-' + attr, '') 57 | 58 | } 59 | 60 | } 61 | 62 | return style 63 | 64 | } 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reprocss", 3 | "version": "0.0.10", 4 | "description": "a flexible style-tag based CSS reprocessor", 5 | "main": "reprocss.js", 6 | "files": [ 7 | "mixins/aspect-ratio.js", 8 | "mixins/auto-expand.js", 9 | "mixins/closest-selector.js", 10 | "mixins/container-queries.js", 11 | "mixins/parent-selector.js", 12 | "mixins/parent-selector.js", 13 | "mixins/scoped-eval.js", 14 | "mixins/xpath-selector.js" 15 | ], 16 | "scripts": { 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/tomhodgins/reprocss.git" 22 | }, 23 | "keywords": [ 24 | "CSS", 25 | "reprocessor", 26 | "js-in-css", 27 | "selector", 28 | "resolver", 29 | "scoped", 30 | "variables", 31 | "cursor", 32 | "scroll", 33 | "XPath", 34 | "aspect", 35 | "ratio", 36 | "variable" 37 | ], 38 | "author": "Tommy Hodgins", 39 | "license": "MIT", 40 | "bugs": { 41 | "url": "https://github.com/tomhodgins/reprocss/issues" 42 | }, 43 | "homepage": "https://github.com/tomhodgins/reprocss#readme", 44 | "contributors": [ 45 | { 46 | "name": "Tommy Hodgins", 47 | "email": "tomhodgins@gmail.com", 48 | "url": "http://tomhodgins.com" 49 | } 50 | ], 51 | "npmName": "reprocss", 52 | "npmFileMap": [ 53 | { 54 | "basePath": "/", 55 | "files": [ 56 | "reprocss.js", 57 | "mixins/aspect-ratio.js", 58 | "mixins/auto-expand.js", 59 | "mixins/closest-selector.js", 60 | "mixins/container-queries.js", 61 | "mixins/parent-selector.js", 62 | "mixins/parent-selector.js", 63 | "mixins/scoped-eval.js", 64 | "mixins/xpath-selector.js" 65 | ] 66 | } 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /min/reprocss.min.js: -------------------------------------------------------------------------------- 1 | /* reproCSS / Tommy Hodgins / MIT License / version 0.0.10 */ 2 | (function(root,factory){if(typeof define==="function"&&define.amd){define([],factory)}else if(typeof module==="object"&&module.exports){module.exports=factory()}else{root.reprocss=factory()}})(this,function(e){var reprocss={};reprocss.count=0;reprocss.style=[];reprocss.load=function(){var tag=document.querySelectorAll("style[process]");for(var i=0;i 2 | 3 | -------------------------------------------------------------------------------- /reprocss.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | # reproCSS 4 | ## version 0.0.10 5 | 6 | reproCSS is a flexible CSS reprocessor that uses ` 16 | 17 | 18 | 19 | 20 | If you are using reproCSS with custom events, you may also optionally use a `selector` attribute specify a list of one or more CSS selectors you would like to add event listeners for. If no `selector` attribute is found all custom events will be applied to window. 21 | 22 | 23 | 24 | To evaluate JavaScript inside the CSS as it's being reprocessed by `reprocss.js` you can use the `${}` interpolation syntax. The following ` 31 | 32 | When the browser is 1000px tall the `${innerHeight}` in our CSS will be output as `500`, leading to the following output: 33 | 34 | 39 | 40 | Currently this plugin only supports ` 68 | 126 | 127 |

Element Queries

128 |

with reproCSS

129 | 130 |

Min-Width

131 |
Min Width (drag to resize)
132 | 133 |

Max-Width

134 |
Max Width (drag to resize)
135 | 136 |

Min-Height

137 |
Min Height (drag to resize)
138 | 139 |

Max-Height

140 |
Max Height (drag to resize)
141 | 142 |

Min-Characters

143 |
Min Characters (type in here)
144 | 145 |

Min-Characters (on form inputs)

146 | 147 | 148 |

Max-Characters

149 |
Max Characters (type in here)
150 | 151 |

Max-Characters (on form inputs)

152 | 153 | 154 |

Min-Children

155 |
Min Children 156 |
157 | 158 | 159 |

Max-Children

160 |
Max Children 161 |
162 | 163 | 164 |

Min-Scroll-X

165 |
166 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Totam distinctio, doloremque, iure magni neque sed natus eveniet, atque tempora aliquid dolores deleniti impedit amet doloribus voluptatibus vel dolorem sit qui.

167 |
168 | 169 |

Max-Scroll-X

170 |
171 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Totam distinctio, doloremque, iure magni neque sed natus eveniet, atque tempora aliquid dolores deleniti impedit amet doloribus voluptatibus vel dolorem sit qui.

172 |
173 | 174 |

Min-Scroll-Y

175 |
176 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Totam distinctio, doloremque, iure magni neque sed natus eveniet, atque tempora aliquid dolores deleniti impedit amet doloribus voluptatibus vel dolorem sit qui.

177 |
178 | 179 |

Max-Scroll-Y

180 |
181 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Totam distinctio, doloremque, iure magni neque sed natus eveniet, atque tempora aliquid dolores deleniti impedit amet doloribus voluptatibus vel dolorem sit qui.

182 |
183 | 184 |

Min-Aspect-Ratio

185 |
(drag to resize)
186 | 187 |

Max-Aspect-Ratio

188 |
(drag to resize)
189 | 190 |

Orientation

191 |
192 | 193 | 308 | 309 | 316 | 317 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![](http://i.imgur.com/HWpgrOP.png) 3 | 4 | # reproCSS 5 | 6 | **A flexible CSS reprocessor using ` 14 | 15 | 16 | 17 | ``` 18 | 19 | If you are using reproCSS with custom events, you may also optionally use a `selector` attribute specify a list of one or more CSS selectors you would like to add event listeners for. If no `selector` attribute is found all custom events will be applied to window. 20 | 21 | ``` 22 | 23 | ``` 24 | 25 | You can add the CSS you want reprocss.js to apply to your HTML in ` 60 | ``` 61 | 62 | When the browser is 1000px tall the `${innerHeight}` in our CSS will be output as `500`, leading to the following output: 63 | 64 | ```html 65 | 70 | ``` 71 | 72 | Currently this plugin only supports ` 92 | ``` 93 | 94 | ### Element Queries via a JS Selector Resolver 95 | 96 | ![](http://i.imgur.com/1mGaC41.png) 97 | 98 | ```html 99 |
100 |

Hello

101 |
102 | 103 | 111 | ``` 112 | 113 | ### JS interpolation in CSS 114 | 115 | ![](http://i.imgur.com/rNZHUXN.png) 116 | 117 | ```html 118 | 119 | 120 | 125 | ``` 126 | 127 | ## Demos 128 | 129 | - [Element Queries with reproCSS](test/element-queries.html) 130 | - [Min/Max Font Size](https://codepen.io/tomhodgins/pen/ZyraEQ) 131 | - [Attribute Values as Numbers](https://codepen.io/tomhodgins/pen/QgQqwx) 132 | - [Regex Search on Attribute Value](https://codepen.io/tomhodgins/pen/MoQmdY) 133 | - [Cursor Tracking](https://codepen.io/tomhodgins/pen/MoQmLY) 134 | - [Scalable Iframe](https://codepen.io/tomhodgins/pen/awqWNz) 135 | - [**View more reproCSS demos on CodePen**](https://codepen.io/search/pens/?q=reprocss) 136 | 137 | ## Mixins 138 | 139 | Writing mixins for reproCSS is easy, any JavaScript function that outputs code that can be used in CSS can be called from anywhere in the stylesheet reproCSS is processing using JS interpolation with `${}`. 140 | 141 | An example of a common mixin template might look like this: 142 | 143 | ```javascript 144 | function mixin(selector, rule) { 145 | 146 | // Find tags in document matching selector 147 | var tag = document.querySelectorAll(selector) 148 | 149 | // Begin with an empty style 150 | var style = '' 151 | 152 | // Begin counting matching tags at 0 153 | var count = 0 154 | 155 | // For each tag matching our selector 156 | for (var i=0; i 500', 'span', 'background: lime;') 267 | ``` 268 | 269 | #### output 270 | 271 | ```css 272 | /* div(this.offsetWidth > 500) span */ 273 | [data-container-unique="0"] span { 274 | background: lime; 275 | } 276 | ``` 277 | 278 | #### demo 279 | 280 | - [Container Queries Mixin Demo](https://tomhodgins.github.io/reprocss/test/container-queries-mixin.html) 281 | 282 | 283 | ### Scoped Eval() Mixin 284 | 285 | This mixin lets you define a CSS selector list, and to output CSS rules with JS interpolation from the context of each element in the document matching the selector. 286 | 287 | #### syntax 288 | 289 | ```javascript 290 | scoped('div', ` 291 | margin: 1em; 292 | background: lime; 293 | height: eval(this.offsetWidth / (16/9))px; 294 | `) 295 | ``` 296 | 297 | #### output 298 | 299 | ```css 300 | /* Scope: div */ 301 | [data-scoped-unique="0"] { 302 | margin: 1em; 303 | background: lime; 304 | height: 144.5625px; 305 | } 306 | ``` 307 | 308 | #### demo 309 | 310 | - [Scoped Eval() Mixin Demo](https://tomhodgins.github.io/reprocss/test/scoped-eval-mixin.html) 311 | 312 | 313 | ### Parent Selector Mixin 314 | 315 | This mixin lets you define a CSS selector list and apply a CSS rule to the parent node of any matching tags in your document. 316 | 317 | #### syntax 318 | 319 | ```javascript 320 | parent('li', 'border: 1px solid red;') 321 | ``` 322 | 323 | #### output 324 | 325 | ```css 326 | /* li:parent */ 327 | [data-parent-unique="0"] { 328 | border: 1px solid red; 329 | } 330 | ``` 331 | 332 | #### demo 333 | 334 | - [Parent Selector Mixin Demo](https://tomhodgins.github.io/reprocss/test/parent-selector-mixin.html) 335 | 336 | 337 | ### Prev Selector Mixin 338 | 339 | This mixin lets you define a CSS selector list and apply a CSS rule to the previous sibling node of any matching tags in your document. 340 | 341 | #### syntax 342 | 343 | ```javascript 344 | prev('li:nth-of-type(2)', 'background: lime;') 345 | ``` 346 | 347 | #### output 348 | 349 | ```css 350 | /* li:prev */ 351 | [data-prev-unique="0"] { 352 | background: lime; 353 | } 354 | ``` 355 | 356 | #### demo 357 | 358 | - [Prev Selector Mixin Demo](https://tomhodgins.github.io/reprocss/test/parent-selector-mixin.html) 359 | 360 | 361 | ### Closest Selector Mixin 362 | 363 | This mixin lets CSS authors apply styles to the nearest element matching a CSS selector to another element matching a given CSS selector. You can use this to find the nearest matching ancestor. 364 | 365 | #### syntax 366 | 367 | ```javascript 368 | closest('#start', '.target', `border-color: lime`) 369 | ``` 370 | 371 | #### output 372 | 373 | ```css 374 | /* #start:closest(.target) */ 375 | [data-closest-unique="0"] { 376 | border-color: lime 377 | } 378 | ``` 379 | 380 | #### demo 381 | 382 | - [Closest Selector Mixin Demo](https://tomhodgins.github.io/reprocss/test/closest-selector-mixin.html) 383 | 384 | 385 | ### Ancestor Selector Mixin 386 | 387 | This mixin lets CSS authors apply styles to all ancestor elements matching a CSS selector to another element matching a given CSS selector. You can use this to style all matching ancestors. 388 | 389 | #### syntax 390 | 391 | ```javascript 392 | ancestor('#start', '.target', `border-color: lime`) 393 | ``` 394 | 395 | #### output 396 | 397 | ```css 398 | /* #start:ancestor(.target) */ 399 | [data-ancestor-unique="0"] { 400 | border-color: lime; 401 | } 402 | ``` 403 | 404 | ## demo 405 | 406 | - [Ancestor Selector Mixin Demo](https://tomhodgins.github.io/reprocss/test/ancestor-selector-mixin.html) 407 | 408 | ### Elder Selector Mixin 409 | 410 | This mixin lets CSS authors apply styles to all elder siblings of elements matching a CSS selector. 411 | 412 | #### syntax 413 | 414 | ```javascript 415 | elder('.target', 'background: lime;') 416 | ``` 417 | 418 | ### output 419 | 420 | ```css 421 | [data-elder-unique="0"] { 422 | background: lime; 423 | } 424 | ``` 425 | 426 | ## demo 427 | 428 | - [Elder Selector Mixin Demo](https://tomhodgins.github.io/reprocss/test/elder-selector-mixin.html) 429 | 430 | > Made with ♥ by [@innovati](http://twitter.com/innovati) -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | reproCSS 5 | 6 | 74 | 75 | 76 | 77 |

reproCSS

78 | 79 |

A CSS reprocessor using <style> tags

80 |

Can you imagine if you could interpolate JS inside CSS with the ${} syntax, and also control when and how frequently that CSS reprocessed with a process="" attribute on the <style> tag:

81 | 82 |
<style process="none"></style>
 83 | <style process="once"></style>
 84 | <style process="auto"></style>
 85 | <style process="touchstart mousedown"></style>
86 | 87 |

If you are using reproCSS with custom events, you may also optionally use a selector attribute specify a list of one or more CSS selectors you would like to add event listeners for. If no selector attribute is found all custom events will be applied to window.

88 | 89 |
<style process="click" selector="#any, .css, [selector]"></style>
90 | 91 |

You can add the CSS you want reprocss.js to apply to your HTML in <style> tags with the following values on the process attribute: 92 | 93 |

    94 |
  • none means no reprocessing 95 |
  • once means process immediately and never again 96 |
  • auto runs every resize, input, and click event on window 97 |
  • any space-separated list of JS events you wish to listen for 98 |
99 | 100 |

How to use reproCSS

101 | 102 |

Github

103 | 104 |

To view reproCSS on Github visit: github.com/tomhodgins/reprocss

105 | 106 |

You can include the reprocss.js JavaScript plugin in your HTML:

107 | 108 |
<script src="reprocss.js"></script>
109 | 110 |

npm

111 | 112 |

If you are using reproCSS on NPM you can include it in your JS modules with a line like this:

113 | 114 |
const reprocss = require('reprocss')
115 | 116 |

How to write reproCSSed CSS

117 | 118 |

To evaluate JavaScript inside the CSS as it's being reprocessed by reprocss.js you can use the ${} interpolation syntax. The following <style> tag would always ensure the <div> in this example was half of the window's height:

119 | 120 |
<style process="auto">
121 |   div {
122 |     height: calc(${innerHeight}px / 2);
123 |   }
124 | </style>
125 | 126 |

When the browser is 1000px tall the ${innerHeight} in our CSS will be output as 500, leading to the following output:

127 | 128 |
<style process="auto">
129 |   div {
130 |     height: calc(500px / 2);
131 |   }
132 | </style>
133 | 134 |

Currently this plugin only supports <style> tags, but it may be possible to support CSS loaded via <link> with a similar technique.

135 | 136 |

Examples

137 | 138 |

Interpolating JS-supplied values in CSS content:;

139 |
<div>Hello</div>
140 | 
141 | <script>
142 |   var user = 'Username'
143 | </script>
144 | 
145 | <style process="once">
146 |   div:after {
147 |     content: ' ${user}';
148 |   }
149 | </style>
150 | 151 |

Element Queries via a JS Selector Resolver

152 |
<div id="demo">
153 |   <p>Hello</p>
154 | </div>
155 | 
156 | <style process="resize">
157 |   ${demo.offsetWidth > 400 && "#demo"} {
158 |     background: lime;
159 |   }
160 |   ${demo.offsetWidth > 400 && "#demo"} p {
161 |     color: red;
162 |   }
163 | </style>
164 | 165 | 166 |

JS interpolation in CSS

167 |
<textarea id="demo"></textarea>
168 | 
169 | <style process="input">
170 |   #demo {
171 |     background: hsl(${demo.value.length}, 50%, 50%)
172 |   }
173 | </style>
174 | 175 |

Demos

176 | 177 | 186 | 187 | 188 |

Mixins

189 | 190 |

Writing mixins for reproCSS is easy, any JavaScript function that outputs code that can be used in CSS can be called from anywhere in the stylesheet reproCSS is processing using JS interpolation with ${}.

191 | 192 |

An example of a common mixin template might look like this:

193 | 194 |
function mixin(selector, rule) {
195 | 
196 |   // Find tags in document matching selector
197 |   var tag = document.querySelectorAll(selector)
198 | 
199 |   // Begin with an empty style
200 |   var style = ''
201 | 
202 |   // Begin counting matching tags at 0
203 |   var count = 0
204 | 
205 |   // For each tag matching our selector
206 |   for (var i=0; i<tag.length; i++) {
207 | 
208 |     // Create an identifier based on the selector used
209 |     var attr = selector.replace(/\W+/g, '')
210 | 
211 |     // Mark tag with a custom attribute containing identifier and count
212 |     tag[i].setAttribute('data-mixin-' + attr, count)
213 | 
214 |     // Add a copy of the CSS rule to the style using a selector for this tag's unique attribute
215 |     style += '\n[data-mixin-' + attr + '="' + count + '"] {\n'
216 |              + '  ' + rule + '\n'
217 |              + '}\n'
218 | 
219 |     // Increment the tag counter by +1
220 |     count++
221 | 
222 |   }
223 | 
224 |   // Return all generated styles as CSS text
225 |   return style
226 | 
227 | }
228 | 229 |

If you were going to create a mixin starting from the template above the first thing you'd want to do is change the function name (currently mixin()) to something unique, as well as update the mentions of mixin inside the mixin logic where it's used to name the elements the mixin is styling, data-mixin-.

230 | 231 |

Once you have changed the name of the function, you can pass a CSS selector or a list of CSS selectors into to the plugin, along with CSS properties and values as a string to be processed and added to new rules. This basic template can be extended in many ways to support different things. Here are some examples of reproCSS mixins and helper functions:

232 | 233 |

Aspect Ratio Mixin

234 | 235 |

This mixin lets you to define an aspect ratio for elements.

236 | 237 |

syntax

238 | 239 |
aspectRatio('iframe', 16/9)
240 | 241 |

output

242 | 243 |
/* iframe { aspect-ratio: 1.77; } */
244 | [data-aspect-ratio-unique=0] {
245 |   height: 503px;
246 | }
247 | 248 |

demo

249 | 250 | 253 | 254 | 255 |

XPath Select Mixin

256 | 257 |

This mixin lets you use XPath as a selector for CSS rules.

258 | 259 |

syntax

260 | 261 |
xpath('//*', `
262 |   border: 1px solid red;
263 | `)
264 | 265 |

outpue

266 | 267 |
/*
268 | 
269 | //* {
270 |   border: 1px solid red;
271 | }
272 | 
273 | */
274 | [data-xpath-unique=0] {
275 |   border: 1px solid red;
276 | }
277 | 278 |

demo

279 | 280 | 283 | 284 |

Auto Expand Mixin

285 | 286 |

This mixin lets you choose between auto-expanding an element's width and height to match its scrollWidth or scrollHeight. Available keywords are width,, height, and both.

287 | 288 |

syntax

289 | 290 |
autoExpand('textarea', 'height')
291 | 292 |

output

293 | 294 |
/* textarea { height: auto-expand; } */
295 | 296 |

demo

297 | 298 | 301 | 302 | 303 |

Container Queries Mixin

304 | 305 |

This mixin lets you define a 'container' using a CSS selector, run a JavaScript test against matching tags that match the container's selector, and to apply a CSS rule to that container or its children.

306 | 307 |

syntax

308 | 309 |
container('div', 'this.offsetWidth > 500', 'span', 'background: lime;')
310 | 311 |

output

312 | 313 |
/* div(this.offsetWidth > 500) span */
314 | [data-container-unique="0"] {
315 |   background: lime;
316 | }
317 | 318 |

demo

319 | 320 | 323 | 324 |

Scoped Eval() Mixin

325 | 326 |

This mixin lets you define a CSS selector list, and to output CSS rules with JS interpolation from the context of each element in the document matching the selector.

327 | 328 |

syntax

329 | 330 |
scoped('div', `
331 |   margin: 1em;
332 |   background: lime;
333 |   height: eval(this.offsetWidth / (16/9))px;
334 | `)
335 | 336 |

output

337 | 338 |
/* Scope: div */
339 | [data-scoped-unique="0"] {
340 |   margin: 1em;
341 |   background: lime;
342 |   height: 144.5625px;
343 | }
344 | 345 |

demo

346 | 347 | 350 | 351 |

Parent Selector Mixin

352 | 353 |

This mixin lets you define a CSS selector list and apply a CSS rule to the parent node of any matching tags in your document.

354 | 355 |

syntax

356 | 357 |
parent('li', 'border: 1px solid red;')
358 | 359 |

output

360 | 361 |
/* li:parent */
362 | [data-parent-unique="0"] {
363 |   border: 1px solid red;
364 | }
365 | 366 |

demo

367 | 368 | 371 | 372 |

Prev Selector Mixin

373 | 374 |

This mixin lets you define a CSS selector list and apply a CSS rule to the previous sibling node of any matching tags in your document.

375 | 376 |

syntax

377 | 378 |
prev('li:nth-of-type(2)', 'background: lime;')
379 | 380 |

output

381 | 382 |
/* li:prev */
383 | [data-prev-unique="0"] {
384 |   background: lime;
385 | }
386 | 387 |

demo

388 | 389 | 392 | 393 |

Closest Selector Mixin

394 | 395 |

This mixin lets CSS authors apply styles to the nearest element matching a CSS selector to another element matching a given CSS selector. You can use this to find the nearest matching ancestor.

396 | 397 |

syntax

398 | 399 |
closest('#start', '.target', `border-color: lime`)
400 | 401 |

output

402 | 403 |
/* #start:closest(.target) */
404 | [data-closest-unique="0"] {
405 |   border-color: lime
406 | }
407 | 408 |

demo

409 | 410 | 413 | 414 |

Ancestor Selector Mixin

415 | 416 |

This mixin lets CSS authors apply styles to all ancestor elements matching a CSS selector to another element matching a given CSS selector. You can use this to style all matching ancestors.

417 | 418 |

syntax

419 | 420 |
ancestor('#start', '.target', `border-color: lime`)
421 | 422 |

output

423 | 424 |
/* #start:ancestor(.target) */
425 | [data-ancestor-unique="0"] {
426 |   border-color: lime;
427 | }
428 | 429 |

demo

430 | 431 | 434 | 435 |

Elder Selector Mixin

436 | 437 |

This mixin lets CSS authors apply styles to all elder siblings of elements matching a CSS selector.

438 | 439 |

syntax

440 | 441 |
elder('.target', 'background: lime;')
442 | 443 |

output

444 | 445 |
[data-elder-unique="0"] {
446 |   background: lime;
447 | }
448 | 449 |

demo

450 | 451 | 454 | 455 | --------------------------------------------------------------------------------