DEV Community

Ken Bellows
Ken Bellows

Posted on • Updated on

Why we need CSS subgrid

It's been quite a while now since CSS Grid Layout Module Level 1 was released. It's been almost two years since that time all the major browsers sort of got together and pushed it out nearly simultaneously (March 2017, ICYMI).

And IMHO, it's the best thing in CSS in a super long time. Don't get me wrong, I love me some Flexbox, and Flexbox is clearly the better choice in many circumstances, but man, Grid just makes so many things so much easier.

But one thing still missing from the Level 1 spec is the ability to create a subgrid, a grid-item with its own grid that aligns in one or both dimensions with the parent grid. It was originally planned to be in Level 1, but the working group decided they needed more time to work out the details, so it was removed, and it will ship in CSS Grid Layout Module Level 2, which seems to be nearing completion.

There has been a lot of discussion over the last 2 years about the use cases for subgrid, how it should be implemented, and even some debate over whether you even need it. A lot of that discussion was centered around two other approaches that can handle many of the same problems as subgrid: nested grids and display: contents. This article will explore both of those approaches, and I hope to demonstrate that there are still some very valid cases where a subgrid is truly needed, and others where it is not strictly needed, but would make for a much cleaner solution.

As with my previous article, I'll present a scenario and implement a solution with these different approaches to explore their strengths and weaknesses.

Scenario: A bunch of cards with numbers on them

Today's scenario: I want a section on my personal site that displays my most recent Dev articles, along with their reaction counts. Let's put together a mockup.

Basic card mockup

That second article sounds interesting; I should write that. Looks like it was pretty well received, too.

Pretty straightforward stuff. Each card has a border with a box-shadow, a user avatar to the left, a title left-aligned along the top, and three reaction counts below. Shouldn't be difficult, right?

Let's code it up.

v1: Good ol' floats

This seems simple at first glance, so let's start out with an old-school float-based layout and see how things go.

Okay, pretty good! I am good at CSS. πŸ‘πŸ‘πŸ‘ (Actually, I just inspected the cards on the dev.to homepage, stole the CSS from there, and tweaked a bit as needed.)

Anyway, I'm satisfied. Everything is looking exactly like the mockup, except... hold up a sec. What's the deal with those reaction counts? Why is the reading list icon on the third card so far off from that of the second card? Why aren't they aligned between the cards?

What I want is for the counters of the same type, e.g. all the unicorn counters, to be aligned across cards, so that the smallest unicorns counter takes up as much space as the largest unicorn counter.

Mockup with alignment lines

So why don't my counters behave like that?

Because I didn't write them that way, I guess. Hm. How would I do that? I want the counts with smaller numbers to have as much horizontal space as the larger ones of the same type from other cards. But this means that some elements are going to need awareness of their... cousin elements? Like, unicorns β†—οΈŽ card 1 ⟢ card 2 β†˜οΈŽ unicorns. Parent's sibling's child. Cousin. Yeah.

But old-fashioned float-based layouts don't allow that. I can only size an element based on its parent, and sort of its siblings... Hey, I know, Flexboβ€” nope, Flexbox doesn't do this either. Same problem. What's left?

Of course, I'm sure you already know the answer. There's only one layout system that can accomplish the task. It is... HTML Tables!

Michael Jordan says, "Stop it. Get some help."

I'm just kidding. Never use tables for layout.

Unfortunately, the current answer is that we can't, not perfectly, not without either setting the <span> widths with JavaScript or else, yes, invoking some uncomfortably hackish and brittle tables-based approach.

But we can get pretty close. Spoiler, if you haven't figured it out, at the end of this article I'm going to tell you how you can do it trivially with subgrid, but for now I'll talk about just how close we can get with current tech.

A brief aside about tables

To address the elephant in the room, yes, this can actually be solved with HTML tables. And the reason I know is that... sob... I had to solve exactly this problem for my day job: laying out a column of cards, each containing a title and 3 dynamic counters, with the counters and their labels kept aligned across the separate cards. And the only way you can currently do it in pure CSS is with tables.

It works, but it's brittle, finicky, very verbose, and nearly unreadable to any other devs that might need to interact with or tweak that CSS (including future me). So for those reasons, I refuse to show you how to do it, because I will not be a part of the problem! (It's not my fault! They made me! 😭)

v2: CSS Grid and display: contents

The most common argument I hear against adding subgrids to CSS is that display: contents fills the gap that subgrid is meant to fill, so subgrid is rendered unnecessary.

For the uninitiated, one of the main constraints of CSS Grid Layout is that only the direct children of the grid container can be placed on the grid. This is why we can't use a simple display: grid on the cards' container to solve our problem; we could position the cards on the grid, rather boringly, but we can't position the cards' contents on the grid, because those elements are not direct children of the grid container element.

Or can we?

Enter display: contents. If you give a container element the rule display: contents, the element sort of... vanishes... at least for layout purposes. The surrounding elements are no longer aware of that container; instead, they see its direct children. What this means in a grid context is: if a grid item is given display: contents, its child elements become grid items instead!

The big advantage here is really semantics and readability in the HTML document. You can still group elements logically and semantically in your markup, but lay them out on the grid as though they were direct grid items.

So lets see if we can apply this to our cards! We'll define a grid on the container holding the cards, then give the root card elements display: contents and lay out the contents of the cards on the grid. (Can you anticipate the problem we're about to have?)

Well, that... that's not right. The counts do line up correctly now, but... where are the cards? Where are the nice borders with box shadow? It's almost as though the cards themselves are gone and all their contents were dumped directly on the β€” oooohhh...

Yes, that's exactly what happened. This is the limitation of display: contents: it's awesome if you really do only need the contents of an element (hence the name), but if you want any kind of styling on the container itself, well... you're out of luck; as far as the layout is concerned, it's missing.

The Manual Approach

So what if we dipped a toe into slightly... dirtier waters and created our own empty "backdrop" element within each card to make it look like there's a container? You can, of course, but the tricky bit is placing it on the grid. One thing I love about CSS Grid is how easy it is to layer elements on top of one another: just attach them to the same grid areas, and apply z-index as needed!

But the trick here is that the cards are dynamic. We don't know ahead of time (or won't once we actually hook this thing up to an API) how many cards we'll have, so we can't, for example, give them each an id and assign them each to a certain row in the grid. This would work for the first few, but once you have more cards than you have ids in your CSS, you're out of luck. And anyway, the point is to find something reusable, scalable, and dynamic.

In the solution above, we're relying on Grid's auto-placement behavior to add new rows as needed. This only works as long as your elements all sit next to each other; there's no way to auto-place elements on top of each other. There's also no way (tragically) to position elements on a grid relative to their auto position, a la position: relative.

It appears we've run out of CSS-based solutions. So we must turn to the only option remaining (besides tables): JavaScript!

v3: JavaScript

Now, I know I rejected JavaScript as an option earlier, but that was about using JavaScript to calculate the width of the count elements, and recalculating each time the window is resized. This is just a tiny bit of JavaScript to place our elements on the correct rows in the grid, just one time, nothing that will repeat with each resize of the window or anything. So it's not as bad. (Still not ideal, though.)

We'll add a <div class="backdrop"></div> to each card, move the container styles to a .backdrop { } block, then use JavaScript to set the grid-row rule for each backdrop element.

That's a lot better. It pretty much matches the mockup down to the pixel.

This works, but there are two main flaws to this approach:

  1. Take a look at the CSS in there. Look at all the padding and margin rules. Notice that there's an empty first column with a width defined by a crazy calc() expression. This is the downside of manually adding everything to a flat grid with no containers to use to manage padding and margin more naturally. I spent like 20 minutes fiddling with those values to get it to match the mockup.

  2. This is not responsive. These cards are small, it's true, and they're all sitting in a single column, so it's not a huge deal. But imagine if you wanted to use cards for a search results grid, with both rows and columns of cards. This becomes very messy very fast. You can't just use @media queries or auto-placement to move the cards around at smaller resolutions; you'll have to do the very thing we wanted to avoid from the start: rearrange your items in JavaScript on each window resize event.

So in summary, that will get you a basic solution, but it's messy and brittle, and a full solution would require more JavaScript that I'd prefer.

Okay, okay, enough with the lead-in. Let's talk about subgrid!

v4: πŸŽ†πŸŽ‡ Subgrid FTW!!! πŸŽ‡πŸŽ†

So. It has come to this.

As I mentioned in the intro, subgrids were originally supposed to be a part of CSS Grid Layout Module Level 1, but were retracted toward the end so the working group could spend more time hammering out the details. Now a lot of that work has been completed, and the CSS Working Group is in the process of specifying CSS Grid Layout Module Level 2 (aka Grid Level 2). A Public Working Draft is already out there for review, although as Rachel Andrew, my favorite resource for all things CSS Grid, wrote in her April 2018 blog post "Grid Level 2 and Subgrid", further developments have occurred since the draft was released, and indeed are constantly occurring, so it may be better to refer to the Editor's Working Draft instead.

Note: At time of writing, there is no subgrid implementation in any major browser...
UPDATE: Subgrid support has shipped in Firefox nightly! Still no movement from Chrome, though; maybe click the star on this subgrid implementation ticket to show community desire for it! (I'm so excited!!! πŸŽ†πŸŽˆπŸŽˆπŸŽˆπŸŽ†)

But let me answer the main question I haven't yet: What is subgrid, anyway? How does it work?

The idea of a "sub-grid" is a grid defined within an item laid out on a surrounding grid that has some relationship to that larger grid. I'll talk about "the parent grid" and "the subgrid" to keep things simple. The simplest sort of relationship is to lock the grid tracks of the subgrid along a single axis onto the tracks of the parent grid, while keeping the tracks along the other axis separate. It's also possible to go 2D and lock both axes of the subgrid onto the parent for total integration. (EDIT: This paragraph has been updated from its original text, see endnote below!)

The declaration that a certain axis of a grid should align with a surrounding grid is done using the subgrid keyword in either the grid-template-columns or grid-template-rows rule:

#parent {
    display: grid;
    grid-template-columns: 1fr 2fr 3fr 2fr 1fr;
    grid-template-rows: 1fr 2fr 2fr 1fr;
}
#subgrid {
    grid-column: 2 / 5;
    grid-row: 2 / 4;

    display: grid;
    grid-template-columns: subgrid;
    grid-template-rows: repeat(3, 1fr);
}

Since the above demo currently doesn't work (Update: except in Firefox nightly!), here's what it should look like once the subgrid keyword is implemented for grid-template-columns:

Subgrid demo expected output

Note that the columns line up with the parent grid, but the rows are completely independent.

Which turns out to be exactly what we need for our card demo!

We'll simply make the cards container a grid with 5 columns, then make each card a subgrid along the column axis, and boom! Problem solved cleanly and simply, mockup met down to the pixel, without sacrificing semantics, readability, or responsiveness, and without needing to introduce empty structural elements (like the backdrop) or JavaScript!

Here it is, in all its not-yet-working(-except-in-Firefox-Nightly!) glory:

It's all a little wonky for now; if you want a picture of what it should look like... check the mockup at the top. πŸ˜‰

More thoughts on subgrid

Subgrid is so simple, yet so powerful. I think once we have subgrid, especially if we get subgrid on both axes in Grid Level 3 (or 4, or...), it will very quickly become indispensable to us.

Here are some of the things that are getting me excited about subgrid:

  • If we combine subgrid with grid-template-areas within the cards (read my last post if you don't know about Grid Areas, it'll blow your mind), complex responsive card-based layouts become trivial.

  • The prospect of a subgrid on both axes gives us a way to sort of accomplish relative grid positioning, at least for semantically grouped items, like I wished I had above! Group your stuff in a container, position your container on the grid, make that container a subgrid on both axes, and declare your tracks relative to the subgrid element's grid position!

  • Between Flexbox, Grid, display: contents, and subgrids, we will finally have everything we need to write very slim, clean, semantic markup with basically no fluff or purely structural elements. It will be a huge boon for accessibility, SEO, and just developers trying to understand your markup!

Conclusion

I'm pumped about subgrid. I'm pumped about the future of the web in general. The improvements made to CSS over the last 5 years or so have been, IMHO, on par with those made to JavaScript in ES6+ in terms of how much they've improved the language. They haven't been quote as extensive, but they have been just as transformative.

The web is an increasingly beautiful platform to write for, and I'm just really excited about it you guys.

Hopefully I've passed a bit of that on to you here. 😁

Resources


Endnote 1: Correction about double axis subgrids!

January 9, 2019

When this article was first published, it contained a very incorrect statement based on a very silly misunderstanding on my part. The paragraph above where I defined subgrid originally read, in part, as follows (emphasis added):

... The simplest sort of relationship, the relationship being specified right now for Grid Level 2, is to lock the grid tracks of the subgrid along a single axis onto the tracks of the parent grid, while keeping the tracks along the other axis separate. Future levels of Grid may allow for locking both axes of the subgrid onto the parent, but we have to start somewhere.

Please note: this is wrong! CSS Grid Module Level 2 will allow for subgrid on both axes, as well as on a single axis! In fact, it seems that the more controversial decision was whether to allow a subgrid on only a single axis, rather than restricting to always requiring both axes to be subgridded!

I have updated the paragraph, as well as the second bullet point in the "More thoughts on subgrid" section, to remove this incorrect information.

This misunderstanding came from a ridiculous repeated misreading of the second paragraph in Rachel Andrew's article "Grid Level 2 and Subgrid". I had read that paragraph (and the surrounding text) about eight times while writing this article, and every time I thought it said:

At the CSS Working Group meeting in Berlin we resolved that subgrids should be single axis only.

But that's not what it says! What it actually says is:

At the CSS Working Group meeting in Berlin we resolved that subgrids should be able to be single axis only.

Which is a very different thing! 🀦🀦🀦

I actually discovered this mistake thanks to a comment below from @dan503 , after which I tweeted at Rachel to ask... and only after she responded did I finally reread that paragraph again and finally realize my mistake!

Entire embarrassing thread starts here: https://twitter.com/ken_bellows/status/1083032646123483136

Endnote 2: CSS Tables

January 10, 2019

@tigt_ brought up another approach that I didn't consider in this article: CSS Tables. I know I railed against HTML tables above in the article, but I think CSS Tables can be a clever solution to many problems, because they allow you to somewhat mix and match table and block behaviors, and because they retain the semantics and accessibility benefits of typical HTML elements.

That being said, CSS Tables unfortunately won't solve this particular challenge, for various reasons. I tried a few different approaches and linked to some pens, but each approach had a flaw. Regardless of the outcome, though, it was a very interesting and fun investigation, and I recommend reading the thread!

Top comments (36)

Collapse
 
tigt profile image
Taylor Hunt

Were CSS tables not enough for the job? display: table, table-cell, etc., that is. I know they can't span across rows and columns so they're not as powerful as HTML table layout. :/

Collapse
 
kenbellows profile image
Ken Bellows • Edited

You know, being completely honest, I hadn't thought of it. But I did just spend a few minutes playing around with it, and my initial impression is that it wouldn't get the job done without requiring a few layers of wrapper <div>s and a lot of finicky margin, padding, and border styles, and at that point it's basically just HTML tables, but implemented with <div>s and a huge amount of CSS.

But take this with a grain of salt, because I admittedly have very little experience using display: table and its ilk. If you have more experience, please give it a shot, fork one of my pens up there and see what you can do! I'd love to learn about it, I really haven't seen it used very often

Collapse
 
tigt profile image
Taylor Hunt

Hm. Do you have the HTML <table> implementation as a pen? It does let you skip setting anything to display:table-row so at the very least it could skip one nesting level.

I used CSS tables more back when I had to fully support IE8, but other than that, they’re mostly obsolete.

Thread Thread
 
kenbellows profile image
Ken Bellows

So, funny story, I played around with it a bit more, and it tickled my memory enough to remember (because I encountered the same problems again) that I actually had tried to use the display-table method when I was implementing basically the same layout for my job. There are a few different ways to approach this, and each has a fatal problem. In all cases, I'm using display: table for the <main> element (so that the table includes all the cards) and display:table-cell for the counts.

  • If you don't use display: table-row anywhere, it sort of just doesn't work. The problem seems to be that the .article-card element, which is display: block by default, gets in the middle and breaks the CSS table. Looks like it's true that you can skip explicit table rows in a CSS table, but only if the table cells are direct children of the table element. pen

  • If you make give cards display: table-row, the browser wants to put all children on the same line. Which, honestly, produced kind of an interesting layout that I'll keep in mind for future experiments, but doesn't match the mockup. Another issue is that the cards now inherit a lot of the same issues that make working with HTML table rows hard, mainly that rules like margins, borders, and padding aren't supported. pen

  • Just to see if I could make it work, I tried giving the article cards display: contents and adding wrapper elements around different parts of the card with display: table-row. Ignoring the problems I mentioned in the display: contents part of the article, I also ran the problem you mentioned earlier: the absence of a colspan type rule. The problem is that the header is wider than any count, but ends up in the same column as one of the counts. pen

CSS Tables are cool, and might even be a valid solution to this sort of situation if the contents of the card could be a single line, using the cards-as-rows approach with some tweaking for style. But if you need multiple rows within your cards with different sized elements on the different rows, the lack of a colspan is gonna be a problem πŸ˜•

Thread Thread
 
tigt profile image
Taylor Hunt

Wow, super in-depth follow-up. Thanks for your time!

  • The lack of borders and padding might/could be fixed with display:table-row-group and border-spacing.

  • Making the headers full-width might work by leaving them out of the table layout algorithm β€” leave ’em as block, and reorient where the cells start by abusing writing-mode. (I’ve done things I’m not proud of.)

…but all that’s definitely deep in the weeds of hackiness. (And let’s not talk about display:table-caption, which hoists the child box out of the border-box of its parent.)

If the CSS Table Layout specification had equivalents to colspan and rowspan, we would have been halfway to Grid in 2009. But I can’t blame them for underspecifying the weirdest, most browser-specific layout system ever accidented.

Thread Thread
 
kenbellows profile image
Ken Bellows

Good idea, forgot about display: table-row-group, that does make the borders somewhat work again.

But leaving the header and .top wrapper as a block doesn't fix the colspan problem, which is now manifesting in a really weird way... Without checking the spec, it feels like the children of a table-row-group are in some sort of all-or-nothing pact, where if any one of them is given display: table-row (and has at least one table-cell child?), they all act like table-rows with table-cell children. But if none of them have a table display type, they act like blocks, even if one has table-cell children...

  • nothing has table-row: pen
  • only .counts has table-row: pen

Yeah, I have mixed feelings about CSS Tables. I almost think it's better that it was kept small and arguably incomplete; maybe its holes helped motivate CSS Grid? Maybe if it had been more complete, people would have continually pointed to tables whenever someone brought up Grid, the same way some currently point to display: contents when someone mentions subgrids. But on the other hand, if we're going to have a table layout system anyway, might as well make it fully functional. Maybe they could augment it now to complete the picture.

Thread Thread
 
kenbellows profile image
Ken Bellows

By the way, thanks for the replies, it's been very interesting! I forget that CSS Tables are a thing, and they're worth remembering for those odd corner cases

Thread Thread
 
sethveale profile image
Seth Veale

Thanks for the write-up and for not flaming someone for mentioning CSS tables. Open inquiry has not been the norm and you're doing good work here.

Thread Thread
 
hebbybomm profile image
hebbybomm

Ken, thanks for giving a great and detailedwrite-up on the need for subgrid.
I've been frustrated by the lack of subgrid on grid frameworks for a while now.

Collapse
 
dan503 profile image
Daniel Tonon

Based on Rachel's post, it looks like 2 dimensional Sub-Grids are coming to Grid level 2. 😁

smashingmagazine.com/2018/07/css-g...

.parent {
  display: grid;
  grid-template-colums: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
}
.child {
  display: grid;
  grid-column: 1 / 3;
  grid-row: 1 / 3;
  grid-template-rows: subgrid;
  grid-template-columns: subgrid;
}
Collapse
 
kenbellows profile image
Ken Bellows

You know, you're right, and the current Working Draft seems to support that as well:

A grid container that is itself a grid item can defer the definition of its rows and columns to its parent grid container, making it a subgrid.

I must be out of date. The last I had heard was from Rachel's article from April, where she said:

At the CSS Working Group meeting in Berlin we resolved that subgrids should be able to be single axis only, returning them to the original concept rather than the revised one mentioned in my 2016 post.

But there have been at least 3 versions of the Working Draft released since then, and maybe it's changed back again? If so, that would be incredible!

Collapse
 
kenbellows profile image
Ken Bellows • Edited

Turns out you're right! I apparently have been missing the words "able to be" in Rachel's quote above! I've updated the article accordingly. Thanks a zillion for pointing that out to me!

Collapse
 
ben profile image
Ben Halpern

Fabulous writeup. Is it just me or is CSS coming out of a bit of an "awkward phase". Flex-box has been an advancement in a sense, but also sort of seems more like a stepping stone towards these sort of features you're describing.

Collapse
 
kenbellows profile image
Ken Bellows • Edited

Yeah, CSS has definitely matured in the last few years. Flexbox was a big step out of the darkness, but I think Grid is what we've all been waiting for since 1996.

That said, Flexbox is an absolutely critical layout method in and of itself, I just think too many people got used to using it for 2D layouts when it's really specifically designed for complex 1D layouts, because it was still so much better than float-based methods.

I recently read something by Rachel Andrew (I forget what) where she says that she wishes Flexbox and Grid had been ready at the same time and released simultaneously, so that people understood that they're meant to be complementary to each other and used in different circumstances. There are lots of things that Flexbox can do very easily that Grid just can't, and obviously the reverse is true as well.

Edit: She says it in the intro to this Smashing article: "What Happens When You Create A Flexbox Flex Container?"

In my ideal world, CSS Grid and Flexbox would have arrived together, fully formed to make up a layout system for the web. Instead, however, we got Flexbox first and, due to it being better at creating grid-type layouts than floats, we ended up with a lot of Flexbox-based grid systems. In fact, many of the places where people find Flexbox difficult or confusing are really due to this attempt to make it a method for grid layout.

Collapse
 
seejamescode profile image
James Y Rauhut

Ken, thanks for giving a detailed write-up on the need for subgrid! I have been frustrated by the lack of subgrid on grid frameworks for a while now.

This caused me to make Grid Wiz. Grid Wiz makes a CSS Grid framework with specified browser support and includes subgrids. The next minor update will probably happen when Grid Level 2 is released so that the code is smaller, but the visual output is the same.

grid-wiz.now.sh/

Collapse
 
joshcheek profile image
Josh Cheek

I think what I really want is the ability to set constraints, like XCode's Interface Builder. Not sure what that would look like in CSS, but it feels simpler and more powerful than needing to create all these different display extensions.

Collapse
 
kenbellows profile image
Ken Bellows

Yeah, I know what you mean. I think we're getting closer to that, especially with the positioning rules that have been added recently, the align-* and justify-* stuff

Collapse
 
nareshravlani profile image
nareshravlani • Edited

Amazing post Ken. Coming from WPF background , I am not well versed with CSS yet. I was totally unaware about the grid system of CSS. As recommended in some comment, I started playing with gridgarden and I just loved it. I can relate many of CSS grid concepts to WPF grid control (perks of knowing different systems 😊) Thanks.

Collapse
 
johnkreitlow profile image
John Kreitlow

What's grid? I'm still riding the flexbox train off into the sunset πŸš‚

Collapse
 
kenbellows profile image
Ken Bellows • Edited

Oh my friend, if you've never tried grid, get ready to have your mind blown. IMO, Grid is hands down the single greatest improvement to CSS in a decade, and that includes Flexbox. I mean, don't get me wrong, Flexbox was a huge step forward and is still a great tool and a critical piece of the layout puzzle. But Grid is just... hoo, it's amazing.

The TL;DR is that Grid gives us native support for that thing we've been hacking into our HTML and CSS for like 20 years: proper Grid layout. It's incredibly powerful, and it's literally changing the way we write HTML+CSS. It's hard to overstate the effect it's having.

My recommendation to quickly see the power of Grid:

  1. Do this: cssgridgarden.com/
  2. Read this: dev.to/kenbellows/css-grid-areas-a...
Collapse
 
uglyeoin profile image
uglyeoin

I've always used Flexbox for the subgrid. Would that solve your problem?

Collapse
 
kenbellows profile image
Ken Bellows

No, the problem is that you can't use Flexbox to align the children of two different parent elements, which is what subgrids allow you to do

Collapse
 
uglyeoin profile image
uglyeoin

Oh I see, you can't do it on any sort of equal widths or percentage widths or anything, it has to flex but be the same. Got ya. An interesting concept. They should invent height = width whilst they are doing it :D

Thread Thread
 
striptogether profile image
StripTogether

If you plan from the very beginning for a layout without pixel-based wrappers, you can kind of achieve this behavior.

Use the viewport width measurement: vw.
Width: 50vw; Height:50vw;

Thread Thread
 
kenbellows profile image
Ken Bellows • Edited

That works if it's okay to base your container size on the viewport, but I've more often wanted to base the container on its dynamic content, while maintaining a fixed aspect ratio.

There are a few CSS Working Group GitHub issues tracking this feature (#333, #1173), and there's actually a "rough draft" section in the CSS Intrinsic & Extrinsic Sizing Module Level 4 Editor's Draft of a proposed aspect-ratio property to fix this, which I'm pretty excited about.

In the meantime, there is a popular ugly hack that works in certain circumstances (but not all) that relies on the fact that percentages in padding, even top and bottom padding, are always based on the width of an element, so that for example you could make a square with:

.square {
  width: /* whatever */;
  height: 0;
  padding-bottom: 100%;
}

...and then a bunch of gross stuff involving absolute positioning and hidden overflows to get the content to sit in the right place... it works, but it's a bit fragile, so use it with caution. CSS Tricks has a great article on it: "Aspect Ratio Boxes"

Collapse
 
link2twenty profile image
Andrew Bone

This is really well written!

I just love CSS and the last few years have been great. We get to lean on the platform more and more.

Collapse
 
kenbellows profile image
Ken Bellows

Thanks for the compliment!

I agree, I'm very optimistic about the future of the platform!

Collapse
 
bwalowitz profile image
Brandon Walowitz

Couldn’t you just add another parent grid element inside the card to hold the three icon/number elements?

Collapse
 
kenbellows profile image
Ken Bellows

Nope, you'd have the same problem you have with floats or flexbox: there's nothing tying the columns of those separate child grids together, so their column widths won't stay aligned. If one card had 190 likes, 5 unicorns, and 2 bookmarks, but another had 9 likes, 3 unicorns, and 500 bookmarks, the bookmarks in the second card would end up being much wider than the bookmarks in the first card, and would cross underneath at least the unicorns of the first card, if not the likes.

The whole point is that we need a way to link the columns of two separate grids, and the way to do that is to subgrid them to a shared parent grid

Collapse
 
bwalowitz profile image
Brandon Walowitz

I'm all for subgrids, but for this card example, isn't it possible specify the width of the likes, unicorns, and bookmarks inside its own grid. You wrap those three elements in a div. Give the div a display: grid and grid-template-columns: 1fr 1fr 1fr;. Then wrap each individual icon/ number element in a div and give each of them their respective grid-column property. That would give each column the same width regardless of the content inside. For your card example, you only need a grid on the icon/numbers line, don't you?

Thread Thread
 
kenbellows profile image
Ken Bellows

The point isn't to give the three counters in the same card the same width, it's to give all counters of the same type across all cards the same width. E.g., all unicorn counters should be as wide as the widest unicorn in any card, but have no affect on the width of any of the bookmarks.

A few people have been confused about what I was trying to accomplish, which makes me think I've explained it poorly... I guess take a look at the mockup at the top of the article to see what I mean. I'll read things over again and see if I can find a way to reword something to make it clearer.

Collapse
 
rctneil profile image
Neil

Fantastic article! Can't wait. Quick question, can a child of a subgrid be a grid too? eg: multiple nested grids?

Collapse
 
kenbellows profile image
Ken Bellows

I don't see why not! AFAIK, there's no rules about how deeply you can nest grids.

Remember that subgrid is not a new display type or anything; subgrids are still grids with display: grid, they just have a special value for their grid-template-rows and/or grid-template-columns. So anything you can do with regular grids still applies, and grids can clearly have other grids as children, since that's what subgrids are in the first place! 😁

Collapse
 
rctneil profile image
Neil

It's pretty much the layout system we all need when subgrid arrives. Just nest nest nest all your grids and things should line up beautifully!

Thread Thread
 
kenbellows profile image
Ken Bellows

I definitely agree, but let me add an addendum: the most amazing thing I have found in using CSS Grid, especially with the addition of display: contents, is how much less I find that I actually need to nest things at all.

In my experience, if a page implemented with, say, a Bootstrap grid winds up with 10 levels of nesting, it can usually be re-implemented with CSS Grid in like 3 levels of nesting. Templates can be flattened into these clean documents that require nesting only when the semantics call for it, rather than adding a bunch of extra nesting purely in service of layout!

So yes, nested grids with subgrid are basically the final layout puzzle piece the web has been waiting on for 30 years (though IMHO Flexbox is equally as important). But I guess my headline is, don't nest unnecessarily; try to keep everything as flat as possible, because man does it improve readability and maintainability!

Collapse
 
klaster1 profile image
Ilya Borisov

CSS Layout API Level 1 is also worth a mention: if browser does not provide a layout mode you need, just make/polyfill your own.