Archive

Archive for December, 2021

Consistent, Fluidly Scaling Type and Spacing

December 16th, 2021 No comments
Screensjhot of the type-scale.com type scale tool. It displays eight variations of font sizes in black on a white background starting from largest to smallest vertically. To the left of the examples are options to configure the output, including base font size, type of scale, Google font selection, and preview text.

When Chris first sent me this prompt, I was thinking about writing about progressive enhancement, but that subject is so wide-reaching to be one thing and all too predictable, especially for those already familiar with my writing. Saying that, what I’m going to outline in this article also isn’t just one thing either, but the day I meet a writing prompt exactly will be the day pigs start flying. This one group of things, though, will change how you write CSS.

I personally think this group of things lets a lot of sites down—especially in a responsive design sense. The things in this group are typography and spacing. So often, I see inconsistent spacing—especially vertically—that makes content hard to scan and creates this subtle, disjointed feeling. The same goes for type: huge headings on small viewports, or heading hierarchies that visually have no contrast in size, rendering them useless in a visual sense.

There is a pretty easy fix for all of this using a sizing scale and fluid type, and I promise it’ll make your websites look and feel heaps better. Let’s get into it.

What the heck is a sizing scale?

A sizing scale is a uniform progression of sizes based on a scale—or, more accurately, a ratio.

In that screenshot of type-scale.com, I’ve selected a “Perfect Fourth” scale which uses a ratio of 1.333. This means each time you go up a size, you multiply the current size by 1.333, and each time you go down a size, you subtract 1.333.

If you have a base font size of 16px, using this scale, the next size up is 16 * 1.333, which is 21.33px. The next size up is 21.33 * 1.333, which is 28.43px. This provides a lovely curve as you move up and down the scale.

CSS clamp() and type fluidity

For years, if you were to say, “Hey Andy, what’s your favorite CSS feature?” I would immediately say flexbox, but nah, not these days. I am a [clamp()](https://developer.mozilla.org/en-US/docs/Web/CSS/clamp()) super fan. I wrote about it in more detail here, but the summary of clamp() is that it does clever stuff based on three parameters you give it:

  • a minimum value
  • an ideal value
  • a maximum value

This makes for a very useful tool in the context of fluid typography and spacing, because you write CSS like this:

.my-element {
  font-size: clamp(1rem, calc(1rem * 3vw), 2rem);
}

This tiny bit of CSS gives us full responsive text sizes based on the viewport width with handy locks to make sure sizes don’t get too big or too small.

It’s really important to test that your text is legible when you zoom in and zoom out when using clamp. It should be very obviously larger or smaller. Because we’re using a rem units as part of our fluid calculation, we’re helping that considerably.

Putting it all together

Right, so we’ve got a size scale and CSS clamp() all set up—how does it all come together? The smart people behind Utopia came up with the simplest, but handiest of approaches. I use their type tool and their spacing tool to create size scales for small and large viewports. Then, using clamp(), I generate a master size scale that’s completely fluid, as well as a Sass map that informs Gorko’s configuration.

$gorko-size-scale: (
  '300': clamp(0.7rem, 0.66rem + 0.2vw, 0.8rem),
  '400': clamp(0.88rem, 0.83rem + 0.24vw, 1rem),
  '500': clamp(1.09rem, 1rem + 0.47vw, 1.33rem),
  '600': clamp(1.37rem, 1.21rem + 0.8vw, 1.78rem),
  '700': clamp(1.71rem, 1.45rem + 1.29vw, 2.37rem),
  '800': clamp(2.14rem, 1.74rem + 1.99vw, 3.16rem),
  '900': clamp(2.67rem, 2.07rem + 3vw, 4.21rem),
  '1000': clamp(3.34rem, 2.45rem + 4.43vw, 5.61rem)
);

This snippet is from my site, piccalil.li, and the typography is super simple to work with because of it.

You could also translate that into good ol’ CSS Custom Properties:

:root {
  --size-300: clamp(0.7rem, 0.66rem + 0.2vw, 0.8rem);
  --size-400: clamp(0.88rem, 0.83rem + 0.24vw, 1rem);
  --size-500: clamp(1.09rem, 1rem + 0.47vw, 1.33rem);
  --size-600: clamp(1.37rem, 1.21rem + 0.8vw, 1.78rem);
  --size-700: clamp(1.71rem, 1.45rem + 1.29vw, 2.37rem);
  --size-800: clamp(2.14rem, 1.74rem + 1.99vw, 3.16rem);
  --size-900: clamp(2.67rem, 2.07rem + 3vw, 4.21rem);
  --size-1000: clamp(3.34rem, 2.45rem + 4.43vw, 5.61rem);
};

This approach also works for much larger sites, too. Take the new web.dev design or this fancy software agency’s site. The latter has a huge size scale for large viewports and a much smaller, more sensible, scale for smaller viewports, all perfectly applied and without media queries.

I’m all about keeping things simple. This approach combines a classic design practice—a sizing scale—and a modern CSS feature—clamp()—to make for much simpler CSS that achieves a lot.

Categories: Designing, Others Tags:

Topological sort

December 16th, 2021 No comments

Jordan Scales explores the computer science concept of topological sorting, and what it might look like if applied to the concept of z-index in CSS. So, you don’t express what the z-index should be directly; instead, you say exactly what other element you want to be on top of.

I think it’s more of a proof-of-concept, but it’s fun to look at anyway:

const resolver = new ZIndexResolver();

// A nav with dropdowns
resolver.above(".nav", "main");
resolver.above(".dropdown", ".nav");
resolver.above(".submenu", ".dropdown");

// Tooltips in the document
resolver.above(".tooltip", "main");

// Modals should go above everything
resolver.above(".modal", ".nav");
resolver.above(".modal", ".submenu");
resolver.above(".modal", ".tooltip");

console.log(resolver.resolve());

That produces an array in the right order:

[ '.modal', '.tooltip', '.submenu', '.dropdown', '.nav', 'main' ]

…which you can skoosh into CSS:

main { z-index: 0; }
.nav { z-index: 1; }
.dropdown { z-index: 2; }
.submenu { z-index: 3; }
.tooltip { z-index: 4; }
.modal { z-index: 5; }

The problem I see here is that it doesn’t account for stacking contexts. And if there is a bug with z-index, it’s always the stacking context. There is no possible z-index value that will raise up an item in a lower stacking order above any other items that are in a higher stacking context. So, to make something like this work effectively, I think it would have to know what (possibly nested) stacking context each item is in, then either attempt to jostle the stacking context themselves, or warn you that what you are asking for won’t work.

To Shared LinkPermalink on CSS-Tricks

Categories: Designing, Others Tags:

HTML Sanitizer API

December 16th, 2021 No comments

Three cheers for (draft stage) progress on a Sanitizer API! It’s gospel that you can’t trust user input. And indeed, any app I’ve ever worked on has dealt with bad actors trying to slip in and execute nefarious code somewhere it shouldn’t.

It’s the web developer’s job to clean user input before it is used again on the page (or stored, or used server-side). This is typically done with our own code or libraries that are pulled down to help. We might write a RegEx to strip anything that looks like HTML (or the like), which has the risk of bugs and those bad actors finding a way around what our code is doing.

Instead of user-land libraries or our dancing with it ourselves, we could let the browser do it:

// some function that turns a string into real nodes
const untrusted_input = to_node("<em onclick='alert(1);'>Hello!</em>");

const sanitizer = new Sanitizer();
sanitizer.sanitize(untrusted_input);  // <em>Hello!</em>

Then let it continue to be a browser responsibility over time. As the draft report says:

The browser has a fairly good idea of when it is going to execute code. We can improve upon the user-space libraries by teaching the browser how to render HTML from an arbitrary string in a safe manner, and do so in a way that is much more likely to be maintained and updated along with the browser’s own changing parser implementation.

This kind of thing is web standards at its best. Spot something annoying (and/or dangerous) that tons of people have to do, and step in to make it safer, faster, and better.

To Shared LinkPermalink on CSS-Tricks

Categories: Designing, Others Tags:

Maybe there kinda is background-opacity?

December 15th, 2021 No comments

I was reading Jake’s “Cross-fading any two DOM elements is currently impossible” which is a wonderfully nerdy deep dive into how there is no real way to literally cross-fade elements. Yeah, you can animate both of their opacities, but even that isn’t quite the same. Turns out there is a Chrome/WebKit-only CSS function call called -webkit-cross-fade() that does the trick. MDN says it’s specced, but the implemented version differs, so it’s a bit of a mess… but it does exist:

.el {
  background: -webkit-cross-fade(url(img1.svg), url(img2.svg), 50%);
}

I didn’t even know that was a thing.

The first thing I thought of was: if one of the images was just a blank transparent image, wouldn’t that apply partial transparency to the other one? And thus it’s kind of a proxy for background-opacity (which doesn’t exist but feels like it should).

I gave it a test to see if it would work:

CodePen Embed Fallback

It seems to work! This is the meat of it:

.el {
  background-image: -webkit-cross-fade(
    url(image.jpg),
    url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7),
    50%
  );

That’s a 1px transparent GIF Base64 encoded.

It doesn’t work in Firefox but it does in everything else. Plus, you can test for support right in CSS and do something different if this isn’t just an enhancement.

@supports (background: -webkit-cross-fade(url(), url(), 50%)) {

  /* Only apply the idea if supported, do the Firefox fallback outside of this */

}

That’s baked into the demo above.

Categories: Designing, Others Tags:

The Vite Ecosystem

December 15th, 2021 No comments

Matias Capeletto covers the breadth of Vite, from the technological shoulders it stands on, to the peers exploring similar territory, to the other technologies it supports, to the frameworks that now use it primarily, and more. The fact that that a post that is this thick like this exists is a testament to Vite’s meteoric rise.

One of the strongest points in Vite is the ecosystem around it. Vite took responsibilities from frameworks (common web patternsglob importsHMR APISSR primitivesbuild optimizations), freeing other maintainers from reinventing the wheel each time by offering a common ground where to collaborate, fostering a lot of explorations in the space. Maintainers from several popular frameworks have chosen Vite as their recommended build tool, and are now deeply involved in Vite core development, participating in discussions and directly working on fixes and features. 

The first commit to Vite was April 19, 2020 for gosh sakes.

I think Matias is right. When you take responsibility away from other technology and say I got this part, it’s commodity stuff anyway, you focus on what makes you special, that’s the right formula. Just like a good startup.

To Shared LinkPermalink on CSS-Tricks

Categories: Designing, Others Tags:

Remove Trackers

December 15th, 2021 No comments

Earlier this week, I tried out a starter theme for a blog platform. The theme had loads of nice default features: pretty typography, fancy navigation, dark mode widget… and a couple of default trackers I really don’t want just sitting there in a header component, waiting for me to add my account information.

As web development has become increasingly complex, more starters, frameworks, and embeddable tools have been created to simplify our developer experience. Just paste this one line of code into the of your site, and you’ll be a 10× full stack developer in no time. Sometimes we’ll pull out a feature we don’t want or the code we don’t need, but who has the time for a line-by-line review? If you got a feature for free, you might as well use it!

Over-simplifying our setup is risky. When we don’t fully understand what we’ve embedded on our site, we give up control of that feature to an unknown third party. We assume the maintainer knows best because the repository has a load of stars on GitHub or because a big name uses that same script on their site. Somebody must have checked this package is legit, right?

The malicious risk

Malicious scripts for password jacking and other nefarious purposes are sometimes found in popular npm packages. Cryptojacking, where crypto miners are installed on your site without your knowledge, are more common. Just recently, Alibaba Cloud services were targeted to mine the Monero cryptocurrency. If we’re a customer of a hacked service, we might hope our provider lets us know if our site is hacked in a timely fashion. If it’s an open source package, we’ve just got to hope we’re online when someone discovers the vulnerability so we can get our sites updated quickly.

The reliability risk

Many third parties we rely on for critical features are just incompetent or unreliable. We make jokes when some big internet infrastructure goes down and leaves us with no choice but to take it easy at work, but it’s not all fun and games for sites providing vital utilities and information for people.

For many years, we’ve been sold on third-party solutions to improve performance issues on our sites. And, occasionally, you will find a service that genuinely serves your site faster and in more locations across the globe than you can throw together yourself. But the majority of the most popular sites on the web have way more than one third-party script embedded on their site. From my work on Better Blocker, I can tell you that around ten third-party scripts is low, and as many as thirty on one homepage is common, especially on news sites. Does that many third-party scripts on one page have a positive impact on performance?

The privacy risk

Whether or not the third-party feature we’ve installed on our site is nefarious, incompetent, unreliable, or does its job, it’s always a privacy risk for our site visitors.

In a world where developer experience is often the priority, it’s too easy to forget we’re using these tools to build experiences for other people. And we have a responsibility to build experiences that don’t put our site’s visitors at risk.

Any third-party script, or any resource that can log visitor information, can be considered a tracker. At best, it has tracker potential. Your analytics, fonts, iframes, content delivery networks, CAPTCHAs — they all have the potential to collect information about your site’s visitors. What information, how much, and how often depends on what the feature does and the access you’ve provided it. That information collected about an individual could be used to sell them ads, build sellable profiles of them or even be used to discriminate against them.

I know privacy isn’t a popular topic in the web community. It feels like we’re already near the bottom of the slippery slope… and sometimes it’s easier to give up than to address how reliant we are on privacy-exploiting funding models. But there are small changes we can make to protect our visitors, even if we simply start with our own personal projects.

1. Review the third-party tools you use

Do you really need two different analytics scripts on your site? Can you embed that font locally instead? Reviewing the tools you already use gives you a manageable way to improve the privacy of your project a little at a time. And you’ll get a bonus when your site’s performance improves.

2. Use privacy-respecting alternatives

Over the last few years, privacy-respecting alternatives to mainstream technology have become more popular. One of my favorite sites is switching.software, which helps you find alternatives to the popular tools you use every day. Good Reports is another one that explains the reasoning behind each recommendation.

Privacy isn’t as hard as giving up the defaults

In this post, I decided not to go into the legal issues around privacy on the web. Making sites that adhere to laws and regulations around respecting rights is essential, but we’re more likely to make great experiences for the people using our sites if we care about their privacy, rather than worrying about what we can get away with on the legal side.

Privacy is not as hard as giving up the defaults, the tools that save us time, or uncritically copying our colleagues’ approaches. But removing one tracker at a time, we can make a difference.

Categories: Designing, Others Tags:

The UI fund

December 15th, 2021 No comments

Google is handing out bucks for CSS-related projects, so you might as well know about it! Nicole Sullivan:

All of us who work on the web regularly benefit from the work of people who create specifications, tools, demos, tutorials, and polyfills. Many of these resources are side projects, made available and supported free of charge. They exist because someone saw a need, created something to meet it, then shared it with the rest of the ecosystem.

We want to recognize and help support this work and invest in the CSS ecosystem.

Ya know how esbuild has seriously shaken things up for the JavaScript processing world? Maybe we need a cssbuild? It would process imports and do bundling (something we generally rely on Sass for). The point would be extreme speed. Maybe it would be plugin-based and compatible with the PostCSS API so that existing PostCSS plugins would work on it. Maybe it could make sourcemaps and do modification. Maybe it would run your Sass, too, I dunno. But something to spark the CSS ecosystem like that could be cool.

Or apply for money to do extreme accessibility testing and implementation on a public design system.

To Shared LinkPermalink on CSS-Tricks

Categories: Designing, Others Tags:

Read Your Website

December 14th, 2021 No comments
Top view of a grill showing 12 square burger patties cooking.

When’s the last time you read your website? Like out loud in the lobby of a Starbucks on a weekday afternoon, over the phone to your parents, or perhaps even as a bedtime story for your kids.

No worries, this isn’t a trick question or anything—just a gut check.

If there’s only one thing you can do to make your website better, then you could do a heckuva lot worse than taking some time to read it. Seriously, do more than look at the words—read them and take in everything that’s being said from the top to the very bottom. And really get in there. I’m talking about opening up everything in the navigation, expanding accordions, opening modals, and taking it all in. Read it the way Wendy’s makes their burgers: no cut corners or nothing.

Credit: mashed.com

Content: All hail the… king?

I’ve heard for years that content is capital “K” King of the capital “W” Web. In my personal experience, though, I routinely see content treated more as a pauper in projects; the lowest rung of the web ladder saved as an afterthought for when everything else is done. FPO all over. It’s not so much that no one cares about what the website says, but that a great deal of attention and effort is placed on design and architecture (among other things, of course), to the extent that there’s little-to-no time to drive an effective strategy for content.

But again, that’s just my experience, and there have certainly been exceptions to that rule.

The problem, I think, is that we know just how effective good content is but often lack the confidence, tooling, and even a clear understanding of content’s role on the web.

Content is problem solving

When crafted with care, content becomes much more than strings of text. That’s because content is more than what we see on the front end. It is in the alt attributes we write. It’s also the structured data in the document . Heck, we sometimes even generate it in the CSS content property.

We start to see the power of content when we open up our understanding of what it is, what it does, and where it’s used. That might make content one of the most extensible problem-solving tools in your metaphorical shed—it makes sites more accessible, extracts Google-juicing superpowers, converts sales, and creates pathways for users to accomplish what they need to do.

Content wants to be seen

Content is like my five-year old daughter: it hates being in the dark. I’d argue there’s little else that’s more defeating to content than hiding it. Remember our metaphorical tool shed? Content is unable to solve problems when it’s out of sight. Content is that cool dorm room poster you couldn’t wait to hang up the moment you stepped foot on campus—show it off, let it do its thing.

The way I see it, if something is important enough to type, then it’s probably important enough to show it too. That means avoiding anything that might obstruct it from a user’s view, like against a background with poor contrast or content that overflows a container. Content is only as good as it is presented. Your website could sport the greatest word-smithing of all time, but it’s no good if it’s hidden. Content wants to be seen.

Are there times when it’s legitimately fine for content to be unseen? You betcha. Skip to content links, for one. I’m not once of those armchair designers (wait, aren’t all designers in some sort of chair?) who is going to tell you certain UI elements—like modals, accordions, and carousels—are evil. It’s more about knowing the best way to present content, and sometimes containing it in a collapsed

/

element is the best call.

But please, for the sake of all virtual humanity, use elements to enhance content, not mask its issues.

Content is efficient

They say a picture is worth a thousand words, right? I mean, that’s cool, I guess. But what exactly are those words and who decides what they are? The end-user, of course! Images are mostly subjective like that, which is what makes them a great complement for content. But images as complete content replacement? I imagine there are way more times where pairing content with imagery is more effective than an image alone.

It depends, of course.

Something we can all agree on is that content is way more efficient than most images. For one, there’s less room for ambiguity, making content more efficient to get a point across. Who needs the representation of a thousand words when we can communicate the same thing just as effectively in a few typed words?

Then there are plenty of accessibility considerations to take into account with images. A background image is unable to convey an idea to a screen reader; that is, unless we inline it, set the alt attribute, and use crafty CSS positioning to create some sort of faux background (faukground?). Even then, we’re already dealing with the alt attribute, so we may as well put that content to real use and display it! That’s way more efficient than coding around it.

We haven’t even gotten into how much larger the kilobytes and megabytes of an image file are compared to content bytes, even in an article that’s chock-full of content like this one. And, sure, this warrants a big ol’ caveat in the form of web fonts and the hit those can have on performance, but such is life.

Content and design work better together

Just because I mentioned content being king earlier doesn’t mean I believe it rules everything else. In fact, I find that content relies on design just as much as design relies on content. There is no cage match pitting one against the other in a fight to the death.

The two work hand-in-hand. I’d even go so far as to say that a lot of design is about enhancing what is communicated on a page. There is no upstaging one or the other. Think of content and design as supporting one another, where the sum of both creates a compelling call-to-action, long-form post, hero banner, and so on. We often think of patterns in a design system as a collection of components that are stitched together to create something new. Pairing content and design works much the same way.

So, why are you reading this?

Go read your site… like now. Belt it out loud. Bring it into the light of day and let it be seen and heard. That’s what it’s there for. It’s your friend for making a better site—whether it’s to be more accessible, profitable, performant, findable, and personable. It gets users from Point A to Point B. It’s how we move on the web and how the web is inextricably linked together.

And, please please please, record yourself reading your site out loud. How cool would it be for the comments in this post to be a living collection of celebrating content and letting it be heard!

Categories: Designing, Others Tags:

Faulty logic

December 14th, 2021 No comments

Ain’t this the truth:

It’s like when you’re learning a new language. At some point your brain goes from translating from your mother tongue into the other language, and instead starts thinking in that other language.

I don’t speak any other language besides English, but I’ve heard that’s true. With perhaps a last step being when you start dreaming in the new language.

But here Jeremy is using it as a metaphor for learning new CSS syntax. First you hear about it, then you try it, then you grok it, then a flip switches in your brain and you start reaching for it intuitively. Indeed thinking it.

I deeply love that moment. It feels like you’ve gone up a level.

The sad part of Jeremy’s article is that there is a disconnect happening. Like logical properties have arrived, we can use them, many of our brains are starting to make the switch. But… they aren’t used consistently.

For example, if you’re thinking in logical properties and setting margin and padding, you might do:

.el {
  padding-inline: 1rem;
  margin-inline: 1rem;
}

In fact, you can even set what would have been width in a top-to-bottom language as inline-size. But, once @container queries drop, which is happening, you can’t express that width breakpoint as inline-size, it’s back to traditional min-width and max-width stuff.

That would be a bummer as it muddies the water of how clearly we are able to think. This stuff is moving very fast though, as I just took a peek at the Draft Spec (soon to be Working Draft?) and Example 2 is:

main, aside {
  container: inline-size;
}

.media-object {
  display: grid;
  grid-template: 'img' auto 'content' auto / 100%;
}

@container (inline-size > 45em) {
  .media-object {
    grid-template: 'img content' auto / auto 1fr;
  }
}

So, it looks like this inconsistency has been mopped up. Example 3 has @container (width > 40em) in it, so maybe it’ll ship being able to use them either way. I might even vote they roll with only logical properties, but I imagine that ship is close to sailing.

Jeremy also points out that overflow-* properties aren’t converted to logical yet, as something like overflow-x should be overflow-inline. Only Firefox has support for that so far.

I hope that’ll get mopped up soon. But all in all, there is a ton of logical properties that are ready to think in: size, position, margin, padding, border, alignment, and more. Heck, even something like border-top-left-radius can now be thought of and used as border-start-start-radius, and you can float: inline-end instead of float: right.

Categories: Designing, Others Tags:

I’m confused about Static Site Generators. Are they only for informational sites where I can’t log in or display any dynamic data?

December 14th, 2021 No comments

(This is a sponsored post.)

I got this question from a listener the other day. Fair question, I’d say. The word “Static” in “Static Site Generator” is at-odds with the word “Dynamic.” It seems to imply that the website created with a Static Site Generator (SSG) is locked in stone, only to be changed when it is run again some future date. That’s a somewhat unfortunate implication, if entirely understandable.

“Static Sites,” in actuality, can be as dynamic as any other side because of one¹ thing baked right in an available to any website: JavaScript. JavaScript can, say, hit an API and update the otherwise statically generated markup of a page. Just think. JavaScript. APIs. Markup… J… A… M… Jamstack!

Part of the trick to understanding this Jamstack world (aka Static Sites that do Dynamic Things) is just looking at what Netlify offers. Netlify literally only offers static hosting. No server-side languages (think Ruby, PHP, or Python) serving up individual pages on Netlify. So SSGs and Netlify go hand in hand. But let’s go through it as a list:

  • Netlify runs your build process for you. Which very likely includes a SSG. The point of which is largely that you keep your built site files out of your version control system, which would otherwise be a wasteful mess.
  • Netlify processes your forms. No need to run an always-on server just for this dynamic feature.
  • Netlify offers authentication. That’s right reader, auth is a first-class citzen of the platform.
  • Netlify runs your server side code in the form of cloud functions. Static hosting doesn’t mean you can’t do server side things. It means you do server side things with modern, cheap, secure, focused, fast, powerful cloud functions.
  • Netlify can build pages on-demand. Meaning you don’t have to pre-build all your pages if you don’t want to.

That’s just some of the feature set. Here’s a fun blog post from a little while ago with some of the staff’s favorite features, many of which aren’t in the list above. Jamstack is starting to literally mean that indeed dynamic things are happening to a static site.

I hope that answers the question for this particular reader and anyone else with the same confusion. SSGs can produce entirely static websites with zero dynamic data and that offer no special logged-in experience. But they can also be every bit as dynamic as any other site, just built from a more solid, static foundation.

  1. Well, let’s say two things. Dynamic things can be done via edge handlers as well, without the need for client-side JavaScript.
Categories: Designing, Others Tags: