[ClojureScript] Re: CSS in CLJS

2017-02-03 Thread Thomas Heller
FWIW I did a quick test to see if things worked with reagent. Turns out they do.

Basically works out of the box:
https://github.com/thheller/reagent-test

The dependency on Clojure 1.9 was not intentional and I would remove it if 
anyone wants to use this with 1.8.

Anyways feel free to clone the test project and mess around, you get the whole 
figwheel experience + CSS without editing CSS files.

/thomas

-- 
Note that posts from new members are moderated - please be patient with your 
first post.
--- 
You received this message because you are subscribed to the Google Groups 
"ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojurescript+unsubscr...@googlegroups.com.
To post to this group, send email to clojurescript@googlegroups.com.
Visit this group at https://groups.google.com/group/clojurescript.


[ClojureScript] Re: CSS in CLJS

2017-02-03 Thread Thomas Heller
As I said I haven't used garden, can't say how much of a difference there is. 
One thing I can't change is that selectors have to be strings, they are 
keywords in garden. The maps of css properties should be portable though and 
you shouldn't really need the selectors after?

As for re-using css classes: Don't! That is the whole point of this, as 
mentioned here: http://mrmrs.io/writing/2016/03/24/scalable-css/ and elsewhere.

I have been in this situation many times where I'm scared to touch an existing 
class since I have no direct record of who uses it in which situation. Or where 
I added another class with !important, just to have a quick fix somewhere. Also 
I hated OOCSS with things like  where 
the actual order mattered and I never could remember which it was.

You can and should however abuse all the power of Clojure. I have this for some 
of my styles:

(defn button-style [env]
  {:padding 10
   :border (str "1px solid " (-> env :colors :border))
   :background-color (-> env :colors :bg)})
   
and then re-use this a couple time for anything that should look like a button:

(defstyled link :a
  [env]
  (merge
(button-style env)
{:display "inline-block"
 :text-decoration "none"}))

(defstyled button :button
  [env]
  (merge
(button-style env)
{:you-get "the-idea"}))

I currently still have a base.css which includes normalizr.css and some other 
generic classes, you can of course still use (button {:className "generic"} 
...). Nothing wrong with that.


As for performance: The generated selectors are very specific in that they only 
match one thing, too open generic styles tend to cause issues. Also if you 
stick to "modern" things (flexbox) the need for some filler HTML elements goes 
away which improves overall performance, not just CSS. Style generation also 
happens ONCE, so even complex style-fns should not be an issue ever.

Also thanks for :advanced optimizations the code to generate the CSS should by 
much smaller than any actual minified CSS. Did I mention dead code removal yet? 
;)

But I currently have only 89 "defstyled" things in my project myself, as this 
is still fairly new. Too early to make general claims about performance, but it 
should probably be on par with hand-written CSS. Generating styles on the 
client might be a bad idea too, my stuff is not yet complex enough to say. Time 
will tell, I am committed however as the past few weeks produced basically zero 
headaches about CSS and that is a nice feeling.

/thomas


-- 
Note that posts from new members are moderated - please be patient with your 
first post.
--- 
You received this message because you are subscribed to the Google Groups 
"ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojurescript+unsubscr...@googlegroups.com.
To post to this group, send email to clojurescript@googlegroups.com.
Visit this group at https://groups.google.com/group/clojurescript.


[ClojureScript] Re: CSS in CLJS

2017-02-03 Thread Dylan Butman
On Thursday, February 2, 2017 at 11:36:43 PM UTC+1, Thomas Heller wrote:
> Hello,
> 
> I'm not sure how many of you are in this horrible situation where you have to 
> write CSS for your React Components. I typically have to write way more than 
> I'd like and always hated the way I wrote it. Until a few weeks ago.
> 
> I wrote this thing and so far I really like it. Too early to tell whether 
> this is actually a good idea but I already prefer it over pretty much 
> everything else I have used in the past (CSS, SCSS, OOCSS, BEM, ...).
> 
> Anyways here it goes:
> 
> (ns my.fancy.component
>   (:require [shadow.markup.css :as css :refer (defstyled)]))
> 
> (defstyled title :h1
>  [env]
>  {:color "red"})
> 
> (h1 {} "hello world")
> 
> In Clojure this produces hello 
> world. There are also ways to generate the appropriate CSS so the 
> element is actually styled in your page. Not totally settled on the final API 
> but it works well enough for now.
> 
> In ClojureScript this produces a ReactElement and should work with React 
> natively and most CLJS React Wrappers like OM (although I tried no other than 
> my own). No extra CSS generation is required here, just include it in your 
> page and it will be styled.
> 
> More here: https://github.com/thheller/shadow/wiki/shadow.markup
> 
> This is basically my take on the whole css-in-js thing that is happening in 
> the JS world if anyone follows this. I wasn't happy with any of their 
> implementations so I wrote this.
> 
> If you'd like to use this try it with this:
> 
> [thheller/shadow-client "1.0.180"]
> 
> The Clojure part also requires hiccup, the CLJS parts require React via 
> cljsjs.react.
> 
> If anyone is actually interested in this I'd be happy to go over some more 
> details. I just open-sourced this as I wanted to use it in another project 
> and needed a place to put it. Consider this very ALPHA though, you have been 
> warned. ;)
> 
> Cheers,
> /thomas

This is interesting. A few thoughts...

Have you considered using garden syntax for the style generation? I have a ton 
of garden styles already, and I imagine others do to, direct porting would be 
awesome.

Is there a way to reuse css classes? Generating classes for each element 
potentially produces a lot of redundant css, and in cases where performance is 
an issue, the same class being applied to many elements will be faster

-- 
Note that posts from new members are moderated - please be patient with your 
first post.
--- 
You received this message because you are subscribed to the Google Groups 
"ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojurescript+unsubscr...@googlegroups.com.
To post to this group, send email to clojurescript@googlegroups.com.
Visit this group at https://groups.google.com/group/clojurescript.


Re: [ClojureScript] CSS in CLJS

2017-02-03 Thread Thomas Heller
I looked at garden but never used it. It seems like a direct alternative to 
SCSS/Less, but nothing more.

The intent of shadow.markup (sorry, couldn't think of a better name yet) is 
that I basically never want to write a single selector ever again. There are 
several cases where this is still needed but way less than I usually do.

You get several things for free by combining the actual HTML Tag with its CSS.

This is a pretty good introduction to the topic of css-in-js and 
styled-components for React
https://www.youtube.com/watch?v=19gqsBc_Cx0

My API is very much inspired by this library, although less strings and more 
Clojure. There are many more implementations of this here: 
https://github.com/search?q=topic%3Acss-in-js=Repositories

Let me try with some sample Clojure code. You'd write something like this to 
generate a simple html snippet:

(ns my.site
  (:require [hiccup.page :refer (html5))

(defn page-html [title body]
 (html5
  [:head]
  [:body
   [:div.box
[:h1.box__title "foo"]
[:div.box__content body]]]))

Here we invented tree css classnames that we need to remember here and 
whereever we get the actual CSS from. This over time leads to this: 
http://mrmrs.io/writing/2016/03/24/scalable-css/ at least it did for me in just 
about every project ever. Garden does not do anything in this regard I think, 
you still define things in two different places.

With shadow.markup you do this:

;; put all defstyled elements in a separate namespace in a .cljc, so you can 
use it everywhere.
(ns my.html.box
  (:require [shadow.markup.css :as css :refer (defstyled)]))
  
(defstyled box :div
 [env]
 {:padding 10
  :border "1px solid green"})

(defstyled title :h1
 [env]
 {:color "red"})

(defstyled contents :div
 [env]
 {})

;; my/site.clj
(ns my.site
  (:require [my.html.box :as box]
[hiccup.page :refer (html5))

(defn page-html [title body]
  (html5
[:head]
[:body
 (box/box {}
  (box/title {} title)
  (box/contents {} body)))
]))

You do not need to remember whether to use a :h1 or :div, you just directly use 
the elements. Since everything in CLJ(S) is namespaced we get a safe naming 
scheme for CSS classes for free as well. You just write normal CLJ(S) code, you 
don't need to context switch and synchronize the class names back and forth. 
Refactoring the defstyled name in Cursive will rename all of its uses as well 
the CSS classnames. The CLJS version with :advanced gives you dead code removal 
for free, so if you don't use an element it's CSS will be removed as well.

There are many more things but the basic idea is to bundle the CSS with the 
HTML that uses it while still supporting all of CSS (ie. no inline styles) and 
remaining pure Clojure.

HTH,
/thomas





-- 
Note that posts from new members are moderated - please be patient with your 
first post.
--- 
You received this message because you are subscribed to the Google Groups 
"ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojurescript+unsubscr...@googlegroups.com.
To post to this group, send email to clojurescript@googlegroups.com.
Visit this group at https://groups.google.com/group/clojurescript.