Given this css code
:root {
--color: #aaa;
--bg-color: var(--color);
--narrow-window-width: 30em;
}
body {
background: var(--bg-color);
}
@custom-media --narrow-window (max-width: var(--narrow-window-width));
@media (--narrow-window) {
body {}
}
Would like to extract computed values of custom properties definitions:
{
"custom-properties": {
"color": "#aaa",
"bg-color": "#aaa",
},
"custom-media-queries": {
"narrow-window-width": "30em"
}
}
We can of cause solve the problem with external values:
var color = "#aaa";
var props = {
"color": color,
"bg-color": color
},
cssnext(cssString, {
features: { variables: props }
});
However, it doesn't scale well when the dependencies between values is deep:
var pageWidth = 960;
var sidebarWidth = pageWidth / 3;
var sidebarSearchWidth = sidebarWidth * 0.8;
var sidebarSearchButtonWidth = sidebarSearchWidth * 0.2;
var props = {
"page-width": `${pageWidth}`px,
"sidebar-width": `${sidebarWidth}px`,
"sidebar-search-width": `${sidebarSearchWidth}px`
"sidebar-search-button-width": `${sidebarButtonWidth}px`
},
The amount of bolierplate code is huge, comparing writing them directly in css:
:root {
--page-width: 960px;
--sidebar-width: calc(var(--page-width) / 3);
--sidebar-search-width: calc(var(--sidebar-width) * 0.8);
--sidebar-search-button-width: calc(var(--sidebar-search-width) * 0.2);
}
We leave the custom properties/custom media queries defintions in ast, and when cssnext done processing the ast, we extract values from these definitions. The processed ast should equivalent to this
:root {
--color: #aaa;
--bg-color: #aaa;
--narrow-window-width: 30em;
}
body {
background: #aaa;
}
@custom-media --narrow-window (max-width: 30em);
@media (max-width: 30em) {
body {}
}
We then iterate over :root
rules and @custom-media
rules to extract the values.
postcss-custom-properties offers a preserve
option, but it duplicates definitions, and postcss-custom-media doesn't offer such feature. Currently enabling the option compiles (or is supposed to compile) to this:
:root {
--color: #aaa;
--bg-color: #aaa;
--bg-color: var(--color);
--narrow-window-width: 30em;
}
body {
background: #aaa;
background: var(--bg-color);
}
@media (max-width: 30em) {
body {}
}
The duplication can be solved by only using the last custom properties definition of that name that doesn't contain var()
. For postcss-custom-media, we need to implement a similar option that compiles this:
@custom-media --narrow-window (max-width: 30em);
@media (--narrow-window) {
body {}
}
to this
@custom-media --narrow-window (max-width: 30em);
@media (max-width: 30em) {
body {}
}
That is, not removing the definition.
postcss-custom-properties currently doesn't resovle var()
usages in media queries (custom or regular), so we need to add that. Also we add the preserve
option to postcss-custom-media. Enabling these options should yield:
:root {
--color: #aaa;
--bg-color: #aaa;
--bg-color: var(--color);
--narrow-window-width: 30em;
}
body {
background: #aaa;
background: var(--bg-color);
}
@custom-media --narrow-window (max-width: 30em);
@custom-media --narrow-window (max-width: var(--narrow-window-width));
@media (max-width: 30em) {
body {}
}
@media (--narrow-window) {
body {}
}
As you can see, this could potentially result in duplicating much code (especially by duplicating media rules, not to mention it might compound with prefixes) without bringing any real benefits (browsers support custom-* features always compute to the same value, if the value is directly resolvable). We can either keep that, or introduce a break change, making preserve
option not to keep the specified value:
:root {
--color: #aaa;
--bg-color: #aaa;
--narrow-window-width: 30em;
}
body {
background: #aaa;
}
@custom-media --narrow-window (max-width: 30em);
@media (max-width: 30em) {
body {}
}
This means preserve
simply preserves definitions. Users who want to retain the specified values should simply disable the plugins. I doubt the var()
fallback brings any real benefits.
Another thing to fix is that postcss-custom-properties currently choke on infinite variable referencing:
:root {
--color: var(--color);
--bg-color: var(--bg2-color);
--bg-color: var(--bg-color);
}
It should detect this and throw an error. This can be fixed by caching resolved values. It should also greatly speed up resolving process, since every value is now only resolved once.
Have a look at https://github.com/WolfgangKluge/postcss-media-variables