
Interoperable CSS - bootload
http://glenmaddern.com/articles/interoperable-css
======
skrebbel
I really really love this idea. My only beef, currently, is that it generates
this kind of CSS (taken from [0]):

    
    
        ._23_aKvs-b8bW2Vg3fwHozO { background: red; }
        ._23_aKvs-b8bW2Vg3fwHozO { color: green; }
        ._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 { color: green; }
        ._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 .global-class-name { color: blue; }
    

This seems like a pain to debug using devtools. I'd love if the generated
classnames could resemble the original classnames, e.g.

    
    
        .my-fantastic-component-24xMw
    

Or even just

    
    
        .my-fantastic-component-1
    

Given that webpack has global program knowledge anyway, it should be able to
prevent name clashes if multiple css files use the same local class name, no?

I see that there's nothing in this _standard_ , however, that would prevent
readable class names.

[0] [https://github.com/webpack/css-loader#local-
scope](https://github.com/webpack/css-loader#local-scope)

~~~
Ambroos
For webpack:

    
    
      You can configure the generated ident with the
      localIdentName query parameter (default [hash:base64]).
      Example for easier debugging:
      css-loader?localIdentName=[path][name]---[local]---[hash:base64:5]
    

From the docs. Results in classes like these:

    
    
      src-components-MyFantasticComponent---myClass---3ZAMU
    

Other packaging systems that use CSS modules will probably offer something
similar.

------
pluma
This sounds great, but the obvious problem with Webpack & co seems that they
are entirely useless for isomorphic code. There's just no way to make require
work like that for code that has to work on the server as well (which is one
of the things React allows us to do).

~~~
skrebbel
This is just plain untrue. The trick is simply to make Webpack generate a
special build for Node.js that doesn't access the DOM.

With oldschool webpack style-loader, all you need is the well documented &
supported ExtractTextPlugin to save the .css to a separate file, and there's
nothing left for node to choke on. I'm not sure whether the same works as
easily for the OP's idea though, but at a first glance I don't see why not.

The only real disadvantage is that you're feeding Node webpack-generated code,
and not vanilla JS files. I've yet to find the real big problem with this,
though, other than a slightly slower save-build-reload cycle.

~~~
pluma
> The only real disadvantage is that you're feeding Node webpack-generated
> code, and not vanilla JS files.

This is what I mean.

Normally your chain would be:

ES2015/JSX -(Babel)-> Node code -(Browserify/etc)-> Browser code

With Webpack's "require" magic you end up with this:

ES2015/JSX -(Babel)-> Intermediate code -(Webpack)-> Browser code & Node code

This isn't necessarily wrong (you can make Webpack use Babel and thus merge
the first two steps, I think) but right now it feels extremely wrong to me.
I'm not yet convinced Webpack is a good idea either -- especially because the
documentation is a sketchy mess at this point.

Webpack (like browserify) was written to generate bundles for the browser, not
modules for Node. I have been wrong in the past and would be willing to
suspend my disbelief if I were able to find any reliable information on how
you're supposed to use Webpack for Node, but right now my gut feeling tells me
it's a really bad idea and the Node support is a hacky afterthought at best.

~~~
skrebbel
Ah, I see your point. That said, Webpack works great with Babel indeed, so in
practice this becomes:

cross-platform ES2015/JSX --(Babel+Webpack)--> Browser code & Node code

The only thing, really, is to stop thinking of webpack as something that turns
node code into browser code, but of something that turns general code into
platform-specific code.

I fully agree that this wasn't what webpack was originally designed for, but
in practice there's nothing about webpack that makes this intrisically
difficult. Personally, I just use DefinePlugin to define a boolean SERVER
constant. It's set to true on the node build and to false on the browser
build, and then in my code there's just some stuff like this:

    
    
        if(SERVER) {
            // node-only code
        }
    

For the browser build, Webpack turns that into this:

    
    
        if (false) {
            // node-only code
        }
    

And then UglifyJS removes it entirely.

React uses the same trick to differentiate between production and dev builds,
so in practice most React+webpack users will already be doing something like
this so it's not a complex step to add.

I manage the difference between test/dev/production builds in the same way,
haven't yet found a downside.

~~~
pluma
FWIW, the React app I would be using Webpack for (currently using Browserify
and Babel) doesn't actually do any server/browser checks, the entire
difference is handled via two different entry points and a few module swaps
for browserify in my package.json file.

------
fiatjaf
I thought you were going to talk about CSS stylesheets that could be used in a
lot of contexts and different websites, instead of in only one, like
[http://fiatjaf.alhur.es/programming/reusable-pure-css-
themes...](http://fiatjaf.alhur.es/programming/reusable-pure-css-themes/)

------
chrramirez
I believe less' `:extend` pseudo-class is a better starting point to
implemented scoped styles. See: [http://lesscss.org/features/#extend-
feature](http://lesscss.org/features/#extend-feature)

------
3solarmasses
This seems like a step in the right direction. I think we all intuitively know
that the current global nature of CSS is plain wrong.

A system like this would make it much easier to swap in new ui elements to an
app without worrying about breaking styles elsewhere.

~~~
talmand
I disagree, I don't intuitively know that the global nature of CSS is plain
wrong. I have never seen an example that explains to me why the global nature
is wrong. I would actually like to see it.

Swapping new ui elements without worrying about breaking styles elsewhere is
quite easy with even basic vanilla CSS.

------
dominotw
i use nested css with react components. Seems to nicely solve the collision
issue.

    
    
       .component-name{
            .label-header ...
            input{..
        }

~~~
talmand
This is the thing that gets me. Most people who complain about CSS not doing
this or not doing that seem to not understand how CSS actually works. Avoiding
collision in CSS is so freaking easy it's funny to see Javascript based
solutions for it.

I really wish that browsers could parse nested CSS like we do with SASS and
LESS so that we can move on from this type of stuff.

Loading CSS on demand I can get behind because it makes sense. But there's no
reason to create these strange class name solutions to avoid collisions, which
make it hard to use browser developer tools, when you can namespace now.
Today. With vanilla CSS even.

~~~
porker
> Avoiding collision in CSS is so freaking easy

Having spent this afternoon scratching my head over one, I'd like to know what
I've missed.

Take your standard website, with a block called '.sidebar'. You want this to
have default styles (font size, headings etc).

Into .sidebar (and .main, and .some-other-region) you can drop components. I
like to use BEM for component naming. This one has: .box {} and .box__header
{}

My issue: given <div class="sidebar"><div class="box"><h4
class="box__header">Header</h4></div></div> the styles on .sidebar h4 {}
override those on .box__header.

How does one set defaults?

~~~
talmand
Assuming I'm understanding correctly, seems easy to me.

    
    
        .sidebar h4 {
          color: red;
          font-size: 20px;
        }
        .box .box__header {
          color: green;
        }
    

<div class="sidebar"><div class="box"><h4>Header</h4></div></div> will produce
red text.

<div class="sidebar"><div class="box"><h4
class="box__header">Header</h4></div></div> will produce green text.

Both will have the 20px font-size.

It all depends on how you plan out the HTML structure and CSS selectors.

EDIT: I would also say if you are placing HTML like this into the page in
several places, then the CSS for it should be self-contained and totally
separated fron the rest of the page. I would be reluctant to use default CSS
on a container such as that. But I can see it would depend on the nature of
the container.

~~~
porker
Perhaps I misunderstand BEM, but .box .box__header {} seems to be against the
spirit of it -- my understanding is that this naming convention exists to
prevent needing to nest style rules?

I agree with your edit; global styles are probably not the best here, however
tempting they may be to reduce wrapper markup and make everything simpler (to
begin with)

~~~
talmand
BEM would work in this case. It's just that I wouldn't use .sidebar as the
starting container for the related elements, it would be .box instead.

In this example .sidebar just happens to be the container to hold other
elements being placed into it. I would make .box be the actual true container
of the widget I am placing inside whatever container happens to need it. My
CSS would be built so that .box is the foundation and it could exist anywhere
on the page.

------
pearjuice
Relevant XKCD:

[https://xkcd.com/927/](https://xkcd.com/927/)

~~~
rrrx3
Always relevant. In life, and in code.

------
EGreg
I've spent the last four years building a platform for reusable components,
which "just work" across all devices, and across domains. So I've had to deal
with reusability to the extreme:

* Installer and versioning across apps and plugins

* Common file system and conventions

* Common event system with automatic unregistering of events

* Common system handling user accounts/contacts/security/etc.

* Common system for handling data/access/realtime updates/offline notifications.

Let me tell you, REAL interoperability is hard. It goes without saying that
everything is namespaced. But then you have to build a robust system which
marries components to the Web's best practices, which are based around
resources. For example you have web "pages" which you can just drop "tools"
(components) on. For these tools to "just work" while being reusable, the
system has to literally have a way of swapping their stylesheets and scripts
in and out on demand. Then it has to provide all the events to hook into and
machinery for "activating" these tools:

* Events for constructing parents before children

* Events for initializing parents after children

* Async loading on demand of all scripts/stylesheets as fast as possible

* Compiling and minifying everything into a couple filesfor production

* Support for versioning and storing some (most) of the code in local bundles for downloaded PhoneGap apps

And then you still get questions such as "how does a Streams/related tool
interoperate with a Q/tabs tool on the SAME ELEMENT, so I can combine the
behaviors and have a bunch of tabs that represent articles related to a
particular topic?" The tabs are supposed to "just work" and the "related" tool
is supposed to "just work".

So when it comes to CSS, a few years ago I just went with the straightforward
approach:

You call Q.addStylesheet(...) and it "just works". It adds your stylesheet
when your tool is loaded and then removes it when it's not needed. Each class
and id is supposed to be prefixed by the namespace of the plugin bundle you're
distributing. Each tool would have classes that are prefixed with that tool's
name. Naturally, you avoid ids in the actual plugin, but each tool has an id
which the _app_ can use to style things.

You can take a look at the result here:

[https://github.com/EGreg/Platform/blob/master/platform/plugi...](https://github.com/EGreg/Platform/blob/master/platform/plugins/Q/web/css/filter.css)

[https://github.com/EGreg/Platform/blob/master/platform/plugi...](https://github.com/EGreg/Platform/blob/master/platform/plugins/Q/web/css/inplace.css)

[https://github.com/EGreg/Platform/blob/master/platform/plugi...](https://github.com/EGreg/Platform/blob/master/platform/plugins/Q/web/css/tabs.css)

[https://github.com/EGreg/Platform/blob/master/platform/plugi...](https://github.com/EGreg/Platform/blob/master/platform/plugins/Streams/web/css/Streams.css)

And the corresponding JS modules:

[https://github.com/EGreg/Platform/tree/master/platform/plugi...](https://github.com/EGreg/Platform/tree/master/platform/plugins/Q/web/js/tools)

[https://github.com/EGreg/Platform/tree/master/platform/plugi...](https://github.com/EGreg/Platform/tree/master/platform/plugins/Streams/web/js/tools)

Here is an example of a Streams/related tool integrating with a Q/tabs tool:

[https://github.com/EGreg/Platform/blob/master/platform/plugi...](https://github.com/EGreg/Platform/blob/master/platform/plugins/Streams/web/js/tools/related.js)

So that's a proven style I would recommend.

~~~
EdSharkey
Seemed like the 'juice' in this interoperable CSS concept was that you could
pull just the CSS classes you needed from the imported css, not simply include
the whole import. It's (purportedly) an unopinionated approach to composing
CSS that's bound to encourage reuse and continuous refactoring without any
unneccessary bloat in the output. Winner winner chicken dinner!

