Foreword
Currently, when I want an element on the page to be customizable in different respects, I define a CSS module for it, and in that module I use custom properties to define CSS properties; those custom properties are defined by other modules or maybe simply in the * { } ruleset, to make them widely available.
In the silly example below, for instance, the .box class is for drawing a box around the text; however, two of the properties it sets are not really hardcoded to two specific values, but to two custom properties which one should set by other means, for instance via the other three classes in the snippet.
/* global rulesets to set some "constants" */
.colored {
--theme-color: green;
}
.shapes-hard {
--border-radius: 0;
}
.shapes-soft {
--border-radius: 5px;
}
/* module that uses existing custom properties */
.box {
text-align: center;
background-color: var(--theme-color, grey);
border-radius: var(--border-radius, 0);
}
<style> div { width: 10em; } </style>
<div class="shapes-hard box">
foo
</div>
<br>
<div class="colored shapes-soft box">
bar
</div>
I'm generally happy with the flexibility that this approach gives.
Actual question
However, what I haven't quite understood is how I can extend this approach to those CSS properties that accept more than 1 value, e.g. transform.
As an example (and it's actually my use case), take this spinning loader and imagine that I want to use it as in the example, but that I also want to be able to put it in the middle of another element, via manual positioning (see this comment).
.container {
position: relative;
width: 5em;
height: 5em;
}
.container::after {
content: "";
display: block;
width: 5em;
height: 5em;
border: 1px solid black;
}
.loader {
border: 10px solid #f3f3f3;
border-radius: 50%;
border-top: 10px solid #3498db;
width: 2em;
height: 2em;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: translate(-50%, -50%) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(360deg); }
}
.center-origin {
position: absolute;
left: 50%;
top: 50%;
}
<div class="container">
<div class="loader center-origin"></div>
</div>
As you can see, the module .center-origin does essentially just one thing, that is translating the element's origin in the exact center of the parent (well, the closest postitioned parent).
What I don't like is that the translate(-50%, -50%) part is hardcoded in a module it doesn't belong to. For instance, I can't reuse the spin animation for things that don't require translate(-50%, -50%).
I would rather have a module like this
.center-self /* maybe not appropriate name */ {
transform: translate(-50%, -50%);
}
and a corresponding markup like this
<div class="container">
<div class="loader center-origin center-self"></div>
</div>
but then I wouldn't know how I can stitch together the part of transform set by .center-self and the part set by @keyframes spin.
Here are some related questions, which seems to answer "it's not possible", but they are quite old, so maybe something's changed in the meanwhile.