Recently I’m thinking how to write CSS in clojurescript. I started writing a little library called mcss.
The project is not finished and I’m still not sure if it is a good thing, but I’d like to share something I found while developing mcss.
Now I’m sure that it’s possible to do following:
Generating CSS via macro, As less runtime as possible
If we using CSS variables(Not supported on some old browsers), the CSS can be generated by macros while we still have the ability to do dynamic style.
;; Definition
(defstyled my-btn :button
{:background-color #(get % :bg-color)})
;; Usage
[my-btn {:css {:bg-color "#999"}}]
In this case the generated CSS is:
.some_ns__my-btn{background-color: var(--some-var);}
And the function my-btn
is like(simplified):
(defn my-btn [props]
(let [css (:css props)
some-var (#(get % :bg-color) css)]
[:button {:style {"--some-var" some-var}}]))
There are a few benefits:
-
The most part of library itself won’t be packaged into the application, bundle size will be smaller, because it won’t ship the CSS compiler code and the specs.
-
the initializing become much simpler, only one insertion when application is started, which make it really fast. And this performance won’t be affected by dynamic styles. Some libraries will insert new style into dom when they met same style with new values, this will be okay in most cases, but will be slow when there are a lot of dynamic styes.
Using munged function name as CSS class
Like Vue, writing scoped CSS make it easier for me to naming CSS and manage my code structure. In ClojureScript we have namespace, so it should be easy to use namepaced symbol for CSS names. In mcss I try to use function name, taken at runtime, so the CSS name is also munged. This make CSS some kind of shorter, especially for atomic CSS I’m going to talk.
Use Dead Code Elimination on atomic CSS
I personally think the atomic CSS is a good stuff that you write little piece of styles as atomic. Then you combine multiple atomic CSS into the component style.
(defa w-100
{:width "100%"})
(defa vh-100
{:height "100vh"})
(defstyled fullscreen :div
[w-100 vh-100])
So how about having huge amount of built-in styles if we could only package those we use? The idea is using Dead Code Elimination. If we define atomic as function, If the function is not called at least once, it won’t be packaged in advanced mode. This is really nice because we don’t have to care the built-in size anymore, we can write large library or bring all other famous pure CSS library into this.