Good griddance

I’m not great at estimation, but I still try to do it on any project I’m working, even if it’s just for my own benefit. I break down different bits of the work, and ask myself two questions:

  1. How important is this?
  2. How long will it take?

If I were smart, I’d plot the answers on a graph. I start doing the important stuff, beginning with whatever won’t take too long. Then I’ve got a choice: either do the stuff that’s not all that important, but won’t take long—or do the stuff that will take quite a while, but is quite important. Finally, there’s stuff that’s not important and will take quite a while to do. I leave that to the end. If it never ends up getting done, it’s not the end of the world.

I guess it’s not really about estimation; it’s more about prioritisation.

Anyway, I’m working on a fun little project right now—the website for one of Clearleft’s many excellent events. There was one particular part of the design that I had estimated would take quite a while to do, so I didn’t get around to it until today. It was a layout that I figured would take maybe half a day of wrangling CSS.

I used CSS grid and I was done in five minutes. That’s not an exaggeration. It was literally five minutes.

I thought to myself, “Well, I want these elements to be arranged in two rows of three columns, but I want that particular one to always be in the last column of the top row.”

Normally my next step would be to figure out how to translate those wishes into floats and clears, or maybe flexbox. But this time, there was almost no translation. I could more or less write the CSS like I would write English.

I want these elements to be arranged in rows of three columns.

display: grid;
grid-template-columns: 1fr 1fr fr

I want that particular one to always be in the last column of the top row.

grid-row: 1;
grid-column: 3;

That was it. I was done.

I think I may need to recalibrate the estimation part of my brain to account for just how powerful CSS grid is.

Have you published a response to this? :

Responses

keithjgrant.com

Whoops. I did not intend to send my entire article as a reply WM. Please feel free to delete that!

# Thursday, January 1st, 1970 at 12:00am

keith•j•grant

React devs: I want to throw out the entire browser rendering pipeline and re-write it in my framework so I have complete control over it all. CSS devs: I just told the browser what I wanted and it did all the work for me. I was done in five minutes.adactio.com/journal/13831

Jen Simmons

“Normally my next step would be to figure out how to translate those wishes into floats and clears, or maybe flexbox. But this time, there was almost no translation. I could more or less write the CSS like I would write English.” adactio.com/journal/13831 Yup. Grid is 😍

Fotis Papadogeorgopoulos

I feel frustrated to read about a React/CSS split, because I think they are usually complementary. When I read “X dev” “Y dev”, I either feel self-doubt on good days, or inclined to avoid the community on bad ones :)

Orlando Del Aguila

Having control of the DOM rendering is good, I worked in an app a few years ago where rendering was actually an issue. But I don’t see enough value in CSS with JavaScript to do use that (unless is strictly necessary like in #ReactNative is)

polytechnic.co.uk

Today I replaced the Skeleton based layout on this site with a CSS Grid based layout. I’ve been wanting to make the move for a while and finally found the time after waking up at stupid o’clock this morning.

I wanted to do a like-for-like replacement and stick with the 12 column layout. I’m not quite ready for a complete redesign just yet.

Based on this clever repeating column trick from the Mozilla Developer Network this is how I went about it.

First up, create a 12 column grid I can add to any container I want:

.layout { display: grid; grid-template-columns: repeat(12, [col-start] 1fr); grid-column-gap: 2rem;
}

Taking a small-screen first approach, set the immediate children to span 10 of the columns, offset by one:

.layout > * { /* All grid elements to span 10 cols offset by 1 */ grid-column: col-start 2 / span 10;
}

Adding my .layout class to the header and footer elements, and then wrapping main and aside in a div with that class gave me my basic layout. Then as the viewport gets wider, I can just do this on the required breakpoints:

@media screen and (min-width: 1000px) { .layout-main { grid-column: col-start 2 / span 5; } .layout-sidebar { grid-column: col-start 8 / span 4; }
}

I could have simplified the syntax and removed the line names by omitting col-start, but named lines are very powerful and I might want to play with them later.

The end result is my CSS payload has gone from around 20k to just under 6k, and my markup is a lot simpler.

It was ridiculously quick and painless. From branching my repository to deploying the final code took just over an hour, and I’m sure fifteen minutes of that was me double checking I hadn’t missed something. As Jeremy said :

I think I may need to recalibrate the estimation part of my brain to account for just how powerful CSS grid is.

(Thanks to Mat for pointing me towards to Pun Generator for the title)

# Thursday, May 31st, 2018 at 12:08pm

keithjgrant.com

I’ve spent a lot of time thinking about what defines a CSS mindset. Some people seem to “get” it, and others don’t. It’s always felt to me that if I could put my finger on that, maybe CSS would make more sense to those who have struggled with it. One piece of my motivation in writing CSS in Depth was to try to articulate some of those things.

Today I want to take a different tack. I want to look at three key characteristics of CSS that set it apart from conventional programming languages: it’s resilient; it’s declarative; and it’s contextual. Understanding these aspects of the language, I think, is key to becoming proficient in CSS.

CSS is resilient

If you were to randomly delete a chunk of code out of a JavaScript file, the app or page using it would almost certainly come crashing to a halt and much of the script (if not the page as a whole) would become useless. If you do the same thing to CSS, you might not even notice. Almost everything apart from that specific section of code will continue to work as intended.

We call this resilience. HTML and CSS were specifically designed to be fault-tolerant. If there’s a problem, the browser won’t throw an error; instead, it will ignore that part of the code and keep on going.

This may seem crazy from a debugging perspective: if it doesn’t throw errors, how do you know what went wrong? But this is an essential piece to how CSS works. It’s woven into the fabric of the language itself. It may take some getting used to, I admit. Once you understand this, though, you can safely use features that aren’t supported in all browsers. This is what makes progressive enhancement possible.

Consider this example of a grid layout. It works in browsers that support grid, and it works in browsers that don’t support grid. It will be slightly imperfect in those that don’t support grid (the exact sizes of the items will probably vary), but it will still layout the page in roughly the same way:

.portfolio { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
} .portfolio__item { display: inline-block; max-width: 600px;
}

A browser that doesn’t understand the two grid declarations will ignore them, and the other rules will do the work. And a browser that does understand grid will use the grid layout and ignore the inline-block declaration (because that’s how grid was designed to work). Jen Simmons half-jokingly calls this “Quantum CSS”. You can take a feature of CSS and “use it and not use it at the same time. It works and it doesn’t work at the same time.”

This concept of “fallback” behavior is integral to using CSS, but it is a foreign concept in most conventional programming languages.

CSS is declarative

In JavaScript, you give specific, step-by-step instructions how to make something happen. In CSS, you tell the browser what you want to have happen, and it works out the how. This is extremely important to understand. If you get it right, CSS will do all the hard work for you! And if you get it wrong, you’ll be fighting against the grain of the language and you will be frustrated at every turn.

Writing CSS is effectively setting up a system of constraints. You don’t tell the browser where to put every single element on the page; you tell it how much space to put between them and let it sort out where they belong. You don’t tell it (or at least shouldn’t tell it) how tall to make a container; you let it figure that out at render time when it knows the contents of the container, which other styles are applied, and how much width is available in the viewport.

There are too many variables to consider. The point of CSS is to make it so you don’t have to worry about them all. Define some constraints. Let the language work out the details.

A simple example

Let’s consider this CSS for a moment: font-size: 2em. What does it do? “It increases the font size,” you say. But that’s not all. It also adjusts the line wrapping of text in the container, as fewer words will now fit on each line. That in turn will often increase the number of lines of text: so it will also increase the container’s height to contain the new lines of text. When the container’s height changes, anything beneath it on the page will be shifted down accordingly. Finally, it also specifies a value for the local meaning of em. Any other properties defined using ems will have their computed values updated to match.

That one declaration creates a whole slew of changes on the page. And they’re all exactly what you should want: the content will always fit, elements aren’t going to wind up overlapping oddly, and anything defined in terms of the font size (like padding, perhaps) will adapt. You don’t have to worry about those details. The browser makes all those calculations and does the work by default.

If you want to stop these things from happening, you can. You could cap the container height with a max-height and overflow: auto. You could redefine padding to be in rems or px so it doesn’t adapt to the local font size. This highlights an interesting part of writing CSS: sometimes you’re not telling the browser what to do; you’re effectively telling it what not to do.

Griddy goodness

Some of the newer features in CSS do even more. Flexbox and Grid are prime examples of this. With just a few declarations, you can build a grid layout that is extremely flexible and “just works”. You don’t have to worry about countless edge cases. You say, effectively “put these boxes in columns of about 400px wide” and it will do it for you. It takes about three lines of code.

If you were to do this imperatively, you would need to deal with all sorts of odd scenarios. What if there’s an extremely long word in one of the boxes? What if the viewport is very narrow? What if it’s very wide? What if one box has a ton of content and another contains just a few words? But chances are, in CSS, you don’t need to think about any of these things. All the hard thought for this has already gone into the spec, and the browser takes care of it for you. This is the power of a declarative language.

This does come with a trade-off: if the declarative language doesn’t support something you want to do (say, a “masonry” layout), you’re left relying on either odd hacks or JavaScript to help accomplish it. And for years, this sort of thing was a large part of CSS development. Thankfully, with the rise of Flexbox and Grid, we can do far more than we could in the past, without any hacks (and yes, floats were a hack). If this limitation still bothers you, I suggest you read up on CSS Houdini, which is just beginning to land in browsers.

CSS is contextual

In the React era, we have embraced the extremely useful approach of modular, component-based development. CSS best-practices do this as well, with BEM and SMACSS and CSS-in-JS. I don’t want to belittle this, because this is an essential way of thinking when building large-scale applications. But I think it’s equally important to acknowledge that CSS is not 100% modular, nor should it be.

There are two reasons for this. First, and most obvious, is that your app should have some global styles. You will almost always want to set a default typeface and font size at the page level. These values will then be inherited by all descendant elements that don’t explicitly override them. You will also want certain aspects of your design to apply repeatedly throughout the page, such as theme colors, border radii, box shadows, and common margin sizes. More localized styles on the page will then assume these global styles are in place.

Second, and more subtle, is the way CSS and your styling decisions are informed by the surrounding context of the page. Consider applying the following CSS to an element:

.the-thing { position: absolute; top: 10px; left: 10px;
}

What will this code do? Without knowledge of where the element is in the DOM and what styles are applied to the rest of the page, there is no way to know. Absolute positioning is done relative to the nearest positioned ancestor; applying it means different things depending on which ancestor, if any, has positioning applied.

Furthermore, how you can (or cannot) stack one element in front of another is going to be highly dependent on where the two are positioned in the DOM. Shuffling items around in the DOM can cause drastic effects on the way items fit together and stack. This is why document flow and stacking contexts are a vital (and sometimes complicated) topics.

But the contextual nature of CSS is also due in part to the way design works. If an engineer designs a bridge, you can’t just look at the blueprint and say, “this is all good except this one beam here; go ahead and take that out”. Removing that beam has ramifications on the structural integrity of the whole thing. Similarly, changing one part of a design can have ramifications on how other items on the screen are perceived. Frequently, you will need to style multiple elements together, in conjunction.

If you make the heading in a tile bigger, for instance, it becomes more prominent to the user and therefore makes other items on the screen seem less important. The restrictions aren’t about physics as with the bridge, but there are subtle rules of “soft science” that impact human perception. Parts of the page render in a physical space on screen, and the realities of the physical world (and how we perceive it) are important to be aware of.

We like to architect software using principles of modularity and encapsulation. This makes sense in the world of code, because code is complicated and this breaks the problem up into manageable sizes. But we should also be aware that it isn’t always perfect. In CSS, we can never completely disregard what’s going on outside a given module.

Summary

These three aspects make CSS different than conventional programming languages. These differences may feel foreign, but it’s these differences that make CSS so powerful. And it’s my suspicion that developers who embrace these things, and have fully internalized them, tend to be far more proficient in CSS.

# Friday, June 8th, 2018 at 12:00am

jgregorymcverry.com

As someone just beginning with CSS Grid after spending a few years hiding in Bootstrap because a float would never do what I told it I am loving a Grid. I can picture how I want the layout to work in my head and quickly get that onto paper and then into a text editor.

I know, technically what Kieth was saying but I never saw “CSS as a system of constraints”. It was always a system of possibilities. Unlimited ways to make things the way I want things to look. Problem was before CSS Grid I never really had enough skill or the time to learn to get the stuff out of my head and on to the web . That has all changed with CSS Grid.

# Monday, June 11th, 2018 at 5:08pm

Jeremy Keith

Oh, that’s totally intended! If your post is marked up as an h-entry, I pull in the whole thing.