##What if we create extend/composes instead of @apply?
syntaxes flavour:
/* 1) similar to pseudo selector :not(.class) */
.class-a:extend(.class-b) {}
.class-a:composes(.class-b, .class-c) {}
/* 2) property style */
.class-a {
extend: .class-b;
}
.class-a {
composes: .class-b, .class-c;
}
.class-a {
extend: eval(.class-b); /* in case browser need to use function to evaluate class like with css custom properties */
}
/* 3) similiar to :before & :after */
.class-a:extend {
content: eval(.class-b, .class-c);
}
happy to hear any suggestions.
I am going for the first option because:
pros
- it resemble :not(), this pseudo selector use selector as parameters
- pseudo classes has multiple purposes like :before add an element
- it resemble js extend:
cons
- maybe it increase specificity because is a pseudo selector
class Person extend Animal {}
.Person:extend(.Animal) {}
The main goal of this new feature are:
- non deterministic resolution
- reuse style, creating pattern
- no need to worry about specificity
- abstract css into css instead of html, create one source of truth and avoid dependency hell in html
- reduce css file size
Extending classes on html is dangerous, it creates an invisible amount of dependency and depend on css code order and specificity. On big code base changing classes on html, changing order of your css, changing css specificity are all possible cause of breaking something somewhere. Extend does not rely on code order or specificity and allow to abstract your css inside css not in html.
How does it work
When the browser parse this selector will create a .class-a CSS object
.class-a:extend(.class-b) {
width: 100px;
background-color: orange;
}
output =>
{
width: 100px;
background-color: orange;
}
When the CSS parser reach .class-b definition create an object and .class-a it will referenced it
.class-b {
font-size: 12;
color: red;
}
output =>
{
font-size: 12;
color: red;
}
/* now this selector will add .class-b styles */
.class-a:extend(.class-b) {
width: 100px;
background-color: orange;
}
output =>
{
font-size: 12;
color: red;
width: 100px;
background-color: orange;
}
The properties do not depend on code order or specificity. When class-b is parsed class-a will reference class-b.
specificity back again
the only case specificity matter again if you write something like this:
<div class="class-a class-b">
but you do not need to because this is enough
<div class="class-a">
note:
If :extend is increasing the specificity because is a pseudo selector I would prefer to use a property.
.class {
extend: eval(.class-b, .class-c);
}
long selector or multiple selector
.long selector #ciao .class-a:extend(.class-b) {}
.class-a:extend(.long selector #ciao .class-b) {}
.class-a:extend(.long selector #ciao .class-b, .long selector #ciao .class-c) {}
/* but it's better if you use single selector */
.class-a:extend(.class-b, .class-c) {}
extend(.first, .second) order matter
the order you define your classes inside the extend() matter but that can be useful to decide which pattern need to overwritten without depending of code order or specificity
.class-b { color: tomato; }
.class-c { width: 100px; }
.class-a:extend(.class-b, .class-c) {
font-family: Arial;
}
output =>
{
color: tomato;
width: 100px;
font-family: Arial;
}
inheritance of custom properties
you can inherit custom properties from the other classes
.class-a:extend(.class-b, .class-c) {
font-family: Arial;
}
.class-b { color: var(--b-color, red) }
.class-a {
--color-b: tomato;
}
output =>
{
color: var(--b-color, red);
font-family: Arial;
}
or you can overwrite it
.class-a:extend(.class-b, .class-c) {
color: black;
}
.class-b { color: var(--b-color, red) }
it’s one clock in London so I hope some American is awake and can give me some feedback goodnight I will answer tomorrow(/today).
Note:
In Android platform you can define inheritance inside style, with the property parent: https://developer.android.com/guide/topics/ui/themes.html#DefiningStyles