JSPM

  • Created
  • Published
  • Downloads 188910
  • Score
    100M100P100Q183664F
  • License MIT

A ponyfill that provides client-side support for CSS custom properties (aka "CSS variables") in legacy browsers

Package Exports

  • css-vars-ponyfill
  • css-vars-ponyfill/dist/css-vars-ponyfill.esm.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (css-vars-ponyfill) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

css-vars-ponyfill

NPM Build Status Codacy grade Codecov License: MIT Tweet

A ponyfill that provides client-side support for CSS custom properties (aka "CSS variables") in legacy browsers.



Features

  • Client-side transformation of CSS custom properties to static values
  • Live updates of runtime values in both modern and legacy browsers
  • Transforms <style>, <link>, and @import CSS
  • Supports chained custom property references
  • Supports complex values
  • Supports fallback values
  • UMD and ES6 module available
  • Lightweight (less than 5k min+gzip) and dependency-free

Limitations

  • Custom property support is limited to :root declarations
  • The use of var() is limited to property values (per W3C specification)

Browser Support

IE Edge Chrome Firefox Safari
9+ 12+ 19+ 6+ 6+

Installation

NPM:

npm i css-vars-ponyfill

Git:

git clone https://github.com/jhildenbiddle/css-vars-ponyfill.git

CDN (unpkg or jsdelivr):

<!-- Minified UMD (latest v1.x.x) -->
<script src="https://unpkg.com/css-vars-ponyfill@1"></script>

Examples

JavaScript (see Options):

import cssVars from 'css-vars-ponyfill';

// Call using defaults
cssVars();

// Or call with options
cssVars({
  // ...
});

HTML:

<head>
  <!-- External CSS -->
  <link rel="stylesheet" href="style.css">

  <!-- Local CSS -->
  <style>
    :root {
      --color: black;
    }
  </style>
</head>

External CSS:

/* File: style.css */
:root {
  /* Chained references */
  --a: var(--b);
  --b: var(--c);
  --c: 10px;
}

div {
  color: var(--color);

  /* Fallback */
  margin: var(--unknown, 20px));

  /* Complex value */
  padding: calc(2 * var(--a));
}

Transformed CSS prepended to <head>:

<style id="css-vars-ponyfill">
  div {
    color: black;
    margin: 20px;
    padding: calc(2 * 10px);
  }
</style>

To update values, call cssVars() with options.variables specified...

cssVars({
  variables: {
    color: 'red',
    unknown: '5px'
  }
});

… and the previously transformed CSS is updated with new values.

<style id="css-vars-ponyfill">
  div {
    color: red;
    margin: 5px;
    padding: calc(2 * 10px);
  }
</style>

Options

Example

// Default values shown
cssVars({
  include   : 'link[rel=stylesheet],style',
  exclude   : '',
  onlyLegacy: true,
  onlyVars  : true,
  preserve  : false,
  silent    : false,
  updateDOM : true,
  variables : {
    // ...
  },
  onSuccess(cssText) {
    // ...
  },
  onError(message, node) {
    // ...
  },
  onWarning(message) {
    // ...
  },
  onComplete(cssText, styleNode) {
    // ...
  }
});

options.include

  • Type: string
  • Default: "link[rel=stylesheet],style"

CSS selector matching <link rel="stylesheet"> and <style> nodes to process. The default value includes all style and link nodes.

Example

cssVars({
  // Include only <link rel="stylesheet"> nodes
  // with an href that does not contains "bootstrap"
  include: 'link[rel=stylesheet]:not([href*=bootstrap])'
});

options.exclude

  • Type: string
  • Default: none

CSS selector matching <link rel="stylesheet"> and <style> nodes to exclude from those matched by options.include.

Example

cssVars({
  // Of matched 'include' nodes, exclude any node
  // with an href that contains "bootstrap"
  exclude: '[href*=bootstrap]'
});

options.onlyLegacy

  • Type: boolean
  • Default: true

Determines if the ponyfill will only generate legacy-compatible CSS in browsers that lack native support (i.e., legacy browsers).

When true, the ponyfill will only generate legacy-compatible CSS, trigger callbacks, and (optionally) update the DOM in browsers that lack native support. When false, the ponyfill will treat all browsers as legacy, regardless of their support for CSS custom properties.

Example

cssVars({
  onlyLegacy: true // default
});

options.onlyVars

  • Type: boolean
  • Default: true

Determines if CSS rulesets and declarations without a custom property value should be removed from the transformed CSS.

When true, rulesets and declarations without a custom property value will be removed from the generated CSS, reducing CSS output size. When false, all rulesets and declarations will be retained in the generated CSS.

Note: @font-face and @keyframes require all declarations to be retained if a CSS custom property is used anywhere within the ruleset.

Example

CSS:

:root {
  --color: red;
}
h1 {
  font-weight: bold;
}
p {
  margin: 20px;
  padding: 10px;
  color: var(--color);
}

JavaScript:

cssVars({
  onlyVars: true // default
});

Output when onlyVars: true

p {
  color: red;
}

Output when onlyVars: false

h1 {
  font-weight: bold;
}
p {
  margin: 20px;
  padding: 10px;
  color: red;
}

options.preserve

  • Type: boolean
  • Default: false

Determines if the original CSS custom property declaration will be retained in the transformed CSS.

When true, the original custom property declarations are available in the transformed CSS along with their static values. When false, only static values are available in the transformed CSS.

Example

CSS:

:root {
  --color: red;
}
p {
  color: var(--color);
}

JavaScript:

cssVars({
  preserve: false // default
});

Output when preserve: false

p {
  color: red;
}

Output when preserve: true

:root {
  --color: red;
}
p {
  color: red;
  color: var(--color);
}

options.silent

  • Type: boolean
  • Default: false

Determines if warning and error messages will be displayed on the console.

When true, messages will be displayed on the console for each warning and error encountered while processing CSS. When false, messages will not be displayed on the console but will still be available using the options.onWarning and options.onSuccess callbacks.

Example

CSS:

@import "fail.css"

p {
  color: var(--fail);
}

p {
  color: red;

JavaScript:

cssVars({
  silent: false // default
});

Console:

> CSS XHR error: "fail.css" 404 (Not Found)
> CSS transform warning: variable "--fail" is undefined
> CSS parse error: missing "}"

options.updateDOM

  • Type: boolean
  • Default: true

Determines if the ponyfill will update the DOM after processing CSS custom properties.

When true, legacy browsers will have a <style> node with transformed CSS prepended to the <head>, while browsers with native support will apply options.variables custom properties using the native style.setProperty() method. When false, the DOM will not be updated by the polyfill in either modern or legacy browsers, but transformed CSS can be accessed with either the options.onSuccess or options.onComplete callback.

Example

HTML:

<head>
  <title>Title</title>
  <link rel="stylesheet" href="style.css">
</head>

JavaScript:

cssVars({
  updateDOM: true // default
});

Result when updateDOM: true

<head>
  <title>Title</title>
  <style id="css-vars-ponyfill">
    /* Transformed CSS ... */
  </style>
  <link rel="stylesheet" href="style.css">
</head>

options.variables

  • Type: object
  • Default: {}

A map of custom property name/value pairs. Property names can omit or include the leading double-hyphen (--), and values specified will override previous values.

Legacy browsers will process these values while generating legacy-compatible CSS. Modern browsers with native custom property support will apply these values using the native setProperty() method when options.updateDOM is true.

Example

cssVars({
  variables: {
    color1    : 'red',
    '--color2': 'green'
  }
});

options.onSuccess

  • Type: function
  • Arguments:
    1. cssText: A string of CSS text from node and url

Callback after all CSS has been processed and legacy-compatible CSS has been generated, but before the legacy CSS has been appended to the DOM. Allows modifying the CSS data by returning any string value (or false to skip) before options.onComplete is triggered.

Example

const beautifyCss = require('js-beautify').css;

cssVars({
  onSuccess(cssText, node, url) {
    // Beautify CSS
    return beautifyCss(cssText);
  }
});

options.onError

  • Type: function
  • Arguments:
    1. message: The error message
    2. node: The source node object reference
    3. xhr: The XHR object containing details of the failed request
    4. url: The source URL string (<link> href or @import url)

Callback after a CSS parsing error has occurred or an XHR request has failed.

Example

HTML:

<link rel="stylesheet" href="path/to/fail.css">

JavaScript:

cssVars({
  onError(message, node, xhr) {
    console.log(message); // 1
    console.log(node); // 2
    console.log(xhr.status); // 3
    console.log(xhr.statusText); // 4
    console.log(url); // 5
  }
});

// 1 => 'CSS XHR error: "fail.css" 404 (Not Found)'
// 2 => <link rel="stylesheet" href="path/to/fail.css">
// 3 => '404'
// 4 => 'Not Found'
// 5 => 'path/to/fail.css'

options.onWarning

  • Type: function
  • Arguments:
    1. message: The warning message

Callback after each CSS parsing warning has occurred.

Example

CSS:

p {
  color: var(--fail);
}

JavaScript:

cssVars({
  onWarning(message) {
    console.log(message); // 1
  }
});

// 1 => 'CSS transform warning: variable "--fail" is undefined'

options.onComplete

  • Type: function
  • Arguments:
    1. cssText: A string of concatenated CSS text from all nodes in DOM order
    2. styleNode: An object reference to the appended <style> node

Callback after all CSS has been processed, legacy-compatible CSS has been generated, and (optionally) the DOM has been updated.

Example

cssVars({
  onComplete(cssText, styleNode) {
    // ...
  }
});

Attribution

This ponyfill includes code based on the following projects. Many thanks to the authors and contributors for helping to make this project possible.

Contact

License

This project is licensed under the MIT License. See the LICENSE for details.