Skip to main content

Learn Grid Now, Container Queries Can Wait

Miriam Suzanne:

There’s no rush to rip out all your media queries, and replace them with containers. You’ll be fine waiting for widely available support and your next scheduled re-factor.

But if you’re still avoiding grid – whatever your reasons – you are, in fact, missing out. CSS grid is one of the best features in CSS, and one of the biggest time-savers on every site we build.

One part of Grid that I’ve been ignoring for too long is the whole template areas syntax...

.grid {
  display: grid;
  grid-template-areas:
    "head head"
    "nav  main"
    ".  foot";
}

.grid header {
  grid-area: head;
}

/* etc. etc. */

For some reason it doesn’t feel grid-y enough for me but I should just sit down and try to get used to it. Even looking at it now I’m slowly realizing that it’s real nice that you can use . to denote an empty column which makes things quite a bit easier. Oh and this reminds me, the other day I spotted this CSS Grid Template Builder by Anthony Dugois and it’s pretty handy!

In defense of asymmetric grids

CSS Grid has made me lazy. Whenever I start a new project I tend to pick a 12 column grid and move on to other things...

.grid {
	grid-template-columns: repeat(12, 1fr);
}

...it’s almost too easy! This is probably also out of laziness in the design, too. I’d often pickup the Bootstrap grid and after years of use I began to see every page built out of 12 columns. So layouts, and the grid systems they’re built out of, felt like a solved problem to me.

But I got into a layout pickle the other day because of this laziness: I realized that my layout looked so weird and wonky here on The Cascade because I was using my trusty 12 column layout without thinking about it. I’d then set every element on the page to fit within those arbitrary constraints:

.main {
	grid-column: 5/13;
}

.sidebar {
	grid-column: 1/5;
}

The problem here was the sidebar would stretch too far at larger screen sizes and felt visually gross. So I did the unthinkable and tweaked the grid to fit the content instead:

.grid {
	grid-template-columns: repeat(4, minmax(auto, 80px)) repeat(7, auto);
}

Translation: “make 4 columns with a max-width of 80px each, and then 7 columns that take up the space left over.” Reading CSS like this always takes an extra second for me to parse and walkthrough step by step but effectively all we’re doing here is telling the first 4 columns to be a different size than the remaining columns.

Gasp! An asymmetric grid! The horror!

Anyway, CSS grid is just a tool and it doesn’t have to be perfect or simple or make everything line up in equal measure. But I also realized here that the grid should always be subservient to the content.

Or: content first, grid last.

A modern approach to browser support

The folks at Clearleft published their browser support policy the other day which is pretty interesting:

Underlying our browser support policy are two foundational principles:

  1. Website content and core functionality should be accessible to everyone.
  2. It’s okay for websites to look different in different browsers.

If content is unreadable in some browsers, that’s a bug that we will fix. If content is displayed slightly differently in some browsers, we consider that to be a facet of the web, not a bug. This means that there will sometimes be subtle visual and functional differences from browser to browser. We deem this acceptable provided that content and core functionality are unaffected.

Responsive posters in CSS

The other day I spotted these lovely VHS posters and wondered how you might make that slanted background pattern there with just CSS. So I took a crack at it and got pretty close:

See the Pen Responsive JVC Video Cassette by Robin Rendle (@robinrendle) on CodePen.

This isn’t an SVG (which is probably the best way to make something like this) but instead it’s plain ol’ CSS. Try and resize the browser though and you’ll see it respond to the height and width of the viewport which feels swish.

So here’s a quick summary of the trick: first I set up container queries and aspect-ratio on the wrapper element...

.cassette {
	container-type: inline-size;
	aspect-ratio: 70/99;
}

That’s what handles all the resizing. Now we can set up some variables:

:root {
  --first-stop: 20cqw;
  --second-stop: 40cqw;
  --third-stop: 60cqw;
  --fourth-stop: 80cqw;
  --fifth-stop: 100cqw;
  --sixth-stop: 150cqw;
  --red: hsl(350, 100%, 50%);
  --orange: hsl(13, 100%, 50%);
  --gray: hsl(17, 19%, 73%);
  --white: hsl(0, 0%, 100%);
}

Those cqw length units are pretty dang handy. 1cqw is 1% of the container’s width which means I can use them in the repeating-linear-gradient property below to create that background pattern:

.body-wrapper {
  background-image:
    repeating-linear-gradient(
      135deg,
      var(--white),
      var(--white) var(--first-stop),
      var(--red) var(--first-stop),
      var(--red) var(--second-stop),
      var(--orange) var(--second-stop),
      var(--orange) var(--third-stop),
      var(--gray) var(--third-stop),
      var(--gray) var(--fourth-stop),
      var(--white) var(--fourth-stop),
      var(--white) var(--fifth-stop),
      var(--white) var(--sixth-stop),
    );
}

I’m sure there’s a more elegant way of doing this but I kept playing around with these values until it looked right. I also set the font-size and position of elements to respond to the size of the container, too:

header {
  padding: 3cqw;
}

h2 {
  font-size: 10cqw;
}

This is fantastic because it means I don’t have to write a bunch of media queries all over the place. I just set the font-size and forget it. And that’s not a dig at media queries! Well, okay – it is. But I am slowly coming to the conclusion that media queries are a design smell. Sometimes they indicate that my code could use more modern CSS techniques to avoid that little bit of extra complexity and logic.

Wellllll...sorta. Chris wrote about this optimistic view of container queries where we all assumed that...

...on any given project, there would be more @container in the CSS than @media. I joined that refrain. I thought for sure it would be true, if not, more like 75%, especially considering how so many sites these days are created by composing sites through component libraries, and since components don’t know where they will be used, the CSS that style those components would use all container queries.

So, did this turn out to be true?

Anecdotally: no, not really.

It’s a great breakdown of why we don’t use container queries all over the place like I have in my little demo above. But either way, this whole “web poster” design with cqw units and a dash of aspect-ratio is super neat and it reminds me of what Jeremy said just the other day:

I really like the newly-launched website for this year’s XOXO festival. I like that the design is pretty much the same for really small screens, really large screens, and everything in between because everything just scales. It’s simultaneously a flyer, a poster, and a billboard.

An intro to CSS anchor positioning

I’ve been half-ignoring anchor positioning but patiently waiting for it to land in browsers for a while now. But this explanation by Brecht yesterday reminded me to buckle up and learn it all properly since it just landed in the latest version of Chrome and Edge.

One thing I hadn’t heard of before Brecht’s post was the inset-area property which sure is handy. As he explains, it lets you draw a grid around an element and then position something left/right/up/down within it:

.anchored {
  position-anchor: --anchortome;
  position: absolute;
  inset-area: top span-all;
}

This feels like how I’d anchor-position something like a tooltip maybe 95% of the time which is neat. But! Although anchor positioning sure is going to be amazing for tooltips, it goes far beyond that. Re-reading Roman Komarov’s post from last year made me spit-take again:

It becomes possible to highlight something in a completely different place on the page, allowing elements to “know of each other”.

Not only does that sound punk rock and strangely ominious, I think that’s what anchor positioning really opens up.

Charm

Since I’ve been working as a designer for a few years now, I’ve felt like I needed to upgrade my command line chops. So I downloaded Warp and fell down a big rabbit hole of futzing and playing with everything I’d missed or ignored over the years.

This led me to Charm, a group of folks who make super interesting command line tools. They make stuff like VHS which helps you create GIFs of your terminal, or Pop that lets you send email via the command line. Bubbles is neat too, it’s a set of components for building your own CLI tools.

The one thing that I love about Charm is that they clearly spend an awful lot of time polishing their work. From the website to the README, everything is clear and everything shines with thoughtfulness. I especially loved this post about their process by Christian Rocha:

The README is critically important to the success of an open source product. It’s often a developer’s first point of contact with a project and the place where a developer will, in a matter of seconds, judge whether the project worthy of further consideration. With this in mind, put a lot of effort into README design, optimizing for strong first impressions.

Our strategy is to simply follow the age-old rule of advertising: showing the product. Good products, when presented correctly, will sell themselves, which is why we spend spend so much time on user experience and attention to detail.

A common web component learning blunder

Dave Rupert:

Through stalking the #WebComponents hashtag and my Frontend Masters course, I’m privy to a lot of developers’ first experiences with web components. There’s a wide range of people digging in, but the most common first-time experience I come across is a developer coming from a classical component framework like React with JSX going straight to writing vanilla Web Components, becoming frustrated, and then deeming web components “not ready for primetime.”

The gist here is that HTML Web Components aren’t really meant to replace these frameworks at all and that’s something I really struggled with until I had my eureka moment a few months ago:

I don’t think we should see web components like the ones you might find in a huge monolithic React app: your Button or Table or Input components. Instead, I’ve started to come around and see Web Components as filling in the blanks of what we can do with hypertext: they’re really just small, reusable chunks of code that extends the language of HTML.

The Gap

Ahmad Shadeed has written another beautifully designed and polished deep-dive but this time all about the gap property. Sometimes it’s nice to go back in time and remember all the negative-margin hacks and complicated layout-related code we had to write just to space things apart. Thankfully no longer!

Another thing Ahmad’s post reminded me is that not only is gap straight up easier to use than managing a lot of margin declarations, but it also prevents layout bugs too. On this thread, Ahmad writes:

Building a UI that doesn’t break is impossible, but at least, you can reduce the issues that might happen:

  • Ask questions: what will happen if there is only one item? or do you expect another variation of this component that will do X and Y?
  • Make sure to stress-test the UI for any spacing issues.

Keeping up with CSS

Max Böck on all the new things in CSS:

While learning the syntax for any given CSS feature is usually not that hard, re-wiring our brains to think in new ways is significantly harder. We’ll not only have to learn the new way, we’ll also have to unlearn the old way, even though it has become muscle memory at this point.

Yes! This is the hardest part of web development for me, as there’s a lot of work that has to go into tearing down the years of experience I’ve had with, say, how CSS used to limit us in terms of layout. CSS Grid isn’t rocket science but unlearning the old and familiar ways sure is complicated. That takes time and serious amounts of effort.

And yet even though we’re living through the golden age of UI on the web, it doesn’t mean we have to use every new CSS thing in every single project. Sure, if something helps save you time then that’s great. Or if it unlocks some new super power then that’s fantastic. But you don’t have to use @layers and logical properties and :is or :has if you don’t need them.

It’s more than ok if you don’t know how the fanciest features work today and I don’t think you should force yourself to put them into a project if you don’t really need to. Yes, many of these new tricks expand what’s possible on the web today and make things easier but it’s perfectly fine to not be at the absolute bleeding edge of this stuff. And keeping up with CSS shouldn’t feel like a full time job, and it definitely shouldn’t stress you out.

This is the real magic of CSS though! All the old techniques from a decade ago work just fine. Are there better ways to do X, Y, or Z? Sure. But it’s also okay to not always be optimizing, to not always be grinding away at the infinite factory line of new CSS features in this mad-dash panic to feel like you’re a real front-end developer.

The thing is that a webpage from 1995 or a webpage from 2035 can—and often should!— work just the same. That’s ok!

Design Spells

Design Spells is a big collection of animations and fun, interactive details taken from all over the web. Lots of these are stressful and overwhelming to me but there’s some particularly absurd things in here I love like Webflow’s ridiculous 404 page or Vercel’s interactive conference badge.

If you’re looking for something to make a Codepen out of, then this is also a fantastic resource to pick something, copy it, and learn how they made it under the hood.

New magic for animations in CSS

Cool, punk rock stuff coming in hot off the press from Chase McCoy here:

There are two new features coming to CSS that will make it much easier to further avoid JavaScript when implementing animations:

  1. Animating to and from display: none; for the sake of enter/exit animations.
  2. Animating to and from the intrinsic size of an element (such as height: auto;).

Traditionally, animating something into our out of the screen (as opposed to just hiding it visually) required JavaScript to remove the element from the page after waiting for the animation or transition to complete. No longer!

This is a BIG deal. I feel like maybe 50% of my late-night panicked CSS-related searches are about these two topics alone. Perhaps the most eye-opening part of Chase’s blog post though is this bit:

.item {
	@starting-style {
		opacity: 0;
	}

	opacity: 1;
	transition: opacity 0.5s;
}

This @starting-style chap is for when you want an element to be hidden by default but then fade in. And Una Kravets and Joey Arhar wrote about this a while back for the Chrome blog where they have a fantastic demo of a todo list in which each new item added is invisible by default with @starting-style and then expands into view.

I can see myself using these new CSS animations in every project from now until the end of time!

11ty goes independent

This is super cool:

...11ty is making some bigger moves: we’re going all-in to create a fully independent and sustainable, grass-roots funded open source project in 2024.

Practically speaking this means that for the very first time in 11ty’s history, I will be working independently on 11ty full time. This means increased iteration speed, more responsive official support, more features and bug fixes, and faster releases.

Exciting stuff! It’s no secret that I’m an 11ty super fan since this very website is powered by it under the hood. Either way, if you or business can help out here, go support this thing and help make the web a better place.

Baseline

There’s been some chatter over the last few days about “Baseline” and I’d heard the name in passing before but I must be honest: I was pretty embarrassed to ask around because a lot of blog posts mention this thing as if it’s been kicking around forever.

(I think it was announced at Google I/O last year and it managed to slip me by! How embarrassing!)

Let’s set the stage then: a “Baseline” feature can be anything—a new CSS property or a handy new thing in JavaScript—and the idea is that, at a glance, us developers can see if that feature is coming down the pipeline or if it’s already supported by browsers today. This should help us get a feeling for whether we can use the feature without a care or if we should think about a backup plan if it’s not supported by some browsers.

This is great because the standards process has felt entirely random to me over the years. I usually don’t know what’s going to ship or what cool new features are going to be available soon. “Baseline 2024” for example is all the features that are new to the web platform this year and you can see a handy list of all them over on The Web Platform Dashboard which is pretty fantastic. In terms of CSS, that means...

  • Declarative Shadow DOM
  • CSS offset-position and offsetpath values
  • The Popover API
  • align-content on block layout

There’s also the Baseline widget (boy, keep saying that over and over and it feels like saying “iPad” obnoxiously without the “the”) and it’s implemented all over MDN and CanIUse, like in this example for the new <search> element. This chap started to be rolled out back in December and the label comes in three flavors: Widely supported, Newly available, and Limited availability.

This is all useful stuff but I love what Jeremy had to say last week:

...I really like how it’s nice and glanceable right now. But it would be nice if there way some indication that a newly-available feature is a progressive enhancement.

For now it’s up to us to make that distinction. So don’t fall into the trap of thinking that just because a feature isn’t listed as widely-available you can’t use it yet.

One example might be text-wrap: balance because, in the spirit of giving hints and suggestions to browsers, it’s totally okay if older browsers ignore that rule since it’s a nice-to-have progressive enhancement. I do think that the “Widely supported” label is supposed to give an indication of that. But then some features that are “Newly available” are totally fine to use because they don’t break any functionality if they’re not supported and they gracefully degrade. So things are a little confusing on that front today.

Either way, I think this is a great improvement and I’m going to use the heck out of it. And I think I prefer bucketing these new features by year more so than I do by version number, like “CSS5”.