css-inherit-fn logo

css-inherit-fn

Enables you to write CSS that can inherit and iterate on --vars with ZERO runtime JS.
--var: calc(inherit(--var, 0) + 1);
Less and Sass `buildInherit()` mixins compile to vanilla CSS.

Not using Less or Sass and still want to play? That's okay!
Also included are options for a global JS function or an ES6 Module that expose the same `buildInherit()` function.

Whatever your setup is, you can start inherit()ing CSS vars today 🎉

npm install css-inherit-fn


User Reach

At the time of writing, css-inherit-fn has 89.37% global user reach.
(According to data from caniuse.com) The limiting factors are:
The :where() selector (89.37%),
followed closely by the Level 4 :not() selector (90.87%).


Importing and Calling buildInherit()

npm install css-inherit-fn




Using Less
@import (reference) "/node_modules/css-inherit-fn/_less-inherit";

.buildInherit(
  ...
);
Bonus: Since Less is awesome, you can skip the install for small projects and fun CodePen demos by importing directly from your favorite CDN:
@import (reference) "https://unpkg.com/css-inherit-fn/_less-inherit.less"; Please tweet @ me if you use it in a CodePen! I'd love to see!




Using Sass
@import "/node_modules/css-inherit-fn/_sass-inherit";

@include buildInherit(
  ...
);
Bogus: Sass cannot @import (or @use) mixins from external sources. ;(




Using ES6 Module
<script type="module">
  import { buildInherit } from "css-inherit-fn/css-inherit.js"
  const style = document.createElement("style")
  style.innerHTML = buildInherit(
    ...
  )
  document.head.appendChild(style)
</script>
Bonus: You could import directly from your favorite CDN instead of installing:
import { buildInherit } from "https://unpkg.com/css-inherit-fn/css-inherit.js"




Using a Global JS function
<script src="https://unpkg.com/css-inherit-fn/css-inherit.global.js">
  // adds "cssInherit" global variable with the "buildInherit" function attached
</script>
<script>
  const style = document.createElement("style")
  style.innerHTML = cssInherit.buildInherit(
    ...
  )
  document.head.appendChild(style)
</script>


buildInherit() Parameters

buildInherit() parameters are the same no matter what enviornment you're using it in.

1. The first parameter is a string that takes a simple selector (such as a single ".className" or element tag like "div").
(Technically it can be anything but you really should limit this to a simple selector.)
This selector is the facilitator that connects ancestors to descendants. Elements matching the selector do not have to be directly nested in each other for the hand-off inherit()ing to work.

2. The second parameter is an intenger setting the maximum depth the selector will allow.
For example, if our selector is '.hi', the max depth needed to inherit() in this chain is 4:
html > body.hi > main > section.hi > div.hi > p > span > i.hi A value of 6 or 7 is probably sufficient for most uses, I wouldn't expect needing more than 16 unless you're doing something artistic/for fun.
No matter what value though, buildInherit() compiles into two selectors (even vs odd nesting depth).

3. The remaining parameters are any number of strings, one at a time, that assign a --css-var and might call `inherit()` to compute its value.
For example: (
  '.hue',
  12,
  '--hue: calc(inherit(--hue, 0deg) + 30deg)'
)
or (
  '.swap',
  6,
  '--bg: inherit(--fg, black)',
  '--fg: inherit(--bg, white)'
)
Only vars assigned within the call to buildInherit() are available for inherit()ing, but they do not necessarily need to inherit in their own value: (
  '.griddy',
  16,
  '--grandcontainer-width: inherit(--container-width, 100vw)',
  '--container-width: inherit(--width, 100vw)',
  '--width: calc(var(--container-width) * var(--portion, 1))'
)

...

.griddy.sm { /* normal CSS, outside of the buildInherit call */
  --portion: 0.25;
}
.griddy.md {
  --portion: 0.333;
}
.griddy.lg {
  --portion: 0.5;
}
.griddy.aspect16-9 {
  height: calc(var(--width) / 16 * 9);
}
.griddy
  --cqw: calc(var(--container-width) / 100);
  --ownw: calc(var(--width) / 100);
}
.griddy.fullscreen {
  --width: 90vw; /* .griddy descendants of .griddy.fullscreen will have a --container-width of 90vw */
}


Playground Time!

Hue += 30deg, animated at the root

Sass cannot @import (or @use) mixins from external sources so no live demos. ;(
Rest assured, Sass tests are passing. In any case, here's what the Sass code would look like if you set this up locally:
@import "/node_modules/css-inherit-fn/_sass-inherit";

@include buildInherit(
  '.hue',
  12,
  '--hue: calc(inherit(--hue, 0deg) + 30deg)'
);

The rest of the CSS and markup is the same across enviornments.



Swapping FG/BG Lightness Values

Swapping mentioned here




Auto Cumulative Nested Sticky Headers w/auto reverse z-index

Source of this idea




Have an idea that would make a great example here?
Please send me a tweet or DM for consideration!