Designing Intrinsic Layouts by Jen Simmons
Alright, it’s time for the final talk of day one of An Event Apart in Seattle. The trifecta of CSS talks is going to finish with Jen Simmons talking about Designing Intrinsic Layouts. Here’s the description:
Twenty-five years after the web began, we finally have a real toolkit for creating layouts. Combining CSS Grid, Flexbox, Multicolumn, Flow layout and Writing Modes gives us the technical ability to build layouts today without the horrible hacks and compromises of the past. But what does this mean for our design medium? How might we better leverage the art of graphic design? How will we create something practical, useable, and realistically doable?
In a talk full of specific examples, Jen will walk you through the thinking process of creating accessible & reusable page and component layouts. For the last four years, Jen’s been getting audiences excited about what, when, and why. Now it’s time for how.
I’m not sure if live-blogging is going to work given the visual nature of this talk, but I’ll give it a try…
How many of us have written CSS using display: grid
? Quite a few. How many people feel they have a good grip on it? Not so many.
Jen has spent the last few years encouraging people to really push the boundaries of graphic design on the web now that we have the tools to do so in CSS. But Jen is not here today to talk about amazing new things. Instead she’s going to show the “how?” The code is on labs.jensimmons.com.
Let’s look at laying out a header. You might have a header
element with a logo image, the site name in an h1
, and a nav
element with the navigation. The logo, the site name, and the navigation are direct children of the parent header
. By default we get everything stacked vertically.
<header role="banner">
<img class="logo" src="..." alt="...">
<h1>Site title</h1>
<nav>
<ul>
<li><a href="...">Home</a></li>
<li><a href="...">Episodes</a></li>
<li><a href="...">Guests</a></li>
<li><a href="...">Subscribe</a></li>
<li><a href="...">About</a></li>
</ul>
</nav>
</header>
Why should we care about starting with semantic HTML? It matters for reusability and accessibility, but also for reader modes in browsers. These tools remove the cruft. If you mark up your content well, it will play nicely with reader modes. Interestingly, there are no metrics around how many people are using reader modes (by design). Mozilla has a product called Pocket that’s a “read later” app. It can also turn saved articles into a podcast for you. Well marked up content matters for audio playback.
Now let’s start applying some CSS. Fonts, colours, stuff like that. Everything is still stacking vertically though. It’s flow content. This can be our fallback layout. Now let’s apply our own layout. We could use float: left
on the logo. Now we need some margin
s. We can try applying width
s and float
s to the h1
and the nav
. Now we need a clearfix to get the parent to stretch to the full height of the content. It’s hacky. float
s suck. But it’s all we had until we got flexbox. But even using flexbox for this kind of layout is a hack too. What we really need is CSS grid.
Apply display: grid
to the header
. Use Firefox’s dev tools to inspect the grid. Seeing the grid helps in understanding what’s going on. We’ve got three grid items in three separate rows. Notice that we don’t have margin collapsing any more. We can get rid of margins and use grid-gap
instead. But we want is three columns, not three rows. We’ll try:
grid-template-columns: 1fr 1fr 1fr;
Looks okay. Not exactly the spacing we want though. We want the logo and the navigation to take up less space than the site name. We could translate our old percentage values into fr
equivalents. 8%
becomes 8fr
. 75%
becomes 75fr
. 17%
becomes 17fr
. But the logo and the nav never shrink below their actual size. Layout isn’t working like we’re used to. The content will never get smaller than the minimum content size. So the amount of space assigned to each column is no longer linear.
Let’s change those fr
units to percentages. Now we need to get rid of our gaps. But now when the layout gets small, everything squishes up. This is what we need breakpoints for. But now we can do something else. Let’s make the logo max-content
. That column will now be the size of the logo. The other columns can remain `fr:
header {
grid-template columns: max-content 3fr 1fr;
}
Let’s also define the last one—the navigation—as max-content
. We can toss auto
in for the middle content (the site name):
header {
grid-template columns: max-content auto max-content; }
Let’s layout the navigation horizontally. The best tool for this is flexbox. The li
elements are the flex items. So the ul
needs to be the flex container.
ul {
display: flex;
}
Looking good. Let’s allow items to wrap onto another line:
ul {
display: flex;
flex-wrap: wrap;
}
Let’s change that navigation from max-content
to auto
so that it doesn’t get too long:
header {
grid-template columns: max-content auto auto; }
(How you want the navigation items to wrap determines whether you use flexbox or grid. Both are perfectly valid choices. There’s nothing wrong with using grid for the small stuff.)
Just look at how little code we need for this layout!
Let’s try a different layout. We’ll put the navigation on a new row.
header {
grid-template-columns: min-content auto;
grid-template-rows: auto auto
}
Let’s get the logo to span across both rows:
.logo {
row-span: 2;
}
Need to finesse the alignment of the navigation? No problem. Play with align-self
property on the nav
element.
Again, look at how little code this is!
But these layouts are safe. We need to break out of our habits. What about disjointed text? Let’s take the h1
. Apply some typography and colour. Also apply overflow-wrap: anywhere
. Now the text can break within words.
We can take this further. But to do that, we have to wrap all of my letters in separate span
s. Yuck!
Apply display: grid
to the h1
that contains all those span
children. Say grid-template-columns: repeat(8, 1fr)
to make an eight-column repeating grid.
Let’s make it more interesting. We can target each individual letter with grid-column
and grid-row
. There are many ways to tell the browser where to place grid items. We can tell them the start lines. By default it will take up one cell.
Let’s add some images. Let’s rotate items. Place items wherever we want them. Mess around with the units to see what happens. Play with opacity when elements overlap. See the possibilities!
But, people cry, what about Internet Explorer? Use @supports
/* code for every browser */
@supports (display: grid) {
/* code for modern browsers */
}
Set up a fallback outside the @supports
block. Toggle grid on and enough in dev tools to see how the fallback will look. If this kind of thinking is new to you, please watch youtube.com/layoutland where Jen talks about resilient CSS.
Let’s try something else. Jen got an email announcement for an event. It had an interesting bit of layout with some text overlapping an image.
Mark up the content: some headings and images. By default the images are displayed inline. The headings are displayed as blocks.
Think about where your grid lines will need to go. How many lines will you need? How about setting your columns with 1fr 3fr 3fr 1fr
? Now how many rows do you need? You define and the grid on the container and tell the items where to go. Again, it’s not much code. Tweak it. How about setting the columns to be 1fr minmax(100px, 400px) min-content
? You have to mess around to see what’s possible. You can use all sorts of units for columns: fixed lengths (pixels, em
s, rem
s), min-content
, max-content
, percentages, fr
units, minmax()
, and auto
. Play around with the combinations.
Jen shows a whole bunch of her demos. Check them out. Use web inspector to play around with them.
And with that, the first day of An Event Apart Seattle is done!