A Love Letter to CSS

When I tell coworkers of my unabated love for CSS they look at me like I’ve made an unfortunate life decision.

“Let’s sit down TJ, and talk about the poor choices you made during childhood that set you up for failure.”

Sometimes I feel that developers, some of the most opinionated human beings on the planet, can only agree on one thing: that CSS is totally the worst.

One of the best ways to get consistent laughs at tech conferences is to take a jab at CSS, and CSS memes are so common that I’m contractually obligated to include two of them in this article.



But today I’m going to blow your mind. Today I’m going to try to convince you that not only is CSS one of the best technologies you use on a day-to-day basis, not only is CSS incredibly well designed, but that you should be thankful—thankful!—each and every time you open a .css file.

My argument is relatively simple: creating a comprehensive styling mechanism for building complex user interfaces is startlingly hard, and every alternative to CSS is much worse. Like, it’s not even close.

To prove my point I’m going to compare CSS to a few alternative styling systems, and I’m going start by taking you back in time.

OMG, remember Java applets?

In college I built a few apps with this powerful, about-to-be-obsolete technology called Java applets. Java applets were basically Java apps that you could haphazardly embed in a browser using an <applet> tag. On a good day half of your users would have the correct version of Java installed on their machines, and they’d be able to run your apps successfully.


A sample Java applet so you can take yourself back to the late 90s

Java applets debuted in 1995 and started to get popular a few years later. If you were around in the late 90s, you’ll remember real debates about whether you should build your next great app using web technologies, or whether you should build using Java applets.

Like most technologies that let you create user interfaces, Java applets let you change the appearance of the controls that you place on the user’s screens. And because Java applets were seen as a plausible alternative to web development, the ease of styling controls in applets was sometimes compared to how you accomplish that same task on the web.

Java applets obviously didn’t use CSS, so how exactly do you style UI controls in a Java applet? Not easily. Here’s a code snippet from the first Google result for “change button color Java applet”.

/*
        Change Button Background Color Example
        This java example shows how to change button background color using
        AWT Button class.
*/
 
import java.applet.Applet;
import java.awt.Button;
import java.awt.Color;
 
public class ChangeButtonBackgroundExample extends Applet{
 
    public void init(){
            
        //create buttons
        Button button1 = new Button("Button 1");
        Button button2 = new Button("Button 2");
        
        /*
          * To change background color of a button use
          * setBackground(Color c) method.
          */
        
        button1.setBackground(Color.red);
        button2.setBackground(Color.green);
        
        //add buttons
        add(button1);
        add(button2);
    }
}

The first thing to note is that Java applets offer no real way to separate your logic and styling code, like you might do on the web with HTML and CSS. This will be a theme for the rest of this article.

The second thing to note is that this is a lot of code to create two buttons and change their background colors. If you’re thinking something like “wow, this approach seems like it would get out of control really quickly in a real-world app”, then you’re starting to get an idea of why the web won and Java Applets didn’t.

That being said I know what you’re thinking.

“TJ, you’re not exactly winning me over by saying CSS styling is better Java Applet’s approach. Way to set a high bar.”

Yes, because Java applet’s visual APIs aren’t exactly the gold standard of user interface design, let’s shift our attention to something developers actually build nowadays: Android apps.

Why styling Android apps is hard

In some ways, Android is a modern, way-better version of the Java applets from years ago. Like Java applets, Android uses Java as a development language. (Although you’ll soon be able to use the Kotlin language, per a recent Google announcement at their Google I/O event.) But unlike Java applets, Android includes a series of conventions that makes building user interfaces a whole lot easier, and a lot more like building for the web.

On Android you define your user interface controls in XML files, and interact with that markup in a separate Java files. It’s very similar to a web app with markup in HTML files, and logic in separate JavaScript files.

Here’s what the markup of a very simple Android “activity” (basically a page) might look like.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.telerik.tj.testapp.MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World" />

</android.support.constraint.ConstraintLayout>

This might look a bit arcane if you’re a web developer, but remember that a basic index.html file has its share of quirks as well. What you’re seeing here is two UI components, an <android.support.constraint.ConstraintLayout> and an <android.widget.Button>, each with various attributes used for configuration. Just to give you a visual, here’s what this simple app looks like running on an Android device.

So to bring this discussion back to the topic of this article, how do you style these components? Much like the web’s style attribute, there are a variety of attributes you can apply to pretty much every Android UI component to change their appearance.

For example, if you want to change the background color of the previous example’s button, you can apply the android:background attribute. In the code below I apply that attribute so that the button appears red.

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World"
    android:background="#ff0000" />

So far so good. Android Studio, Google’s recommended Android development environment, even provides a robust visual editor that makes configuring some of these common properties really easy. The image below shows Android Studio’s design view for this sample app. Note how you can easily configure properties such as “background” using the pane on the right-hand side of the screen.

Through things like the design view, Android makes the basics of applying styles to user interface controls very simple. But this is where the pro-Android portion of this article ends.

Real-world development requires you to go well beyond the basics, and, at least in my experience, this is where the verbosity of Android and the simplicity of CSS really starts to show. For example, suppose you want to create a collection of property name/value pairs that you can easily reuse – something kind of like CSS class names. You can kind of do that in Android, but it gets messy very quickly.

Android apps have a styles.xml file where you can create XML chunks in that file that build on top of each other. For instance, suppose you wanted to make all your app’s buttons have red backgrounds. On Android you could use the following code to create a “RedTheme” style.

<style name="RedTheme" parent="@android:style/Theme.Material.Light">
  <item name="android:buttonStyle">@style/RedButton</item>
</style>

<style name="RedButton" parent="android:Widget.Material.Button">
  <item name="android:background">#ff0000</item>
</style>

After that change, you could then apply a android:theme="@style/RedTheme" attribute to the top-level UI component you want this theme to apply to. In the code below I apply that attribute to the top-level layout component from our previous example.

<android.support.constraint.ConstraintLayout
    ...
    android:theme="@style/RedTheme">

This works, and all buttons within that layout will indeed be red, but let’s take a step back. All of that code — the handful of lines of XML, the markup attributes, and such — all of that is replicating what you can accomplish in CSS using button { background: red; }. And these same sort of styling tasks don’t get easier as your Android apps get more complex.

In general, non-trivial styling implementations on Android tend to involve either nested XML configuration files, or a bunch of Java code to create extensible components — neither of which fill with me with much joy.

Consider animations. Android has some built-in animations, and those tend to be nice and easy to use, but custom animations must be implemented in Java code. (Here’s an example.) There’s no equivalent of something like CSS animations that lets you configure and manage your animations along with your app’s styling.

Consider media queries. Android lets you implement some CSS-media-query-like properties to your UI components, but it’s entirely done in markup, which doesn’t lend itself to reusability across pages or views.

Just to give you a sense of what I’m talking about, this is the very first code example from Android’s documentation on Supporting Multiple Screen Sizes. I’ll offer it below verbatim as some food for thought the next time you complain about CSS media queries.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout android:layout_width="match_parent" 
                  android:id="@+id/linearLayout1"  
                  android:gravity="center"
                  android:layout_height="50dp">
        <ImageView android:id="@+id/imageView1" 
                   android:layout_height="wrap_content"
                   android:layout_width="wrap_content"
                   android:src="@drawable/logo"
                   android:paddingRight="30dp"
                   android:layout_gravity="left"
                   android:layout_weight="0" />
        <View android:layout_height="wrap_content" 
              android:id="@+id/view1"
              android:layout_width="wrap_content"
              android:layout_weight="1" />
        <Button android:id="@+id/categorybutton"
                android:background="@drawable/button_bg"
                android:layout_height="match_parent"
                android:layout_weight="0"
                android:layout_width="120dp"
                style="@style/CategoryButtonStyle"/>
    </LinearLayout>

    <fragment android:id="@+id/headlines" 
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="match_parent" />
</LinearLayout>

We could keep going through CSS features, but hopefully you’re seeing a pattern: you can do a whole lot to style your apps on Android, but the solutions almost always require a whole lot more code than it does on the Web.

And while it’s easy to gawk at some of Android’s XML verbosity, remember that it’s really, really hard to come up with a mechanism of styling UI components that’s clear, concise, and that works well in large-scale applications. You can definitely find CSS examples that are subjectively as bad as Android’s solutions, but having worked in both I’ll personally take CSS’s approach without a second thought.

To round out my argument let’s look at one other popular platform for rendering UI components: iOS.

Why styling iOS apps is hard

iOS is a bit unique in the software development world, as it’s one of the only software platforms I know of where the majority of your UI development is done through a visual tool. That tool is called storyboards, and you use them within Xcode to build apps for iOS and macOS.

Just to give you an idea of what I’m talking about, here’s what it looks like to add two buttons to a view in an iOS app.

It’s worth noting that you don’t have to to build iOS apps using storyboards, but the alternative is generating your most of your user interface in Objective-C or Swift code, and therefore storyboards are the development path that Apple recommends for iOS development.

NOTE A complete discussion of when storyboard development is and isn’t appropriate for iOS apps is out of the scope of this article. If you’re interested, check out this debate about the topic on Quora.

So to bring the conversation back to the top of this article, how do you style iOS UI components? Well as you might expect from a visual editor, there are easy ways to configure individual properties of UI controls. For example, if you want to change the background color of a button, you can do so pretty easily from a menu on the right-hand side of the screen.

Much like Android, the task of applying individual properties is very simple. But also like Android, things get much harder when you move beyond the basics. For example, how do you make multiple buttons look the same in an iOS app? Not easily.

iOS has this concept of outlets, which are essentially a mechanism for your Objective-C or Swift code to get a reference to user interface components. You can think of outlets sort of like document.getElementById() calls on the Web. To style multiple iOS UI components you need to get an explicit reference, or outlet, for each control on your storyboard, loop over them, and then apply your changes. Here’s an example of what a Swift view controller that changes the background color of all buttons looks like.

import UIKit

class ViewController: UIViewController {

    // A collection of button outlets that you fill using
    // Xcode’s storyboard editor
    @IBOutlet var buttons: [UIButton]!

    func styleButtons() {
        for button in self.buttons {
            // Apply a red background color by setting the view’s
            // backgroundColor property.
            button.backgroundColor = UIColor.red
        }
    }
    
    // This is the entry point to your view controller. iOS
    // invokes this function when your view loads.
    override func viewDidLoad() {
        super.viewDidLoad()
        self.styleButtons()
    }
}

The point here is not the specifics, so I’m not going to go over what each and every line of Swift code is doing here. The point is that styling multiple controls inevitably involves Objective-C or Swift code, something you can easily accomplish in CSS by defining a simple class name.

And as you might expect, more complex iOS styling tasks don’t involve less code. For example, creating a simple iOS “theme” involves a whole bunch of UIAppearance APIs, and dealing with multiple device types requires that you learn about the non-trivial topic of auto layout.

To be fair, native developers can make somewhat similar arguments about there being some bizarre features in CSS, and to a certain extent they’re right. After all, whether we’re talking about the Web, or a native platform such as iOS or Android, the task of positioning, styling, and animating user interface components, across all sorts of devices, is no easy task. Any comprehensive styling system must inevitably make tradeoffs, but, having worked in a number of software ecosystems, CSS stands out to me for a number of reasons.

Why CSS is more awesome

CSS is amazingly flexible.

CSS lets you separate your app’s concerns so that your styling logic is completely separate from your app’s main logic. The separation of concerns principal has been a bedrock of web development for the last two decades, and CSS’s architecture is one of the main reasons this approach is possible.

That being said, CSS is also flexible enough that you can ignore the separation of concerns principal if you’d like, and handle all your styling through application code. Frameworks like React were able to take this approach without needing to change the CSS language or architecture in any way.

Android and iOS have relatively strict mechanisms when it comes to styling your user interface controls, but on the web you have options, and you can pick the option that best suits your application’s needs.

CSS is a simple language, and therefore an excellent compiler target.

CSS is a relatively simple language. Think about it, at a high level all you have is a collection of selectors that define a series of name/value pairs. And that simplicity makes a whole lot of things possible.

One of them is transpilers. Because CSS is relatively simple, transpilers such as SASS and LESS were able to innovate on top of the CSS language and experiment with powerful new features. Tools like SASS and LESS have not only improved developer productivity, they’ve also helped influence the CSS specification itself, with features like CSS variables now being available in most major browsers.

But CSS’s simplicity enables more than just transpilers. Every theme builder or drag & drop building tool you see on the web is possible because of just how easy CSS is to output. The concept of a theme builder isn’t even a thing in the iOS or Android worlds, because the tool’s output would need to be a complete iOS or Android app, which isn’t exactly an easy thing to generate. (Instead of iOS/Android theme builders you tend to see things like app templates or app starters).

Here’s another one: you know how your browser’s developers tools are awesome and let you easily tweak the look and feel of your application? This is again CSS’s simplicity at work. iOS and Android have nothing that comes close to the visual development tools we have on the web.

One final example: on the NativeScript project we were able to allow developers to style native iOS and Android controls using subset of CSS, for example using Button { color: blue; } to style a UIButton or android.widget.Button. We were only able to do this because CSS is a flexible and easy to parse language.

CSS lets you do some amazing stuff.

And finally, the single biggest reason CSS is awesome is the sheer range of things developers have been able to build with a language of simple selectors and rules. The internet is full of "10 AMAZING CSS-ONLY EXAMPLES" posts that prove this point, but I’m going to embed a few of my favorites right here because I can.

See the Pen Full CSS 3D Solar System by Wayne Dunkley (@waynedunkley) on CodePen.

See the Pen CSS 3D Bending Effect – Page Flip by Fabrizio Bianchi (@fbrz) on CodePen.

See the Pen STAR WARS AT-AT Walker by r4ms3s (@r4ms3s) on CodePen.

Conclusion

So does CSS have its quirks? Sure. The box model is a bit weird, flexbox isn’t the easiest thing to learn, and it’d be great if features like CSS variables were available years ago.

Every styling system has its warts, but CSS’s flexibility, simplicity, and pure power have stood the test of time, and have helped make the web the powerful development platform it is today. I’m happy to defend CSS against the CSS haters, and I encourage you to do the same.

Header image based upon Valentines by Misha Gardner

Comments

  • Maximast

    For the first time someone who supports my thought process. Nice article.

  • I really couldn’t agree more. I’ve always thought CSS was amazing for styling. I remember back in the early 2000s coding in VB6 and wishing with everything I had that I could just use CSS to style everything.

    And then Node JS and Electron came and I was in heaven. But now I’m learning React Native and once again I’m crying for my separate .css file

    • But now I’m learning React Native and once again I’m crying for my separate .css file

      You should try NativeScript 😉

  • Jen Looper

    Terrific read!

  • Mike Henry

    You can subclass any UI element in iOS once and then apply it to that element in Storyboards. No need to loop over buttons or assign outlets. Just define how the button/table/cell/view should look one time and apply it as needed.

    • Ah, didn’t realize that. I’ll have to play with subclassing a little more, thanks!

  • Andrew Faulkner

    To be fair, I’ve never actually heard anyone mock CSS’ capability at styling. All the hate usually relates to its abilities as a layout solution, for which it’s far from ideal, even with flexboxes, media queries, and grids in play. Even the jokes you posted reflect that (since they’re both about CSS failing at positioning), and IMHO the example platforms you referenced actually have much easier to use layout mechanisms (at least the 2 I’ve used: Android and iOS). Whenever I have to build a complex layout with CSS, I usually find myself wishing I were using Android layouts or iOS storyboards again.

    Of course, I think this is one of those scenarios where no one notices when it works well, and everyone complains when it doesn’t. Working with CSS I always forget about the sheer agony of creating animations, customizing look-and-feel of built-in elements, or setting up themeable UI components on Android or iOS – all of which just blend into the background when working with CSS.

    As a (primarily) JS developer who frequently mocks CSS, I showed up all ready to argue…but instead you made a convert out of me: I’d never before noticed just how much better CSS is at styling and theming than pretty much anything else. In retrospect it should be obvious: after all, CSS usually gets credited with bringing the concept of “selectors” to the mainstream, because of how easy it makes it to programmatically zero in on collections of UI elements to style – and it’s the element selection aspect that (IME) generally makes styling so painful on any platform.

    Kudos, great article – you turned me from a CSS-hater to a CSS-for-styling lover, CSS-for-layout tolerater (baby steps :))

    • Matt McMatt

      I second that Andrew Faulkner! 😛

    • You make a good point about layout and positioning being the primary source of CSS complaints. But even there I would personally take CSS over Android & iOS without a second thought. I definitely agree that Android and iOS make the basics of layout super simple, but I personally struggle when I try to get into advanced problems like handling multiple screen sizes or animations.

      But to be fair I have some definite bias because I have far more web experience than I do iOS and Android experience. I’ve internalized how things like display: block work and am nowhere near deeply understanding concepts like auto layout.

      Glad you enjoyed the article 😄

  • danjah

    This is great! I always suspected the winner would be CSS by comparison, I just never had a concise description of platform flavors readily available!

  • Pingback: Dew Drop - May 31, 2017 (#2490) - Morning Dew()

  • GeoDanila

    Ever heard of XAML? 🙂

  • Ed Charbeneau

    Ok, I already like CSS. We’re in the same camp here. But then there’s Sass (.scss), I could write Sass for days and enjoy every minute. Oh how I love you Sass!

  • Taylor Hunt

    CSS’s simplistic design also lets clients do amazing things with it.

    • Incrementally render HTML streaming in from the network
    • Reevaluate and repaint quickly (not quickly enough to totally ignore, but, you know)
    • Its declarative nature allows new implementation approaches, such as Servo’s Webrender uploading web pages as scene graphs to the GPU. ≈40→200 fps is no joke.
    • Evolve without versioning, forward-compatibility issues, or restriction on new capabilities such as custom filters and paint worklets.
    • While user stylesheet never manifested as must-haves, the Stylish extension is impressively popular across all browsers. What other styling environments give users that ability?
    • Assistive technology can parse it to fix broken accessibility, such as ignoring what’s display:none

    The tradeoff is a lack of developer power, but the Web was ever thus.

    (Sorry for the double-post, Disqus likes flagging my comments as spam with Tracking Protection on.)

    • Thanks @disqus_HKSY3YC6pk:disqus,

      This is great. I didn’t even think about a few of these, and the incremental rendering and repaint abilities are especially important. Another few things native apps can’t really do.

  • Really nice TJ. At first I thought the post title was a bit silly, given how much struggle our team has had with only having the subset of CSS currently present in {N}. But after reading more, I see just how good we have it, compared to what we could be dealing with! Thanks for the post!

  • uyouthe

    I’m building a flowcharts editor. It’s all SVG, so I’ve chosen svg.js as the framework. Initially I solved styling problems using the framework’s tools, but when the things came to style merging and overriding, I was like “Damn, I’m reinventing CSS!”. I did some refactoring, and then 20 lines of CSS replaced 500 lines of JS, and it made my tool far more extendable, too.

    CSS is the best.

  • Declarative should always win over imperative, because it’s just simpler to deal with. That’s why CSS is awesome. Thanks for writing the article!

  • Bobort

    I’ve never had an issue with CSS. I always thought it was a very well-thought out declarative language. It seems to me that people ought to be complaining about how browser vendors implemented CSS. And, it seems to me, that we have come a long way since Microsoft’s browsers are doing pretty much what the other browsers are doing in their implementation. The problem was nearly always Internet Explorer, not CSS.

  • I <3 CSS even more now.

  • If CSS is so flexible and amazing, and doing anything on mobile is so hard…

    Where are CSS Storyboards? Why is it still basically impossible to create anything remotely close to mobile apps using CSS? And why each of the amazing CSS examples are easily hundreds of lines long with non-intuitive hacks, hardcoded values etc. which cannot be applied across components, whereas on mobile it’s usually a couple of lines of code (well, sometimes tens)?

    CSS is an increasingly designed-by-committee monstrosity.

  • Pingback: Daily links 2017-07-03 | Marcin Kossowski()