Don’t know about “brilliant”, and not a standalone CSS solution, but my Web/MX hack (ne mxWeb) offers a radically different solution. Key qualities:
- it still works with stylesheets via the
classattribute; - the in-line style of a widget can be defined reactively, via a CLJS formula that keeps up with other app state. Or at least examines other widget state to decide its CSS;
- so, yeah, we have dynamic CSS without juggling classes; and
- the style attribute can be expressed as an object with individual reactive properties per style attribute. Prolly not huge performance win, but certainly easier to fine-tune or just understand a widget’s styling.
These examples are from the huge-ish Web/MX demo app “AskHN Who’s Hiring?”. (Live version built with the JS version of Web/MX is here.). Now the examples.
A primitive rule building a style string reactively, to show/hide a star in the header of a job which the user has scored:
(span {:style (cF (str "color:black;max-height:16px;margin-right:9px; display:"
(if (or (deets? me)
(zero? (memo/job-memo job :stars)))
"none" "block")))}
(utl/unesc "⭑"))
A case that shows dynamic CSS classes, in support of animation, as well as more structured specification of :style:
(div {:class (cF (if (deets? me) "slideIn" "slideOut"))
:style (cF {:margin "6px"
:background "#fff"
:display (if (deets? me) "block" "none")})}
...etc)
And a full-blown css-inline model:
(make-css-inline me
:border "none"
:font-size "14px"
:display (cF (if (and (rx-completed rx)
(not (rx-due-by rx)))
"none" "block"))
:background-color (cF (when-let [clock (mxu-find-class (:tag @me) "std-clock")]
(if-let [due (rx-due-by rx)]
(if (rx-completed rx)
_cache ;; cF expansion has _cache (prior value) in lexical scope
(let [time-left (- due (mget clock :clock))]
(cond
(neg? time-left) "red"
(< time-left (* 24 3600 1000)) "coral"
(< time-left (* 2 24 3600 1000)) "yellow"
:default "green")))
"#e8e8e8"))))
One thing not shown is that, since Web/MX accepts a map of CSS attributes, it would not be hard to fake in-line CSS composition with a clever set of routines, perhaps by rolling our own fake CSS class tags and driving the final CSS map off that. But that sounds like we would descend into CSS combination hell pretty quickly. There if we want it, tho.
Finally, again, this is not a standalone solution. I offer this more as an example of how much goodness falls out of making widget properties individually reactive. I will yap more about this in the formal announcement of Web/MX. RSN.