[css-custom-functions] user-defined custom CSS functions
Nobody has claimed this yet.
- Dominant language
- Bikeshed
- Stars
- 1.9k
- Forks
- 149
- PR merge metrics
- No merged PRs in 30d
Description
I wish there was a way to make re-usable CSS "functions".
Currently, we can't make re-usable logic without unfortunately coupling to HTML markup. See:
- https://stackoverflow.com/questions/63459791/why-do-these-css-variables-not-work-when-passed-into-calc
- https://stackoverflow.com/questions/52015737/css-scoped-custom-property-ignored-when-used-to-calculate-variable-in-outer-scop
As you can tell from those pages, in order to make re-usable expressions ("functions"), we must couple the re-usability to the HTML markup, which is not ideal.
It would be great to be able to create re-usable logic/functions in a way that does not require a CSS author to ever touch any HTML code.
How might an proposal syntax look like, to work around the current limitation?
Perhaps:
:root {
--sum: function( calc( var(--a) + var(--b) ) )
}
/* Then anywhere in any CSS rules, without dependence on HTML markup: */
.foo.bar.whatever {
--a: 4px; --b: 6px;
font-size: call(--sum);
}
^ In that example, the user does not have to worry about "evaluating CSS variables at the level where they are needed" (which requires the CSS author to touch the HTML markup as shown by @Afif13's nicely-written answer in the second SO question).
There's probably a bunch of other ways we could do it.
Here's another idea for sake of spinning up some ideas:
:root {
--sum: function(--a, --b, calc( arg(--a) + arg(--b) ) )
}
/* Then anywhere in any CSS rules, without dependence on HTML markup: */
.foo.bar.whatever {
font-size: call(--sum, 4px, 6px);
}
Or, maybe we can create a new special type of block (it may be cleaner):
@function sum(a, b) {
return: calc(arg(a) + arg(b))
}
/* Then anywhere in any CSS rules, without dependence on HTML markup: */
.foo.bar.whatever {
font-size: sum(4px, 6px);
}
/* Maybe `call()` or similar is required to distinguish from builtins? */
.foo.bar.whatever {
font-size: call(sum, 4px, 6px);
}
Maybe functions can also return a rule expression, which could be "mixed" onto a rule (not sure about syntax though):
@function foo(a, b, c) {
return {
background: a b c;
}
}
.whatever {
call(foo, lightblue, url("foo.gif"), no-repeat); /* How to handle commas? */
color: red;
}
results in equivalent of
.whatever {
background: lightblue url("foo.gif") no-repeat;
color: red;
}
or something.
With @function, maybe the return just has to match the context where the function is being used. For example in the previous two examples we saw it used to return a property value, and to return a rule that is mixed in the rule where it is used.
Maybe we could also use it at the top level to create top-level rules (not sure about the particular syntax, probably someone with CSS implementation expertise can weigh in):
@function makeKeyframes(name, a, b, c) {
@keyframes arg(name) { ... something here ... what are a, b and c? ... }
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the issue's proposed custom-property, call(), and @function syntax examples and the linked discussions about CSS variable scoping. Done means reaching an agreed proposal for reusable CSS logic that does not require HTML coupling, including how value and rule results, arguments, and top-level rules should work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- css
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100