Styling an Elm application without CSS

Photo by Rick Mason

As much as I love CSS for its creative potential, it seems impossible not to feel a lot of pain when it comes to scaling it. At carwow, we currently have over 40 engineers working on our online application daily and all of us end up writing CSS at some point. As much as we try hard to keep things tidy and leverage our design system, we inevitably come across the typical issues with maintaining a large CSS codebase: lack of consistency, redundancies, over-complications and frequent regressions of our User Interface.

I have been following many conversations on how to tackle these problems, and there seems to be different schools of thought. One consists of enforcing a stricter use of CSS, via linters and naming conventions (Object-Oriented CSS, SMACSS, BEM, etc). Another one is re-thinking the way we manage styles and avoiding writing any direct CSS. That can be done either by using a functional toolkit such as Atomic CSS or Tachyons, or managing styles in JavaScript (see JSS, CSS modules or styled components).

I usually feel puzzled with the idea of managing CSS in JavaScript. We are already overloading users with lots of JavaScript - whether for abundant interactivity or marketing trackers. By handling both HTML and CSS in JavaScript, I come to wonder if we are really solving problems or just bundling heavier, slower and more obtrusive websites. As Harry Robert justly puts it:

In the meantime, I recently came across this thread about the outcome of building Twitter’s new Progressive Web App and generating on-demand CSS with a JS framework

The following paragraph particularly caught my attention as I could completely relate to the issues described.

Not long after, I also watched Matthew Griffith’s talk at the elm-conf 2018 on his design toolkit Elm UI.

Having worked with Elm for over a year, this talk spoke a lot to me. I really enjoy Elm for its predictability, the feedback loop working with the compiler and the assurance of not having runtime errors. Moreover, Elm was originally built as a graphics library and it does feel like a natural fit for the DOM. It would also make sense to use it to declare the layout and appearance of the applications we build.

I watched this talk with both excitement and skepticism. On one side, I really like the approach of re-thinking the way styling works for websites rather than using Elm functions that replicate CSS properties per-se. It seems that a lot of thought was put into making layout building simpler and more intuitive with Elm UI. One of the flaws of CSS is that it’s very hard to read. Looking at a list of properties in a selector never really gives you a full picture of how the element will look in the browser. With Elm UI, layout and styling seems a lot easier to read, and by extension, faster to learn too.

The other element I really enjoyed in the talk is the relationship between Elm UI and design systems. I have been working actively in building and maintaining a styleguide and feel passionate about achieving a UI library that’s flexible, modular and works for both developers and designers. Again, issues with scaling CSS come in the way to reach this goal. I like the idea of being able to assemble pieces of UI just like a set of LEGO blocks. Having encapsulated styles in components and being able to declare layouts simply would be key to reach this state.

Meanwhile, I felt skeptical about the possibilities offered by Elm UI. By adding a level of abstraction on top of CSS, isn’t there a risk of limiting its possibilities? The examples provided in the talk as well as some of demos I’ve seen online are quite simplistic and I wonder if we can achieve complex designs with Elm UI. Can we overlay elements? Animate and transform elements with graceful transitions? Use viewport units or size calculations? These questions seem crucial to me to be able to use Elm UI on production while keeping the design team happy.

I then decided to confront my skepticism and try out the library with a few use cases and see it for myself. One of my attempts was to re-create our styleguide’s modal component using Elm UI. Some of the specifications I wanted to replicate here are the overlay taking over the whole viewport and blocking user scrolling, as well as the overall modal having a flexible height, up to 65vh. The body of the modal should display an inner scrollbar if necessary. Finally, the component opens and closes with quick transitions of the overlay’s opacity and the size of modal, to convey the pop-up effect.

Building the foundations of the modal, I rapidly came across a few overflow issues, which I interpreted as a reminder that, deep down, I’m still writing CSS. I had hope that Elm UI would prevent that from happening, but I guess there are limits to how robust an atomic CSS toolkit can be.

No runtime layout error, eh?

Overall, I found the experience of learning Elm UI pleasant and some of the ways to declare layout and styles are much more elegant than in CSS.

For example, setting an element as an overlay in front of the rest of the page is done via:

Element.layout [ inFront modalOverlay ]

We also benefit from the Elm syntax, which can be handy, for example, to set padding or border width values:

paddingEach { edges | top = 24, left = 32 }

Instead of having to set all 4 edges and follow an arbitrary order:

padding: 24px 0 0 32px

Quite rapidly, I managed to build the entire component:

However I couldn’t fulfil the following requirements:

  • I couldn’t set a maximum height in viewport units. I had to set it in pixels instead.
  • I couldn’t find any way to set transitions on opening and closing the modal. I guess transitions and animations are features that Elm UI could handle in future versions.
  • Our styleguide has a set of font-sizes that are responsively adjusted for 3 screen sizes. I didn’t seem to be able to do that here and generally, it doesn’t seem to apply media queries via Elm UI.
  • There are some minor issues I also didn’t seem to be able to get around. For example, Element.textColumn have a minimum width of 500px by default, which doesn’t make much sense to me, and it doesn’t seem easy to override it. I also had trouble vertically aligning text elements within a row, which is normally straightforward with Flexbox. Although, these issues could be just due to my lack of experience with the toolkit.

In the end, I really enjoyed trying out Elm UI. It’s a well thought, quick-to-learn and fun-to-use library. I think it is a little bit too limited at the moment to be able to use it in production and fulfil the design requirements we usually have. There are also other concerns that would need to be cleared, for example how well it handles browser quirks and supports legacy browsers.

I hope these limits are only due to Elm UI’s newness and that it continues to develop and offer greater possibilities soon.

PS: Also, what’s with the flex-grow: 100000?

Wait. What?