Subgrid Changes Everything

For the frontenders out there, you’ve likely seen the news. Subgrid has shipped. It came to Firefox back in 2019, to Safari last year, and now Chrome has shipped it. If you haven’t been following, let me catch you up.


I got my starts in web development back around the turn of the century. Which was not that long ago. Promise. In those *barf* 20+ years, I have seen every major shift in how we lay out websites. When I started, we used tables still. It was gross, but we had no choice.

See the Pen Table Layout by James Finley (@thefinley) on CodePen.

For a table-based layout, you would start with a table to lay out your columns and rows and then nest child tables until you died in a nest of unmanagable code so you could get close to a complex layout. Luckily we never even considered people being on small screens back then.


At the end of the 1900’s— I just made a lot of people hate me— we got CSS and were told that it was for styling and format, while HTML was for semantics— describing the text and content of our page. Fair, but it had no true layout system. The closest it had was floats, which were really meant to allow you to have text wrap around an image. But we wanted a 6 column layout. So grid systems like and Bootstrap were born to allow us to use utility classes to layout pages. Along with that, we entered an era where vertical was problematic— having all your columns match height in a row required very gross tricks. Oh, and clearfixes. Look it up if you need a refresher.

But, our HTML became a lot cleaner as we got to write less code and allow CSS to do it’s thing.

See the Pen Float Layout by James Finley (@thefinley) on CodePen.


For most of the 2000’s we got used to laying out pages using grid systems built on floats. At the end of the 2000’s, we got our next big shift: flex box. And right in time for the Responsive Web movement. Chrome rolled out support in 2010, Safari in 2008, Firefox in 2006. IE got it with version 10 in 2012, which truly opened us up to use it.

See the Pen Flexbox Layout by James Finley (@thefinley) on CodePen.

Flexbox getting solid support and version usage by 2013-2015 meant we could finally easily center things vertically and horizontally for the first time since tables. Over a decade of CSS and no real layout system, no we had one, but we also had grid right on the horizon.


IE was first to implement Grid in 2015 to the surprise of everyone. This was when Microsoft really started to show signs of caring for web developers and supporting standards with Edge 12. Where flexbox worked well for layout elements out in one dimension— either column or row— grid was a real, true two-dimensional grid system built right into CSS. March 2017 grid shipped in Chrome, Firefox, and Safari. All at once within weeks of each other.

See the Pen Grid Layout by James Finley (@thefinley) on CodePen.

Instead of needing complex utility functions that did math, we now could tell a cell in a grid to start at column 1 and span 3 columns. And this has been are last 6 years of web development. I’ve been in this game for 20 years. Grid is a beautiful thing.



The original spec, from my understanding, included something called subgrid and it was dropped from the original release. You see in the demo above of grid, the grid can only be used by direct children of the element with display: grid. For grandchildren, they are out of luck. Remember us nesting tables back in the 1900’s? Yeah, we had to go back to that. You have a six-column layout with a cell taking up four columns of that. You want to have four items inside that each take up one column? Yeah, those items don’t know about the grid, so you have to establish a four-column grid on their parent and use the calc function to mastery to get your gaps to align. Subgrid was supposed to allow you to pass the grid onto the children of a grid cell.

And now we are caught up to the present. Subgrid has shipped. Browser usage stats are going up. The demo below will work in anything after Chrome 117, Safari 16, and Firefox 17. Edge will get it soon, from my understanding.

See the Pen Subgrid Layout by James Finley (@thefinley) on CodePen.

Now we can truly lay out pages where everything sits in one grid. Blocks on the page can be logically and semantically separated while not making layout complicated and can still internally rely on one grid.

See the Pen Complex Subgrid Layout by James Finley (@thefinley) on CodePen.

Each of these major eras of web layout have changed the way we think, the amount of code we write, and what designers are able to design. During the float era having three equal height columns was a PITA. Vertically centering something was too. Grid allows some truly complicated layouts that we are still not scratching the surface on, but in many ways it was hampered by the lack of subgrid support for the last six years. Subgrid changes everything once again and I am more than excited for this new era in web layout design.

Really impressive demo. First, this is for single-page applications. Second, there is an API for multi-page applications. Check it out in Chrome Canary and look at the code. I discussed this with my team yesterday. The demo is built on Astro. All that is shipped to the browser is 301kB. Of that 291kB is images. Less than 5.5kB for the document, CSS, and JS. CSS is powering the transitions and only a bit of JS intercepts the navigation event, loads the fragment of HTML, injects it into the DOM, and adds the necessary classes to trigger the animations.

This is a truly impressive demonstration. With very minimal effort, one can use an SSG like Astro— which can run as an SSR too— and deliver a fully working application that requires no JavaScript but progressively enhances to dynamic page transitions with easy— something that is extremely difficult even for SPA libraries— and asynchronous page loading. Only 150 lines of JS are in this project— 150 lines that ship to the browser.

For an old curmudgeonly standards guy like myself, this gives me some hope that we can get back to the days of the largest assets we send to the browser are images instead of hundreds of kilobytes of JavaScript.

Source: Bramus

Something non-designers understandably struggle with is how to make things look good. One of those things is long form content that’s well set and readable. Luckily, CSS makes this easy, you just have to know what to change. That’s exactly what we’re going to teach you in this article.

Set Studio

So many good tips in this article from Andy Bell. I’m using many of them already on this site. Long-form content can be hard to format, so if you need some help, tap the link above!

Wrote this five years ago. Then it was Bootstrap and a bunch of JavaScript ninjas that didn’t know HTML/CSS. Now it’s Tailwind and a bunch of React ninjas that see HTML as an implementation detail and CSS as fundamentally broken.

Between the various CSS-in-JS solutions and the use of massive UI frameworks— looking at you MUI— we have taken frontends that could be lightweight, fast-loading, and enjoyable and made them into monstrosities of slowness.

I was looking at a website for a development agency in Atlanta last night and my 8 year old laptop got so hot the fans had to spin up. The website wasn’t even doing much beyond showing some content with some simple animations. I could understand not being able to run the latest games on my laptop but content-centered websites shouldn’t be doing this.

When every new website on the internet has perfect, semantic, accessible HTML and exceptionally executed, accessible CSS that works on every device and browser, then you can tell me that these languages are not valuable on their own. Until then we need to stop devaluing CSS and HTML.

Mandy Michael

Preach! It’s all I see these days in job descriptions. JAVASCRIPT! Ninja preferred. Rockstar acceptable. And then they produce crap frontend code. Their HTML and CSS is restricted to Bootstrap at best, custom crap with style attributes all over the place at worst. When I was their age, the emphasis of frontend was on the other side of the triangle: HTML and CSS. Without these, your JavaScript means nothing. Even if you are embedding your CSS and HTML in your JavaScript. Shudder.

Astro Build Performance

Sixty-five seconds just to build out the first pages of the #tech pages. Why? Because they are reliant on a complex function that gets a tag map. So let’s understand how pages are built for a route, from what I gather.

function doComplexThing() {
	const things = [];
	// do the thing

	// return the data
	return data;

The getStaticPaths method returns an array of pages and their data. This is called once. So that complex function? Not really a problem here. Then Astro renders each page that getStaticPaths returns. The problem is that I need that complex function’s data here too. Without calling it here, we build these pages in 10 seconds. With it, 65.

export async function getStaticPaths() {
	const things = doComplexThing();
	return => ({
		params: {
			tag: thing

Okay, now we have options. We could just put that data in the paths’ props. But it is used by a component in the page that is rendered. We could pass that data as a prop to that component. But it would be easier to call it inside the component. 65 seconds. And that’s just a fraction of the pages that need to build.

And that leads to an old trick from my PHP days. Caching the data of a function and returning it the next time we try to access it.

export let cachedThings: any[] | undefined = undefined;
export function doComplexThing() {
	if (cachedThings) return cachedThings;
	const things = [];
	// do the thing
	// cache it
	cachedThings = things;

	// return the data
	return data;

Now when we call doComplexThing() the first time, it runs the complex code. But then we hit it hundreds of more times and returns the cache.

There are many reasons to love the return of blogs. Folks taking the time to make a well-reasoned argument without truncating it to 140 characters is one of the biggest. And boy, William makes a great point here. Aside from the obvious spelling mistakes.

Clouds, and VPS’s before that, work on the age-old principle of buying in bulk and selling by the piece. You run one big server for $1,000/month, then you rent it out to seven people for $200/month, and voila, you’ve cleared a $400/month profit.

DHH, Don’t be fooled by serverless

This is something that has bothered me for some time. The prices of these services when compared to full servers is absurd. Hear that whole sentence. Compared to full servers. The response of many would be either a) “the prices are very low!” or b) “no one needs a full server!” The whole sentence matters. If you need a full server, the price is very high to rent it piecemeal. If you are going to eat a whole cow in a year, buying it pound by pound from the grocery store will cost substantially more than buying a whole cow.

But what happens if a customer needs the performance of a whole box, most of the time? Then they’re paying $1,400/month for $1,000’s worth of computing. Or maybe, because they’re reserving the whole box, they’ll get a deal at $1,250/month by committing to a whole year. That deal is far less obviously good on both sides. It’s basically a credit agreement at a 25% APR. Tread wisely!

But if you execute enough functions to fill the computing power of a whole box, it’s a terrible deal.

And then there is the lock-in. If you build an application in PHP or Ruby, you can basically run that anywhere. These cloud services are designed so you have to architect around them. If the pricing of my server for this site goes too high, I can take it elsewhere. It’s just HTML.

The further down the rabbit hole you go with “cloud-native” services in serverless, the harder it’ll be to climb out when you realize that you should own the donkey rather than rent it. And especially once you realize that paying to rent a whole donkey at the piece price of a hundred slices is an even worse deal than just renting the whole donkey by itself! […] And if you start off with a proprietary serverless setup, you might well find the lock-in impossible to escape by the time the rental math no longer works.

So who are these services best suited for?

The cloud is primarily for companies that have big swings in use – like Amazon’s original AWS case of huge demand around Black Friday and Christmas, which left them with unused capacity for the rest of the year – or for early outfits that don’t do enough business to either warrant owning a whole computer or spend so little on the cloud that it just doesn’t matter.

Front Matter CMS

With the relaunch of Finley, I am. a couple of weeks ago I shifted from using a CMS to everything-is-code. My blogging days stretch back to the mid-2000’s and my having built my own blogging tool called Blog Wizard. Various versions of that powered several blogs until I launched Finley, I am. in 2015 on Ghost.

Simply put, I am used to having a CMS. Code is great, but certain things are nicer with a CMS. Managing data things, specifically. The week with the relaunch I had imported all the articles from Ghost 1-to-1. Same tags and everything else. Last Sunday I started refactoring the tags. Because everything-is-code and I realized that I could build something cool if my tags were better. As detailed in the linked article, I merged and deleted a ton of tags. Over 300 tags in over 400 posts.

That brings us to Front Matter CMS. First, it’s a plugin for VS Code. Many CMSs exist for SSGs like Astro that write code. This sits alongside your Markdown post, living in the sidebar of Code. For SEO-minded folks, it provides SEO status info— like title, slug, article length, keyword management, etc. For me, it’s the publishing date, draft status, and very much the tag management for articles I love. Autocomplete on tags will help you remain consistent on your tag use, which I then use for finding similar posts.

And it helps you manage. The Dashboard shows all published posts and easily helps you find and edit your drafts. Taxonomies? Yeah, merging, renaming, deleting, and more. And remember, everything-is-code, so changing merging “video” into “videos” results in 10 changed files that you then commit and push.

If you use Hugo, Jekyll, Astro, or other SSGs that use front matter for metadata around posts, go grab Front Matter CMS and give it a shot.

Scroll Snap for a Nice Mobile Experience

Small enhancement to homepage. Two column layout, so mobile normally would make that one column. Which it had. But I write a few featured posts and lots of “other” posts. The sidebar had the “other” posts, but that got put way down the page. You’re unlikely to get there through scrolling. But putting it first wouldn’t make sense because then the featured posts are too far.

So… I made a scroller using the new scroll-snap CSS functionality. Now you can see the latest “other”, but it doesn’t push the featured posts down 3 scroll heights.

.b--article-list {
	display: flex;
	width: calc(100vw - 64px);
	overflow-x: scroll;
	scroll-snap-type: x mandatory;
	scroll-padding-right: 20%;

	> * {
		min-width: calc(80% - 32px);
		padding-left: 32px;
		scroll-snap-align: start;

With scroll-snap-type set to x mandatory, we allow card-based scrolling horizontally. Setting the scroll-snap-align to start for all children makes the snap point the left side of each card.

I have implemented this style of interface before, almost a decade ago. It took a lot of JavaScript. Now with just a few lines of CSS, you get a super interactive little component.

Demo: Homepage view on mobile or scale down and you’ll see the Ramblin’ section using the above.

Clamp for Truly Responsive Typography

CSS’s clamp() has been around for a few years now, but I finally got to use it in the rebuilding of this site. Let’s look at the hero text block on my new homepage!

:root {
  --font-size--dynamic-headline-3: clamp(21px, 4vw, 36px);
  --vertical-spacing-5: clamp(36px, 8vw, 72px);

.b--homepage-hero {
  max-width: 60ch;
  margin: 0 auto var(--vertical-spacing-5);
  font-family: Parkly, sans-serif;
  font-size: var(--font-size--dynamic-headline-3);
  text-transform: uppercase;

  & p {
    color: rgb(0 0 0 / 60%);
    text-align: center;

    & strong {
      font-family: "Parkly Wide", sans-serif;
      color: rgb(0 0 0 / 75%);
      text-transform: uppercase;

I’ve got the two variables included too. Okay, so the Dynamic Headline 3 variable is defined as clamp(21px, 4vw, 36px). Minimum, preferred, and maximum. The browser then makes the decision for us. Now one has to be mindful of that middle. It can be a somewhat arbitrary relative value if your clamp is tight, but if you have multiple headlines of varying sizes— like any typographer is going to— you need to make these numbers proportionate. Let’s look.

:root {
  --font-size--dynamic-headline-1: clamp(43px, 8vw, 72px);
  --font-size--dynamic-headline-2: clamp(32px, 6vw, 54px);
  --font-size--dynamic-headline-3: clamp(21px, 4vw, 36px);
  --font-size--dynamic-headline-4: clamp(21px, 3.1vw, 28px);
  --font-size--dynamic-headline-5: clamp(21px, 2.65vw, 24px);
  --font-size--dynamic-copy: clamp(16px, 2vw, 18px);
  --font-size--dynamic-small: clamp(14px, 1.78vw, 16px);

Dynamic Headline 2 is 50% larger than Dynamic Headline 3. That applies to the min, pref, and max. But at the smallest sizes, Dynamic Headline 3, Dynamic Headline 4, and Dynamic Headline 5 are all the same. They got too small otherwise.

As we allow our pages to be more fluid with dynamic grids, flexbox, and clamps, we have to let go of some of our pixel precision in design. Almost all the fonts— and vertical spacing!— on this site are dynamic with clamp(). The header, I think, is the only thing that isn’t.