Writing CSS Algorithms | Lara Schenck


I shared a Tweet earlier this week about “artifacts from the development of a CSS algorithm”. I’m glad I acted quickly on the sharing impulse, but it’s so much better to post that kind of content here on my own website. So, this post started out with the intention of quickly recapping that Tweet and moving on to the next installment of the Designgineering Chronicles (which is going to be a doosie…) but, as is often the case, the quick, short blog post becomes something much longer…

We now have another written portion of the Algorithms of CSS!!! Major win! It’s out of order, but I wrote it and I’m happy about it and will organize them all at a later date.

Some Background and A Definition

Back to the topic at hand…CSS algorithms! I’m so excited!! Before I explain how to write one, let me quickly answer the question: What is a CSS algorithm?

Eventually there will be a specific post with more details, but for now, this definition will suffice:

A CSS algorithm is well-defined declaration or set of declarations that produces a specific styling output.

Me, in version 2 of the Algorithms of CSS at WordCamp US, 2018.

Phrased another way, a CSS algorithm is a very intentional and well thought-out utility pattern.

At the time of this writing, CSS algorithms are not really a thing, but I think they could be. I adopted this concept in my own development practice last year, and it’s been working really well for me both in my work-work and side-work of speaking and writing. The phrase “CSS algorithms” is helpful in a variety of ways, including but not limited to:

  • a useful paradigm for naming (naming is the hardest, after all),
  • a familiar concept for those coming to CSS from back-end development (who might write CSS off as hard/weird/annoying/illogical),
  • an intriguing concept for those new to web development (gets more people interested in CSS!),
  • an indication that CSS is a designed language (as Rachel Andrew puts it) that we can do a lot of cool stuff with

Also, words, in general. Does it seem like front-end development – specifically UI development – is lacking in official verbiage compared to other types of programming? That’s another topic. Back to what we are here for…

How to Write a CSS Algorithm

In version 1 of the Algorithms of CSS, the latter half of the talk reviewed applying the process for writing algorithms in whiteboard interviews to writing CSS algorithms. Here are the primary stages of white-boarding an algorithm, according to Cracking the Coding interview (I think…):

  1. Pseudo-code
  2. A brute force solution
  3. Testing the algorithm, or walk-though
  4. Optimization

These map very well to writing CSS algorithms. I will now walk through these staged with a recent, specific example for the overall article layout for the Cantaloupe redesign at work (read more about that here). There was a bit of nuance to this layout; an element that did not behave like the others. It jumped to a different cell and became sticky at a certain size. It was ripe for an elegant, algorithmic approach with CSS Grid!

In any programming language, it’s all too easy to jump straight into code when five minutes of planning would have saved hours. When writing a CSS algorithm, it goes without saying that we choose the latter!

Step 1: Pseudo-Coding with Boxes

I started out by pseudo-coding my algorithm as boxes because, after all, as CSS developers, we are programmers of boxes (another Tweet that would be much better off as a blog post). Here are the boxes:

This is a scratch pad I keep next to my computer for pseudo-coding algorithms.

I was working from Invision mockups for the mobile layout, desktop, and large desktop. For me, the key things to accomplish in this pseudo-code stage are:

  1. Figure out what the boxes are vs. what they will contain
  2. Give the boxes names
  3. Make a list of exactly what changes between breakpoints
  4. Determine what is the responsibility of this algorithm, and what is the responsibility of something else

A big part of writing CSS algorithms is thinking about the single responsibility principle. This slide from v2 of the Algorithms of CSS illustrates that well:

Packing too much responsibility into one tool results in a less useful tool!

Sorry, spork…

So, since this algorithm was for the overall article layout, properties like background-color or font-size are outside of it’s scope.

Step 1.5: Setting Up Your Workspace

Now that we have a pretty good idea of what our algorithm needs to do – and, equally important, what it doesn’t need to do – it’s time to start programming some actual boxes in safe space, ideally outside of the production code-base. This space needs to be fast and isolated, but also representative of the production environment, set up with all the tools you need to write CSS e.g. SCSS mixins and variables. Brad Frost calls it the Frontend Workshop Environment, and CodePen was basically built for this purpose.

At PMC, we have some architecture for prototyping within a pattern library, which for us, is a flat HTML site generated from SCSS comments via kss-node.

I want to emphasize, though, that it does not matter where you write this code or what it looks like. The goal here is to have a place to figure out your algorithm that is fast and where there is no judgement or risk of affecting other parts of the site. Here are a few practices I’ve been using that I’ve found particularly helpful.

scratch-pad.scss

In our SCSS structure, there is a file called scratch-pad.scss that is only loaded in the pattern library (a.k.a. the workshop) and includes a // stylelint-disable comment at the top to disable the linter.

The primary contents are styles namespaced with .kss-* that assist in prototyping – things like .kss-add-height which adds 1000px of height, or a series of nested .kss-box selectors that add different background colors and border colors.

.kss-box { background-color: lemonchiffon; border: 5px solid skyblue; margin: $spacer-025; > .kss-box { background-color: aliceblue; border-color: hotpink; > .kss-box { background-color: white; border-color: peachpuff; border-width: 1px; } }
}

It’s definitely smelly CSS, but I don’t care…that’s what the scratch pad is for!

It also imports breakpoint-label.scss – a separate helper tool that adds a label indicating the current breakpoint:

See the Pen Breakpoint Label by Lara Schenck (@laras126) on CodePen.

Step 2: Brute-Force Solution

Now it’s time to get something working. In your safe, workshop space, try different approaches and figure out what works and, equally important, what doesn’t work.

Create Your Named Boxes

Once you have a workshop environment set up, however you choose to do that, it is time to scaffold the markup and apply the names to your boxes.

For the article grid, I used a BEM convention to identify the boxes e.g. .a-article-grid contained .a-article-grid__main and .a-article-grid__social, etc. Then I filled those boxes lorem ipsum, placehold.it images, and a few includes of existing patterns where I could.

Here’s what my pattern library entry ended up looking like for the article grid – complete with the breakpoint label and some horizontal overflow I had to figure out in due time:

Figure out the Algorithm / Write Smelly CSS That Works

What is that “well-defined declaration or set of declarations” that will accomplish your goal? What boxes require what declaration(s)? How do properties and values update as breakpoints change? Which CSS features will you use to solve your problem? Are custom properties a pure gift from God and The One True Way?

This is programming – you are figuring out the set of instructions for a computer to solve a problem, 💯.

(Side note: I’ve been working with this subject matter for over a year now, and the more experience I gain in development, the more I’m like…CSS is a programming language, goddammit! I keep expecting to encounter an argument that will truly convince me otherwise, but so far I haven’t. It’s also worth noting that I am aware this could be cognitive dissonance.)

Step 3: Walk-through

A successful brute-force step should result in a clear understanding of your algorithm’s core steps and the tools you need to accomplish the task. In a whiteboarding interview, this is where you would talk through each step of your algorithm and propose ideas for optimization,

In CSS-algorithm-land, this is where you simulate the rendering engine in your brain to figure out what, of the code you’ve written so far, is part of the algorithm and what declarations aren’t used or should be the responsibility of a different class. In other words, trim the fat from your algorithm. Make sure the declarations you have are the only ones you need. Is there a stray width: 100%; from your brute force solution that isn’t actually doing anything?

An understanding of the domain in domain-specific is essential here. You don’t have to be an expert, but you need a mental model of the browser that is clear enough to simulate the cascade and rendering. There are lots of resources for learning this, many of which are listed here.

Step 4: Optimize (and refactor)

For me, the walk-through, or “rendering engine in my brain”, of step 3 and the optimization in step 4 are tightly linked, and often result in a refactor that means going back to 2 to figure out a different approach.

This slide from v1 of the Algorithms of CSS sums up the entire process nicely:

Your smelly code gradually morphs into a beautiful flower!

In general though, this optimization step means work the algorithm into your system and document it. If all of your code is in scratch-pad.scss, figure out where it is supposed to live and write a description of what the algorithm does, where it should and should not be used, and how it should be maintained.

At PMC, we have a directory specifically for algorithms in our ITCSS architecture (blog post and image illustrating that will come at a later date), and the comments can go in a KSS comment to be parsed as documentation in the pattern library. I also like to clean up the pattern library entry – especially for layout algorithms – so that the boxes clearly indicate the algorithm. Here’s what it ended up looking like, and here is the corresponding SCSS file:

The entry for the Article Grid algorithm in the Cantaloupe pattern library.

Similarly, I think it is important to clean up the pattern markup to indicate only the relevant elements for the algorithm. I like to use a // to help with readability in the class attribute – it might be overkill in this case, but it does help when there are a lot of utility classes:

<div class="a-article-grid // kss-box"> <header class="a-article-grid__header // kss-box"> <div class="kss-height-sm"></div> </header> <div class="a-article-grid__author // kss-box"> <div class="kss-height-sm"></div> </div> <div class="a-article-grid__social // kss-box"> <div class="kss-height-sm"></div> </div> <div class="a-article-grid__main // kss-box"> <div class="kss-height-lg"></div> </div>
</div>

The final step, of course, is getting this algorithm from the pattern library into the production code-base, and we must not underestimate the complexity of this task…we should also not underestimate the possibility of testing the implementation of algorithms! I haven’t done that yet, but my mind is buzzing with the possibilities.

Parting Notes For Those Interested in Writing CSS Algorithms

I think it is safe to assume that you do not have a specific namespace and directory devoted to algorithms in your CSS architecture. It’s also very possible that if you created one, there would be some awkward questions in a code review.

That said, I want to end with a couple of suggestions for those who would like to write CSS algorithms but not actually call them algorithms:

  1. Call them utilities (I mean, they are utilities), but figure out a way to mark them as slightly different or more involved that usual utilities so that other developers know that they requires specific usage and maintenance.
  2. If it is an algorithm for a specific piece of interface that already has a file, add it to that file CSS and group the declarations under concise comments with a note to consider abstracting the declarations to a UI-agnostic pattern if they prove re-usable.
  3. …I will definitely think of more, and will add them later!

Finally, what do you think? Do you already write CSS like this? Is this useful?