Open muratcorlu opened 2 years ago
Love the idea to control component styles based on a custom property.
There's already a discussion on higher level custom properties that might solve the use case.
Container queries could also solve part of the use case: https://github.com/w3c/csswg-drafts/issues/5624#issuecomment-849091911 https://drafts.csswg.org/css-contain-3/#container-rule
my-button {
container: my-button / style;
}
@container my-button style(--size = regular) {
/* styles */
}
@johannesodland Thanks for mentioning other discussion. I couldn't notice it before. I also mentioned my proposal there. For me, other discussion proves a need to set custom variables for web components in a better way. Hopefully, we can have a consensus on a solution.
Another more CSS-familiar syntax would be:
padding: map-get(small 4px 8px, regular 8px 16px, large 12px 24px, var(--size, regular));
Structure above is map-get( mapItem, mapItem, ... , key)
and mapItem is key value
(value is everything until comma). Then maybe this can also allow us using CSS variables for map items too.
:host {
--padding-sizes: small 4px 8px, regular 8px 16px, large 12px 24px;
padding: map-get(var(--padding-sizes), var(--size, regular));
}
This is like the nth-value()
function discussed in https://github.com/w3c/csswg-drafts/issues/5009#issuecomment-626072319
But instead of
my-button {
--size: small;
}
button {
padding: map-get((small: 4px 8px, regular: 8px 16px, large: 12px 24px), var(--size, regular));
}
you would use natural indices:
:root {
--small: 1;
--regular: 2;
--large: 3;
}
my-button {
--size: var(--small);
}
button {
padding: nth-value(
var(--size, var(--regular));
/*small*/ 4px 8px;
/*regular*/ 8px 16px;
/*large*/ 12px 24px
);
}
Interesting approach. That also could solve the problem. The only big problem I see here is that this will require defining many enum-like values (--small: 1
) outside of the web component styles.
@Loirooriol
This is like the
nth-value()
function discussed in #5009 (comment) [snip]
Once we have if()
, we don't need to change the user-facing API to accommodate CSS' limitations, we can just do:
my-button {
--size: small;
}
button {
--size-index: if(--size: small, 1, if(--size: regular, 2, if(--size: large, 3)));
padding: nth-value(--size-index, ...);
}
Though some sugar to make this less painful might be nice.
Nested if
s looks a bit difficult to read and too crowded since you repeat if(--size: {someting}
every time.
In case of using for an index;
--size-index: map-get(small 1, regular 2, large 3, var(--size, regular));
vs
--size-index: if(--size: small, 1, if(--size: large, 3, 2));
I still find mapping values more readable than if conditions.
Even more readable:
--size-map: small 1, regular 2, large 3;
--size-index: map-get(var(--size-map), var(--size, regular));
Once we have map-get
function we don't need to work with indexes though:
:host {
--padding-sizes: small 4px 8px, regular 8px 16px, large 12px 24px;
padding: map-get(var(--padding-sizes), var(--size, regular));
}
Actually, I just remembered that I had defined if()
with the second parameter optional, and it defaults to an empty value. This means you can do it like this:
my-button {
--size: small;
}
button {
--size-index: if(--size: small, 1) if(--size: regular, 2) if(--size: large, 3);
padding: nth-value(--size-index, ...);
}
(I should also change the syntax to use ;
for a separator, so the values can contain commas)
you would use natural indices:
:root { --small: 1; --regular: 2; --large: 3; } my-button { --size: var(--small); } button { padding: nth-value( var(--size, var(--regular)); /*small*/ 4px 8px; /*regular*/ 8px 16px; /*large*/ 12px 24px ); }
With predefined readable indices, this could look something like this:
my-button {
--size: small;
}
button {
padding: choose(
var(--size, medium);
small: 4px 8px;
medium: 8px 16px;
large: 12px 24px
);
}
or even like this:
my-button {
--size: small;
}
button {
padding: choose(
var(--size, medium);
4px 8px;
8px 16px;
12px 24px
);
}
Numerical index | Size | Shirt | Screen | SI | Metric | Lightness |
---|---|---|---|---|---|---|
-2 | tiny |
XS |
watch |
micro |
centi |
darkest |
-1 | small |
S , SM |
mobile , phone |
milli |
deci |
dark |
0 | medium |
M , MD |
tablet |
unity |
unity |
moderate |
1 | large |
L , LG |
laptop |
kilo |
deca , deka |
light |
2 | huge |
XL |
desktop |
mega |
hecto |
lightest |
@index-style size {
-2: XS, extra-small, tiny;
-1: S, SM, small;
0: M, MD, medium;
1: L, LG, large;
2: XL, extra-large, huge;
}
button {
padding: choose(
var(--size, medium) size;
4px 8px; /* =< -1 */
8px 16px; /* == 0 */
12px 24px; /* >= +1 */
);
margin: choose(
var(--size, medium) size;
4px; /* =< 0 */
6px; /* >= +1 */
);
}
I want to start a discussion about having a
map-get
function in CSS like in older versions of SASS.Need:
When we use HTML Custom Elements (a.k.a Web Components), Shadow DOM is a powerful opportunity to isolate components style, and using CSS Custom Properties (a.k.a. CSS Variables) for customizing components styles is a very convenient approach. But in some scenarios, we are very limited in providing some good limited options to our component consumers as a component developer.
For example;
I want to provide a
button
component that can be in a limited set of sizes regarding our design system. So we have variants likelarge
,regular
orsmall
. Currently, many people use component attributes like<my-button small>
but this is not an ideal way when you think about a responsive design. Instead, I would prefer to be able to say:To be able to have that kind of clean solution we need to have a solution to map this
small
naming to a different type of units inside component styles.Proposal
As in old
map-get
function of SASS, having an opportunity to set a value by picking from a map would be great like:Means: regarding to value of
--size
variable (regular
by default) set padding to4px 8px
if value issmall
.So a consumer can not set the padding of my button component other than the options that I set here. Also a consumer can customize this property with a responsive design approach:
This can be also used as conditional values for non size units:
Means: regarding to value of
--variant
variable (primary
by default) set background-color to#006600
if value issecondary
.So, the structure is
map-get( (mapObject), key )
I'm not sure what is the best format for defining a map in CSS with current technical background, but JSON-likekey: value,
structure would be very familiar for many front-end developers.I hope I could express the motivation very well. Any ideas and questions to clarify details are very welcome.