UNPKG

deqaf

Version:

Decaffeinate your CSS stylesheets client-side

288 lines (216 loc) 11 kB
# deqaf Decaffeinate your JS-powered CSS stylesheets client-side > Looking to work with caffeinated stylesheets server-side? Check out [qaffeine](https://github.com/tomhodgins/qaffeine) ## About This project provides a way to parse extended CSS in the browser and separate out the JS-powered styles from ["caffeinated" CSS stylesheets](https://github.com/tomhodgins/caffeinated-style-sheets). This allows you to write CSS stylesheets that include styles supported by JavaScript plugins. ## Plugin Usage This project is provided as an ES module. The easiest way to use deqaf is to import it inside a module: ```html <script type=module> import deqaf from 'https://unpkg.com/deqaf/index.js' deqaf({ stylesheet: {}, rule: {} }) </script> ``` To use deqaf, you can run the function supplying the following argument: ```js deqaf(plugins) ``` - `plugins` is an object containing `stylesheet` and `rule` properties, optionally containing any stylesheet or rule plugins you want to make available to deqaf. ### Defining Plugins To extend CSS with JavaScript functions, the two following possibilities exist: a rule plugin, or a stylesheet plugin. A rule plugin accepts a CSS selector list, as well as any additional options, and lastly takes a CSS declaration list (everything inside the curly brackets `{}` after the selector list. A rule plugin must return a string that is a valid CSS stylesheet. The other type of plugin is a stylesheet plugin, which takes 0 or more optional arguments, as well as one last argument that contains a CSS stylesheet as a string, and returns a string that is a valid CSS stylesheet. If you had a plugin named `example()` that was loaded in the file where you're using deqaf, suppose it looks like this: ```js example(selector, rule) { return Math.random() > .5 ? `${selector} { ${rule} }` : '' } ``` That function would return a rule written for the supplied selector 50% of the time, and return nothing the other 50% of the time. A function like this could be given to deqaf like this: ```js deqaf( { rule: { example } } ) ``` This would loop through the entire CSSOM and process any rules that include `[--example]` in the selector, and would process them with our `example()` plugin. On the other hand if we had a simple stylesheet plugin which takes a CSS stylesheet: ```js function example(stylesheet) { return Math.random() > .5 ? stylesheet : '' } ``` This function would return the supplied stylesheet 50% of the time, and return nothing the other half of the time. We could pass this into deqaf like this: ```js deqaf( { stylesheet: { example } } ) ``` This would process any `@supports` rules that include `--example()` in the condition, and would process them with our `example()` plugin. By supplying plugins to deqaf through this structure we can include rule and stylesheet plugins with the same name, as well as give functions a custom name for our use with deqaf, even if the function has a different name in your JavaScript code. This makes for a flexible and comfortable stylesheet writing experience. > To see an example of a script using deqaf, check out [index.html](https://github.com/tomhodgins/deqaf-demo/blob/master/dist/index.html#L113&L124) from the [deqaf-demo](https://github.com/tomhodgins/deqaf-demo) project ## Writing Extended Selectors for JS-Powered Rules ```css selector, list[--custom='"extended", "selector", "here"'] { } ``` To extend a CSS rule for use with deqaf, add a custom extended selector between the normal selector list and the declaration list, effectively splitting the rule in two: everything before the extended selector is your CSS selector list, and everything after your extended selector is part of the declaration list: ```css selector <HERE> { property: value; } ``` To this location you can add an attribute selector `[]` that's written for any name you want, as long as it starts with a double dash `--`. If we were going to extend a rule with a plugin named `demo()`, we could add `[--demo]`. ```css h1[--demo] { background: lime; } ``` This would allow deqaf to parse out the selector list `h1`, as well as the declaration list `background: lime;`, and write a call to our `demo()` function like this: ```js demo('h1', 'background: lime;') ``` > To see an example of an extended selector deqaf can read, check out [stylesheet.css](https://github.com/tomhodgins/deqaf-demo/blob/master/src/stylesheet.css#L110) from the [deqaf-demo](https://github.com/tomhodgins/deqaf-demo) project: ```css .minwidth[--element='{"minWidth": 300}'] { border-color: limegreen; } ``` ### Defining custom events for extended selectors ```css --selector: ; --events: []; ``` - `--selector` is either `window` or a CSS selector list as a string - `--events` is an array of events quoted as strings The default settings for jsincss (which deqaf uses to run the JS-powered rules it finds) are to listen to the load, resize, input and click events on the window object, so you could think of that like this: ```css [--example] { --selector: window; --events: ["load", "resize", "input", "click"] } ``` Instead, if you wanted a rule to reprocess only on the `paste` event, and only on `<textarea>` elements, you could set custom `--selector` and `--events` like this: ```css [--example] { --selector: "textarea"; --events: ["paste"]; } ``` > To see an example of an extended selector with custom events deqaf can read, check out [stylesheet.css](https://github.com/tomhodgins/deqaf-demo/blob/master/src/stylesheet.css#L297&L298) from the [deqaf-demo](https://github.com/tomhodgins/deqaf-demo) project: ```css .min-scroll-y[--element='{"minScrollY": 50}'] { --selector: ".min-scroll-y"; --events: ["scroll"]; border-color: limegreen; } ``` ## Writing Extended @supports Rules for JS-Powered At-rules ```css @supports --custom('extended', 'at-rule', 'here') { } ``` To extend an `@supports` rule for use with deqaf, add a custom extended selector between the `@supports` text and the group body rule. ```css @supports <HERE> { } ``` To this location you can add any name you want, as long as it starts with a double dash `--`, and ends with a pair of brackets `()`. If we were going to extend a rule with a plugin named `demo()`, we could add `--demo()`. ```css @supports --demo() { html { background: lime; } } ``` This would allow deqaf to parse out the group body rule and write a call to our `demo()` function like this: ```js demo('html { background: lime; }') ``` > To see an example of an extended selector deqaf can read, check out [stylesheet.css](https://github.com/tomhodgins/deqaf-demo/blob/master/src/stylesheet.css#L114) from the [deqaf-demo](https://github.com/tomhodgins/deqaf-demo) project: ```css @supports --element(".minwidth", {"minWidth": 300}) { [--self] { background: greenyellow; } } ``` ### Defining custom events for extended at-rules ```css [--options] { --selector: ; --events: []; } ``` - `[--options]` a custom selector for a rule that we can use to define custom events - `--selector` is either `window` or a CSS selector list as a string - `--events` is an array of events quoted as strings The default settings for jsincss (which deqaf uses to run the JS-powered rules it finds) are to listen to the load, resize, input and click events on the window object, so you could think of that like this: ```css [--options] { --selector: window; --events: ["load", "resize", "input", "click"] } ``` Instead, if you wanted a rule to reprocess only on the `paste` event, and only on `<textarea>` elements, you could set custom `--selector` and `--events` like this: ```css [--options] { --selector: "textarea"; --events: ["paste"]; } ``` > To see an example of an extended at-rule with custom events deqaf can read, check out [stylesheet.css](https://github.com/tomhodgins/deqaf-demo/blob/master/src/stylesheet.css#L313&L316) from the [deqaf-demo](https://github.com/tomhodgins/deqaf-demo) project: ```css @supports --element(".min-scroll-y", {"minScrollY": 50}) { [--options] { --selector: ".min-scroll-y"; --events: ["scroll"]; } [--self] { background: greenyellow; } } ``` ## Known Compatible Stylesheet Plugins - [jsincss-compare-attribute](https://github.com/tomhodgins/jsincss-compare-attribute) - [jsincss-days](https://github.com/tomhodgins/jsincss-days) - [jsincss-element-query](https://github.com/tomhodgins/jsincss-element-query) - [jsincss-overflow](https://github.com/tomhodgins/jsincss-overflow) - [jsincss-protocol-sniffer](https://github.com/tomhodgins/jsincss-protocol-sniffer) - [jsincss-viewport](https://github.com/tomhodgins/jsincss-viewport) - [qaffeine-demo: element query plugin, at-rule edition](https://github.com/tomhodgins/qaffeine-demo/blob/master/src/element-query-at-rule.js) - [css-polyfill-patterns: dynamic values examples, at-rule examples](https://github.com/tomhodgins/css-polyfill-patterns) ## Known Compatible Rule Plugins - [jsincss-ancestor-selector](https://github.com/tomhodgins/jsincss-ancestor-selector) - [jsincss-auto-expand](https://github.com/tomhodgins/jsincss-auto-expand) - [jsincss-closest-selector](https://github.com/tomhodgins/jsincss-closest-selector) - [jsincss-custom-specificity](https://github.com/tomhodgins/jsincss-custom-specificity) - [jsincss-elder-selector](https://github.com/tomhodgins/jsincss-elder-selector) - [jsincss-element-units](https://github.com/tomhodgins/jsincss-element-units) - [jsincss-first-selector](https://github.com/tomhodgins/jsincss-first-selector) - [jsincss-frontend-variables](https://github.com/tomhodgins/jsincss-frontend-variables) - [jsincss-has-selector](https://github.com/tomhodgins/jsincss-has-selector) - [jsincss-last-selector](https://github.com/tomhodgins/jsincss-last-selector) - [jsincss-parent-selector](https://github.com/tomhodgins/jsincss-parent-selector) - [jsincss-previous-selector](https://github.com/tomhodgins/jsincss-previous-selector) - [jsincss-regex-match](https://github.com/tomhodgins/jsincss-regex-match) - [jsincss-scoped-eval](https://github.com/tomhodgins/jsincss-scoped-eval) - [jsincss-string-match](https://github.com/tomhodgins/jsincss-string-match) - [jsincss-xpath-selector](https://github.com/tomhodgins/jsincss-xpath-selector) - [deqaf-demo: element query plugin, selector edition](https://github.com/tomhodgins/deqaf-demo/blob/master/src/element-query-selector.js) - [css-polyfill-patterns: pseudo class examples, simple selector examples](https://github.com/tomhodgins/css-polyfill-patterns) ## More Reading - [Qaffeine walkthrough video](https://www.youtube.com/watch?v=6pRRB1gXgPo) - [Caffeinated Style Sheets talk slides [Web Unleashed 2018]](https://tomhodgins.com/caffeinated-style-sheets.pdf) - [Deqaf demo project](https://github.com/tomhodgins/deqaf-demo) - [Qaffeine demo project](https://github.com/tomhodgins/qaffeine-demo)