📝 CSS-Tricks 222: A Note about Color Variables

View this newsletter on the web.

[Robin]: I read this post from Dave Rupert about setting color variables, using a combination of Sass vars, CSS vars, and what Dave calls “semantic theme vars.” He writes:

Last week I got the opportunity to work on a side project that has no plans to include IE 11 in the support matrix and let me tell you; what a wonderful feeling! This opens the door to a lot of fun CSS, namely Custom Properties. Adding a proper “Dark Theme” to the application has been on the backlog for awhile and seeing some free time in my schedule, I sat down to hammer it out. It’s nothing super original, but I settled on a solution where I can layer in the ability to theme my application but also maintain some of the power of Sass in the process.

Dave decided to use a combination of all these things and I think it’s interesting because it shows the complexity of adding color options to a codebase. When we talk about color variables, it’s not as simple as pick a color, and then just use CSS variables in your project). Dave uses CSS and Sass vars together, like this:

html { --black: #{$black}; --grey: #{$grey}; --light-grey: #{$light-grey}; --white: #{$white}; --primary: #{$primary}; }

This is an interesting for me personally because I’ve been refactoring colors at Sentry, where I work. Our codebase has a theme.tsx file where we set a ton of color variables, like this:

const colors = { gray100: '#FAF9FB', gray200: '#F2F0F5', gray300: '#E7E1EC', gray400: '#C6BECF', gray500: '#9585A3', gray600: '#645574', gray700: '#4A3E56', gray800: '#302839', } as const;

We then have an alias object:

const aliases = { text: colors.gray800, border: colors.gray400, success: colors.green400, error: colors.red, disabled: colors.gray400, } as const;

The idea is that when we’re making a new component with Emotion, we don’t have to remember which gray is our default text color. So, in a component we might have something like this:

import styled from '@emotion/styled'; const Alert = styled('div')` background: ${p => p.theme.error}; color: ${p => p.theme.white}; `;

I like how Dave approaches things by combining Sass and CSS variables:

Digging in the code, I found dozens of places where we were using Sass color functions like lighten() and darken(). Programmatically generating colors (grays) still has a ton of value for this project. Unfortunately, CSS doesn’t have color functions (yet). Rather than letting this be a blocker for me, I decided I can have the best of both worlds.

--border: #{darken($light-grey, 6%)};

The lack of true CSS color functions is one of the last few Sass superpowers that I can’t really do without. Dave links to a proposal by Lea Verou where she wrote about how color functions might be implemented in CSS and that’s super exciting to me.

📝 CSS-Tricks 221: Move and Replace

View this newsletter on the web.

[Robin]: This week I’ve been moving into a new apartment and everything is, well, to put it kindly, an absolute nightmare. There’s a rat king of cables and three laundromat’s worth of clothes on the floor. Important documents are flung about all over the place in my kitchen, there are coffee cups in the plant pots, there are knives teetering on top of books, and I am now deadly certain that I’m breaking a dozen or more violations in my tenancy agreement. Drama!

Why am I talking about all this? Well, there is some method to the madness here. Yes, everything is disorganized and tragic but it makes sense in my head. I have made piles of gross stuff, organized bundles of categories which themselves happen to be very disorganized — and I eventually need to deal with them. Once I’ve built up enough courage I slowly walk over to a pile, give it a long, hard stare, and then dive in to fix it.

And I think is true of refactoring a big codebase, too.

Over the past few weeks I’ve been busy refactoring the styles in our app at Sentry — slowly, but surely. But I’ve started to take the approach that was recommended to me by my old mentor Kelly Sutton who in turn learned that from his mentor Kent Beck.

Anyway, step #1 in a refactor? Don’t refactor it, don’t edit the logic of the code itself. First, move all the junk into one spot.

In my case that means moving the five chunks of CSS that styles the Button component and move all of that into the same .less file. But I haven’t changed the logic yet, I haven’t removed any styles, as much as I might like to.

So what’s step #2 of a refactor after moving things? REPLACE! Purge every line of code ruthlessly because now you know that it all works in the order that it should. Delete, delete, delete. Anything that’s inefficient or weird or simply unhelpful? Bye! Send it all back to hell where it came from.

Now it’s important to mention that tech debt is going to happen to everyone but we have a decision as to whether it happens to us or we happen to it. Okay, that sounded smarter in my head. What I mean by that is there is unknown tech debt that hurts everyone and then there‘s the tech debt where everyone is focused on a plan to resolve it. So, at least we’re recognizing there’s a problem here with our CSS. That’s step #0 of any refactor.

But all I’ve been doing this week is move the mess around. I move a bunch of bad code into one spot, wait for tests to pass, and we learn that there are no regressions yet. That’s the plan, at least. We’re still in step #1 of the refactor, just as I’m still stuck in the first stage of moving into my new apartment; make big bundles of mess and then preparing myself to tackle each bundle one by one.

I guess my advice to myself here is this: small steps where you’re not being punk rock and deleting massive amounts of code will actually make things faster in the end. Try and break up every refactor project into two steps: Move and Replace, and from there you’ll be more focused, fewer regressions will happen, and it’ll ultimately be faster in the end.

Although yes, it’s embarrassingly messy and slow in the beginning. In fact, from a distance it even looks like you’re contributing to the mess. But dang it really does seem to work — so much so that when I’m refactoring things I become incredibly annoying:

“Move and replace,” I now whisper to myself. “Move and replace.”

📝 CSS-Tricks 220: The Principle of Least Power

View this newsletter on the web.

Just the other day Kilian Valkohof wrote this great piece about how to create a full-bleed layout effect where an element like an image breaks out from the grid you’ve established.

Kilian shows us how he does that with plain ol’ CSS:

body > *:not(img) { position: relative; max-width: 40rem; margin: auto; } 

The :not pseudo-class above will set the max-width of every element on a page that isn’t an <img> to have a max-width of 40rem. So you get something like this:

This isn’t the only way to create this full-bleed effect where images stretch across the whole page. A while back Josh Comeau wrote about how to create a full-bleed layout using CSS Grid and the whole post is absolutely worth reading.

But! Kilian argues that if the :not selector works, without having to setup a complex Grid solution to this problem then we should use it because his code abides by the principle of least power. Kilian then describes that principle like this:

When I build websites, I try to stick to the principle of least power. This states that you should use the least powerful language that does the job. In other words, don’t go straight for the more complex language (like JS) if a simpler language (like CSS or HTML) can also do the same thing. The simpler language will be more maintainable, more robust and easier to understand.

I think about this all the time, especially when it comes to design systems. Whenever I create a new component or a new design my thinking goes something like this:

  1. Can I use HTML?
  2. If not, can I get away with lightly styling the markup?
  3. Can I change the design to make this easier to implement?
  4. Dangit okay, if I can’t do that then I’ll hand-write some JavaScript to solve this problem.
  5. Eff it—okay, this is annoying—I’ll pull in a third-party library.

It’s all too easy to jump straight to step 5 here and pull in a third party library to solve our problems, or npm install something because we don’t want to have to go through the pain of the trying the first four steps. But with almost every codebase I’ve worked on I’ve found this—the principle of least power—is definitely the right way to approach web development in general.

All of this ties neatly into what Jim Nielsen mentioned just the other day when it comes to cheating entropy with old projects:

HTML, CSS, and JS are, in a semver sense, still at version 1.x. Whatever you wrote in 2018 or 2008 will still work. On the other hand, a project built on abstractions from native web technologies—frameworks, tooling, language sub/supersets—will contain innumerable dependencies with countless major version changes over time. Updating a single dependency often requires updating everything. Building on top of base web technologies, where possible, is a way to cheat the entropy and churn of modern web technology abstractions.

All that can be summed up like this: the principle of least power is progressive enhancement.

📝 CSS-Tricks 219: Design Systems and the Black Box

View this newsletter on the web.

Earlier this week, I watched this fantastic talk by Ethan Marcotte about the current state of design systems and I haven’t been able to stop thinking about it. The part that really stuck out to me though was this bit:

Creating modular components isn’t the primary goal or even the primary benefit of creating a design system. And what’s more, a focus on process and people always leads to more sustainable systems.

I love this talk but I find that a lot of the writing about design systems work out there focuses on how to make good docs, how to make things accessible, building marketing sites for your system, or focusing on color contrast. But I think the big weird problem about design systems that no one really talks about is that it can become extremely political.

I tend to forget this because I get so bogged down in the details of a design system, like caring about typography or refactoring CSS, etc. But as much as those details should be sweated, they can sometimes get in the way of bigger improvements that need to be made when it comes to the culture of your organization.

Design systems isn’t just about components, but as Ethan mentions in that talk, it’s about people and process. (I’m repeating this for myself because I keep forgetting that.) What does that really mean? Well, sometimes it’s a better use of your time to try and hire a team instead of fixing this one tiny problem with your docs. Or maybe not a team but just making the case to hire a dedicated front-end/UI engineer, as I’ve been doing this week.

A few weeks ago I realized that I had to snap myself out of trying to fix problems with our components or with accessibility or color and instead try to change the process of our organization and how we build things. Progress can often be made 1% at a time, but sometimes you need to confront the biggest hurdle of working on design systems…

…tackling the politics. Ugh.

Hiring, managing, making the case for a new team. All of that is design systems work just as much as the writing of code or auditing of components. And it can be pretty scary if you’ve never done that before.

My advice is to try and phrase the problem in a way that management will understand. Don’t say “our components are bad and should be better” — focus instead on the business arguments. Why would hiring a UI engineer help the company? How is a design systems team going to improve the bottom line? Making a case for a dedicated person or even a full team is the design systems work at its very hardest; trying to improve the people and the process at the same time. It’s what really differentiates a junior design systems person to someone who’s more senior.

And if I could give myself advice for a second I’d say: be patient, make your case, and then repeat it until it becomes so boring and obvious to everyone else that hiring a team is the right thing to do. It’s tough and can be demoralizing but sometimes is the only way to tackle design systems problems at scale: moaning loudly in a British accent.

Well, at least that works for me.

📝 CSS-Tricks 218: Web Components, Colorful Design Systems, Onboarding Animations

View this newsletter on the web.

Color within Constraints

Here’s a fantastic piece by Linzi Berry about the design systems team at Lyft and how they work on their color guidelines:

On the surface color seems simple, but getting 100+ designers and engineers to follow guidelines that are a part of literally everything they make is a huge undertaking. To put it in perspective: over 50% of Lyft’s design system team’s office hours, high visibility projects and inner team disagreements are color related. We’ve learned a lot over the past three years. It sure as hell ain’t perfect, but it’s working pretty well so far.

This is partly the reason why, at Sentry, we decided to make two color systems: UIs and charts. For most of the UI we can work within an extremely small band of colors — buttons, text, etc. — because we often don’t need that much variation in styles. But charts most certainly do. And since our app has a whole bunch of complex chart variants then that helps us draw this line between them.

That distinction between UI colors and chart colors helps us keep things consistent. But also it’s worth noting that the problems Linzi’s team at Lyft are trying to tackle are much more complex, with hundreds of designers and engineers.