📝 CSS-Tricks 226: Websites Can Be Weird

View this newsletter on the web.

[Robin]: The first thing that caught my eye this week is this fabulous tutorial by Alex Trost where he walks us through how to make this rather nifty design:

This design is the work of Andy Barefoot, who’s really pushing forward the weirdness and pure magic of what’s possible with CSS Grid. Just check out his personal website, that happens to look something like this:

Andy has a ton of amazing Pens that he’s created over the years, including this eye-catching sneaker website:

I love work like this, it’s just the sort of stuff to remind me that we don’t always have to build things the way that we have. Websites can be weird! And peculiar! And that’s just what I love about Barefoot’s work.

📝 CSS-Tricks 225: Learning Things You’ve Been Avoiding

View this newsletter on the web.

[Robin]: One time I was interviewing someone for a UI engineering gig and noticed something interesting. We were building a UI that involved flexbox and the person opened up DevTools and started clicking up and down in the list of values available to them. And I shortly realized that this person understood that it was this property that would solve the problem, but they didn’t quite understand what combination of properties and values to use for the right solution.

Now, we shouldn’t ever mock someone for not knowing something — especially when it comes to the ever-changing and evolving field of web development — but what we can’t really forgive ourselves for is refusing to learn something out of stubbornness or embarrassment.

That was me a couple of weeks ago when it came to the flex CSS property. Out of pure stubbornness I refused to learn how it worked, and whenever I was confronted with something like this…

.parent { display: flex; } .child { flex: 0 1 auto; }

…I would find some way to fix the problem without flex. I mean, it looks so weird! I tend to hate CSS shorthands anyway, but I would see this everywhere. Why is that? Why do people keep writing code I don’t understand? Ugh!

And yet, dangit, I still refused to learn.

But after sitting down and writing out how each property works, things sort of clicked: the flex property tells the child element of a flex parent how to expand and shrink. That’s not scary at all! We can think of it like this:

/* This is just how I think about the rule above in my head */ .child { flex: [flex-grow] [flex-shrink] [flex-basis]; } /* or... */ .child { flex: [max] [min] [ideal size]; }

Somehow, translating it into “max, min, and ideal size” made it all make sense for me.

Anyway, understanding flex (as well as flex-grow, flex-shrink, and flex-basis) is important if we want to build modern UIs on the web today. But I guess my real point here is that the thing we’ve been avoiding learning about usually isn’t really as scary as we initially think.

And sitting down, being patient with ourselves is the best way to learn something new. Even if it is a little embarrassing.

📝 CSS-Tricks 224: VS Code Tasks

View this newsletter on the web.

[Robin]: One of the nifty things about VS Code is that you can run tasks when you open up a project. So instead of having to open up the command line and also have VS Code open at the same time, you can configure VS Code to run tasks like Gulp automatically. Chris wrote about this very thing and how he got a Gulp task running. This had me thinking, why don’t I do this for my own little site, too?

So, first up I opened the workspace for my site in VS Code. Then I selected the default task by hitting Command + Shift + P and selecting Tasks: Configure Default Build Task

After clicking this, VS Code rather smartly shows that there are a bunch of different options from the scripts section from within my package.json which looks something like this:

See that gulp dev & eleventy --serve? That’s what runs when I type npm start into the command line and it’s what boots up my local environment for my website. Anyway, once I selected Configure Default Build Task I selected npm start

Like I said, npm start runs every task within gulpfile.js and kicks off the Eleventy build process. Once that’s done now I can hit command + shift + b on a Mac and that task will pop off and start running in VS Code’s command line. Neat! That’s much faster than having to load two separate apps to build something on my personal blog.

Now, if I head to tasks.json, we can see this default task that we’ve setup. But I want to have this command run every time I open up this workspace (I’d prefer not to have to manually do it each dang time). So! I edited the task that looked like this:

{ "version": "2.0.0", "tasks": [
{
"type": "npm",
"script": "start",
"problemMatcher": ,
"label": "npm: start",
"detail": "gulp dev & eleventy --serve",
"group": {
"kind": "build",
"isDefault": true
}
}
] }

And then from here I can add the runOptions property and set runOn to folderOpen:

{ "version": "2.0.0", "tasks": [
{
"type": "npm",
"script": "start",
"problemMatcher": ,
"label": "npm: start",
"detail": "gulp dev & eleventy --serve",
"group": {
"kind": "build",
"isDefault": true
},
"runOptions": {
"runOn": "folderOpen"
}
}
] }

Once I’ve selected Allow and Run in the popup that appears after I save this file, I can now just open up this workspace and gulp dev & eleventy --serve will run automatically! The command line at the bottom will pop up and things will get started automagically. That’s pretty neat and saves me having to open up another command line app and type yet another command.

📝 CSS-Tricks 223: Core Web Vital Tooling

View this newsletter on the web.

Core Web Vital Tooling

Core Web Vitals is how Google measures the performance of any given site and you might’ve already heard the buzzwords like LCP, FID, and CLP. But — these are actually really useful metrics to figure out how to improve performance. So here they are again:

  1. Largest Contentful Paint (LCP)
  2. First Input Delay (FID)
  3. Cumulative Layout Shift (CLS)

In my head, I find it useful to translate these into questions:

  1. When can we see the content?
  2. When can we interact with the website?
  3. Is the website content stable yet?

Chris writes:

When I first got into caring about performance, it was all: reduce requests! cache things! Make stuff smaller! And while those are all very related to web performance, they are abstractly related. Actual web performance to users are things like how long did I have to wait to see the content on the page? How long until I can actually interact with the page, like type in a form or click a link? Did things obnoxiously jump around while I was trying to do something? That’s why Core Web Vitals are smart: they measure those things.

That’s why we need to think about performance from three different perspectives. So, for example: you might have a super fast LCP (meaning that the content is available very quickly). But! You might have a ton of ads and images and videos being loaded on the page which might impact the layout (CLS). This happens to me most frequently on large news websites — I try to click a link and then the rug is pulled out from beneath me and I’m now clicking a different link. Gah!

All of these different metrics for performance can be measured with a bunch of new tools, including SpeedCurve and Calibre, where Karolina Szczur wrote about their importance:

If you’re not tracking and improving your Core Web Vitals, your Performance Score will be lower. A worse Performance Score means lower search ranking and worse user experience for your customers.

Us web developers have to familiarize ourselves with this stuff if we want to make our websites fast and our customers happy.

Here’s another distinction that is worth wrapping your mind around. When doing performance testing, there is what is known as RUM (“real user monitoring”) and synthetic (e.g. run tests in a headless browser). Both of these are useful!

I mention this because I’ve seen some chatter recently talking about how one-or-the-other is the only one that matters. First, when it comes to Web Core Vitals, the metric First Input Delay (FID) can only be measured by RUM, so RUM is clearly important there, but also because, ya know, measuring actual users performance is important because that is real information about how your real users are experiencing your site. But once you have RUM, that means you’ve already shipped code to production. Synthetic data is the only kind you can get while you’re, say, running performance tests against Pull Requests, which is also a damn fine idea.

📝 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.