A CSS reprocessor using <style>
tags
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:
<style process="none"></style> <style process="once"></style> <style process="auto"></style> <style process="touchstart mousedown"></style>
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.
<style process="click" selector="#any, .css, [selector]"></style>
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:
none
means no reprocessing
once
means process immediately and never again
auto
runs every resize
, input
, and click
event on window
To view reproCSS on Github visit: github.com/tomhodgins/reprocss
You can include the reprocss.js
JavaScript plugin in your HTML:
<script src="reprocss.js"></script>
If you are using reproCSS on NPM you can include it in your JS modules with a line like this:
const reprocss = require('reprocss')
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:
<style process="auto"> div { height: calc(${innerHeight}px / 2); } </style>
When the browser is 1000px tall the ${innerHeight}
in our CSS will be output as 500
, leading to the following output:
<style process="auto"> div { height: calc(500px / 2); } </style>
Currently this plugin only supports <style>
tags, but it may be possible to support CSS loaded via <link>
with a similar technique.
content:;
<div>Hello</div> <script> var user = 'Username' </script> <style process="once"> div:after { content: ' ${user}'; } </style>
<div id="demo"> <p>Hello</p> </div> <style process="resize"> ${demo.offsetWidth > 400 && "#demo"} { background: lime; } ${demo.offsetWidth > 400 && "#demo"} p { color: red; } </style>
<textarea id="demo"></textarea> <style process="input"> #demo { background: hsl(${demo.value.length}, 50%, 50%) } </style>
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 ${}
.
An example of a common mixin template might look like this:
function mixin(selectorList, rule) { // Find all tags in document matching selector list var tag = document.querySelectorAll(selectorList) // Start with an empty string for the style var style = '' // Being counting tags at 0 var count = 0 // For each tag in the document matching our selector list for (var i = 0; i < tag.length; i++) { // Create an identifier based on the selector var attr = btoa(selectorList).replace(/=/g, '') // Mark tag with the name of our mixin, the identifier, and tag count tag[i].setAttribute('data-mixin-' + attr, count) // Add a new CSS rule based on the attribute and supplied CSS to our style style += '\n[data-mixin-' + attr + '="' + count + '"] {\n' + ' ' + rule + '\n' + '}\n' // Increment the tag counter count++ } // return all generated styles for the tag(s), selector(s), and rule(s) given return style }
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-
.
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:
This mixin allows you to define an aspect ratio for elements.
${aspectRatio('iframe', 16/9)}
/* aspectRatio(iframe, 1.77) */ [data-aspect-ratio-unique=0] { height: 503px; }
This mixin allows you to use XPath as a selector for CSS rules.
${xpath('//*', ` border: 1px solid red; `)}
/* //* { border: 1px solid red; } */ [data-xpath-unique=0] { border: 1px solid red; }
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
.
${autoExpand('textarea', 'height')}
/* autoExpand('textarea', 'height') */
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.
${container('div', 'this.offsetWidth > 500', 'span', 'background: lime;')}
/* div: this.offsetWidth > 500 */ [data-container-unique="0"] { background: lime; }