0.2.0 • Published 1 year ago

postcss-logical-property-polyfill v0.2.0

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

postcss-logical-property-fallbacks

PostCSS plugin that will polyfill inset-inline-(start|end) and border-(start|end)-(start|end)-radius in older browsers that don't support them. The polyfill works by leveraging CSS variables, and works for sub-trees and not just globally..

Vendor Prefixes for margin, padding and border

Input:

.foo {
  margin-inline-start: 10px;
}

Output:

.foo {
  -webkot-margin-start: 10px;
  margin-inline-start: 10px;
}

CSS variable based polyfill for inset-inline and border-radius

Input:

.foo {
  inset-inline-end: 10px;
}
.bar {
  inset-inline-start: 5px;
}

Output:

* {
  --x-inset-inline-end: initial;
  --x-inset-inline-start: initial;
}
[dir="ltr"],
html:not([dir="rtl"]) {
  --logical-polyfill-0-ltr: 10px;
  --logical-polyfill-1-ltr: 5px;
  --logical-polyfill-0-rtl: initial;
  --logical-polyfill-1-rtl: initial;
}
[dir="rtl"] {
  --logical-polyfill-0-ltr: initial;
  --logical-polyfill-1-ltr: initial;
  --logical-polyfill-0-rtl: 10px;
  --logical-polyfill-1-rtl: 5px;
}
@supports not (inset-inline-end: 0) {
  .foo {
    --x-inset-inline-end: 10px;
    left: var(--logical-polyfill-0-rtl, var(--x-inset-inline-start));
    right: var(--logical-polyfill-0-ltr, var(--x-inset-inline-start));
  }
}
.foo {
  inset-inline-end: 10px;
}
@supports not (inset-inline-start: 0) {
  .bar {
    --x-inset-inline-start: 5px;
    left: var(--logical-polyfill-1-ltr, var(--x-inset-inline-end));
    right: var(--logical-polyfill-1-rtl, var(--x-inset-inline-end));
  }
}
.bar {
  inset-inline-start: 5px;
}

How does this actually work?

Whenever you use inset-inline-(start|end) or border-(start|end)-(start|end)-radius, a pair of CSS variables are generated --var-name-ltr and --var-name-rtl. Based on the current writing mode, only one of these two variables will ever have a value.

Then we can simply use both the physical properties with the respective variables and get the desired result:

left: var(
  --logical-polyfill-1-ltr
); /* Has an effect in LTR only, the variable is "undefined" in RTL */
right: var(
  --logical-polyfill-1-rtl
); /* Has an effect in RTL only, the variable is "undefined" in LTR */

However, this limits us to having a value for just ONE of the two sides. "left" or "right", but not both.

In order to be able to support inset-inline-start and inset-inline-end we need a fallback CSS variable for the values.

/* inset-inline-start: */
--inset-inline-start: 10px;
left: var(
  --logical-polyfill-1-ltr,
  var(--inset-inline-end)
); /* this property is overridden and has no effect */
right: var(
  --logical-polyfill-1-rtl,
  var(--inset-inline-end)
); /* this property is overridden and has no effect */

/* inset-inline-end: */
--inset-inline-end: 10px;
left: var(--logical-polyfill-2-rtl, var(--inset-inline-start));
/* In RTL, it takes the first value, in LTR, it takes the second value */
right: var(--logical-polyfill-2-ltr, var(--inset-inline-start));
/* In LTR, it takes the first value, in RTL, it takes the second value */

Now, although the left and right properties that were generated from the inset-inline-start property have no effect, (Since there are more left and right properties generated from inset-inline-end) the --inset-inline-start variable is used as the fallback value for either left or right, whichever property should not currently have a size based on the direction.

Additional Utility CSS variables available:

In addition to the CSS variables generated for inset-inline-(start|end) properties, a few CSS variables are always injected that can be used in-place of "logical" values.

[dir="ltr"],
html:not([dir="rtl"]) {
  --is-ltr: 1;
  --is-rtl: 0;
  --start: left;
  --end: right;
  --inline-unit: 1;
}
[dir="rtl"] {
  --is-ltr: 0;
  --is-rtl: 1;
  --start: right;
  --end: left;
  --inline-unit: -1;
}

Usage

Step 1: Install plugin:

npm install --save-dev postcss postcss-logical-property-fallbacks

Step 2: Check you project for existed PostCSS config: postcss.config.js in the project root, "postcss" section in package.json or postcss in bundle config.

If you do not use PostCSS, add it according to official docs and set this plugin in settings.

Step 3: Add the plugin to plugins list:

module.exports = {
  plugins: [
+   require('postcss-logical-property-fallbacks'),
    require('autoprefixer')
  ]
}