Fluid type sizes and spacing — Piper Haywood
Prompted by Utopia, Piper shares her methodology for fluid type in Sass.
Prompted by Utopia, Piper shares her methodology for fluid type in Sass.
Oh, this is smart! You can’t target pseudo-elements in JavaScript, but you can use custom properties as a proxy instead.
Robin makes a good point here about using dark mode thinking as a way to uncover any assumptions you might have unwittingly baked into your design:
Given its recent popularity, you might believe dark mode is a fad. But from a design perspective, dark mode is exceptionally useful. That’s because a big part of design is about building relationships between colors. And so implementing dark mode essentially forced everyone on the team to think long, hard, and consistently about our front-end design components. In short, dark mode helped our design system not only look good, but make sense.
So even if you don’t actually implement dark mode, acting as though it’s there will give you a solid base to build in.
I did something similar with the back end of Huffduffer and The Session—from day one, I built them as though the interface would be available in multiple languages. I never implemented multi-language support, but just the awareness of it saved me from baking in any shortcuts or assumptions, and enforced a good model/view/controller separation.
For most front-end codebases, the design of your color system shows you where your radioactive styles are. It shows you how things are tied together, and what depends on what.
A reminder that the contens of custom properties don’t have to be valid property values:
From a syntax perspective, CSS variables are “extremely permissive”.
Don’t write
fopen
when you can writeopenFile
. WritethrowValidationError
and notthrowVE
. Call that namefunction
and notfct
. That’s German naming convention. Do this and your readers will appreciate it.
Heydon cracks me up—his Patterns Day is going to have you crying with laughter; guaranteed!
Here he is talking about custom properties in CSS as part of his Making Future Interfaces video series.
Here’s a tiny lesson that I picked up from Trys that I’d like to share with you…
I was working on some upcoming changes to the Clearleft site recently. One particular component needed some SVG background images. I decided I’d inline the SVGs in the CSS to avoid extra network requests. It’s pretty straightforward:
.myComponent {
background-image: url('data:image/svg+xml;utf8,<svg> ... </svg>');
}
You can basically paste your SVG in there, although you need to a little bit of URL encoding: I found that converting #
to %23
to was enough for my needs.
But here’s the thing. My component had some variations. One of the variations had multiple background images. There was a second background image in addition to the first. There’s no way in CSS to add an additional background image without writing a whole background-image
declaration:
.myComponent--variant {
background-image: url('data:image/svg+xml;utf8,<svg> ... </svg>'), url('data:image/svg+xml;utf8,<svg> ... </svg>');
}
So now I’ve got the same SVG source inlined in two places. That negates any performance benefits I was getting from inlining in the first place.
That’s where Trys comes in. He shared a nifty technique he uses in this exact situation: put the SVG source into a custom property!
:root {
--firstSVG: url('data:image/svg+xml;utf8,<svg> ... </svg>');
--secondSVG: url('data:image/svg+xml;utf8,<svg> ... </svg>');
}
Then you can reference those in your background-image
declarations:
.myComponent {
background-image: var(--firstSVG);
}
.myComponent--variant {
background-image: var(--firstSVG), var(--secondSVG);
}
Brilliant! Not only does this remove any duplication of the SVG source, it also makes your CSS nice and readable: no more big blobs of SVG source code in the middle of your style sheet.
You might be wondering what will happen in older browsers that don’t support CSS custom properties (that would be Internet Explorer 11). Those browsers won’t get any background image. Which is fine. It’s a background image. Therefore it’s decoration. If it were an important image, it wouldn’t be in the background.
Progressive enhancement, innit?
Cassie posted a neat tiny lesson that she’s written a reduced test case for.
Here’s the situation…
CSS custom properties are fantastic. You can drop them in just about anywhere that a property takes a value.
Here’s an example of defining a custom property for a length:
:root {
--my-value: 1em;
}
Then I can use that anywhere I’d normally give something a length:
.my-element {
margin-bottom: var(--my-value);
}
I went a bit overboard with custom properties on the new Patterns Day site. I used them for colour values, font stacks, and spacing. Design tokens, I guess. They really come into their own when you combine them with media queries: you can update the values of the custom properties based on screen size …without having to redefine where those properties are applied. Also, they can be updated via JavaScript so they make for a great common language between CSS and JavaScript: you can define where they’re used in your CSS and then update their values in JavaScript, perhaps in response to user interaction.
But there are a few places where you can’t use custom properties. You can’t, for example, use them as part of a media query. This won’t work:
@media all and (min-width: var(--my-value)) {
...
}
You also can’t use them in generated content if the value is a number. This won’t work:
:root {
--number-value: 15;
}
.my-element::before {
content: var(--number-value);
}
Fair enough. Generated content in CSS is kind of a strange beast. Eric delivered an entire hour-long talk at An Event Apart in Seattle on generated content.
But Cassie found a workaround if the value you want to put into that content
property is numeric. The CSS counter
value is a kind of generated content—the numbers that appear in front of ordered list items. And you can control the value of those numbers from CSS.
CSS counters work kind of like variables. You name them and assign values to them using the counter-reset
property:
.my-element {
counter-reset: mycounter 15;
}
You can then reference the value of mycounter
in a content
property using the counter
value:
.my-element {
content: counter(mycounter);
}
Cassie realised that even though you can’t pass in a custom property directly to generated content, you can pass in a custom property to the counter-reset
property. So you can do this:
:root {
--number-value: 15;
}
.my-element {
counter-reset: mycounter var(--number-value);
content: counter(mycounter);
}
In a roundabout way, this allows you to use a custom property for generated content!
I realise that the use cases are pretty narrow, but I can’t help but be impressed with the thinking behind this. Personally, I would’ve just read that generated content doesn’t accept custom properties and moved on. I would’ve given up quickly. But Cassie took a step back and found a creative pass-the-parcel solution to the problem.
I feel like this is a hack in the best sense of the word: a creatively improvised solution to a problem or limitation.
I was trying to display the numeric value stored in a CSS variable inside generated content… Turns out you can’t do that. But you can do this… codepen.io/cassie-codes/p… (not saying you should, but you could)
I think Cathy might’ve buried the lede:
The knock on effect of this was removing media queries. As I moved towards some of the more modern features of CSS the need to target specific screen sizes with unique code was removed.
But on the topic of Sass, layout is now taken care of with CSS grid, variables are taken care of with CSS custom properties, and mixins for typography are taken care of with calc()
.
Personally, I’ve always found the most useful feature of Sass to simply be that you can have lots of separate Sass files that get combined into one CSS file—very handy for component libraries.
I had to read through this twice, but I think I get it now (I’m not the sharpest knife in the drawer). Very useful if you’re doing theming in CSS.
In defence of the cascade (especially now that we’ve got CSS custom properties).
I think embracing CSS’s cascade can be a great way to encourage consistency and simplicity in UIs. Rather than every new component being a free for all, it trains both designers and developers to think in terms of aligning with and re-using what they already have.
Remember, every time you set a property in CSS you are in fact overriding something (even if it’s just the default user agent styles). In other words, CSS code is mostly expressing exceptions to a default design.
On Ev’s blog, Marcin goes into great detail on theming an interface using CSS custom properties, SVG, HSL, and a smattering of CSS filters.
I was kind of amazed that all of this could happen via CSS and CSS alone: the colours, the transitions, the vectors, and even the images.
This article is about using custom properties and CSS grid together, but I think my favourite part is this description of how custom properties differ from the kind of variables you get from a preprocessor:
If you’re familiar with Javascript, I like to think of the difference between preprocessor variables and CSS Variables as similar to the difference between
const
andlet
- they both serve different purposes.
A handy guide to navigating all the new-fangled JavaScript.
Mike examines the real power of CSS custom properties compared to Sass variables—they can change at runtime.
I’m convinced that in almost all cases, responsive design logic should now be contained in variables. There is a strong argument too, that when changing any value, whether in a media query or an element scope, it belongs in a variable. If it changes, it is by definition a variable and this logic should be separated from design.
Harry demonstrates a really good use for CSS custom properties—allowing users to theme an interface.
Chris has a written a response to my post (which was itself inspired by his excellent An Event Apart presentation) all about CSS, variables, and abstractions.
I love this kind of old-school blog-to-blog discussion.