meyerweb.com

Skip to: site navigation/presentation
Skip to: Thoughts From Eric

Archive: 'Tech' Category

Generating Wireframe Boxes with CSS and HTML5

I was recently noodling around with some new layout ideas for An Event Apart’s speaker pages (e.g., Chris Coyier’s or Jen Simmons’) and wanted to share the ideas with other members of the team.  But what I really wanted to show was wireframes to convey basic arrangement of the pieces, since I hadn’t yet done any time polishing details.

I thought about taking screenshots and Photoshopping wireframe boxes over the various layout pieces, but then I wondered: could I overlay boxes on the live page with CSS?  Or perhaps even create and overlay them with nothing but some declarations and a wanton disregard for the sensibilities of god or man?

And that’s when I realized…I could.

“Your scientists were so preoccupied with whether they could they didn’t stop to think if they should.” —Dr. Ian Malcolm (Jurassic Park, 1993)

Now I’m going to share my discovery with you.

Before I get started, I want to make one thing clear: this isn’t backward compatible.  I don’t care.  It doesn’t need to be.  It does work in the latest versions of Firefox and Chrome, within reasonable tolerances—Chrome falls a bit short on one aspect, which I’ll point out when we get there.

All good?  Then let’s go.

The goal was creating X-filled boxes that wireframers love so very, very much.  I figured, any container element that needs to have a box stuck over it gets a class of wireframe.

<div class="wireframe">…(content goes here)…</div>

(Don’t get too attached to that class, by the way: it doesn’t survive the article.  Foreshadowing!)

The easy part was drawing a box around any element with that class.  I decided to use outlines, because they’re rarely employed for box edging and they don’t affect the layout even if your box-sizing is set to content-box.  (Mine usually is, by dint of not setting box-sizing at all.  But, you know, you do you.)

.wireframe {outline: 2px solid gray;}
Adding simple boxes (to a redesigned local copy of Rachel Andrew’s speaker page)

The boxes overlap each other because the layout pieces on the right are, at least for the moment, floated.  They’re laid out that way so that if the right-hand content is short and the bio and articles run long, they can wrap around below the ‘sidebar’.  It’s generally useful to have the outlines showing the actual limits of the element boxes to which they’re attached.

There is a potential drawback here: if your layout involves using negative margins to pull some elements out of their parents, and those parent elements are designated as wireframe boxes, outlines will stretch around the outhanging elements in Firefox, though not in Chrome.  Borders do not act the same way in Firefox.  I can’t rightly call this a bug, because I’m honestly not sure what outlines should do here.  Just be aware of it, is what I’m saying.

Anyway, drawing rectangles with outlines, that’s the easy part.  Now I needed two diagonal lines, going from corner to corner.  But how?

Linear gradients, that’s how.  See, if you use quadrant-based directions for your gradients, special magic math happens under the hood such that at the exact midpoint of the gradient, the color-line that extends perpendicularly off the gradient ray shoots precisely into the corners of the two quadrants adjacent to the quadrant into which the gradient ray is pointing.  Okay, that was probably hard to follow.  For example, set the gradient direction as to top right and the 50% color line of the gradient will run into the top left to the bottom right corners.

That’s exactly what I needed!  Thus:

.wireframe {outline: 2px solid gray;
   background:
      linear-gradient(to top right,
         transparent 49.9%, gray 49.9%,
         gray 50.1%, transparent 50.1%);
}

Okay, that’s one diagonal line.  The other is literally a copy of the first, except for having it go toward a different quadrant.

.wireframe {outline: 2px solid gray;
   background:
      linear-gradient(to top right,
         transparent 49.9%, gray 49.9%,
         gray 50.1%, transparent 50.1%),
      linear-gradient(to bottom right,
         transparent 49.9%, gray 49.9%,
         gray 50.1%, transparent 50.1%);
}
Diagonal lines!

Bingo: an X.  But not one that scales terribly well.  Using percentages there means that the gray lines will be as thick as 0.2% the total length of the gradient ray.  Small boxes get thin, sometimes broken diagonals.  Great big boxes get thick honkin’ lines.

So I fixed it with calc().

.wireframe {outline: 2px solid gray;
   background:
      linear-gradient(to top right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px)),
      linear-gradient(to bottom right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px));
}
Properly sized diagonal lines!

And there you go: two-pixel-thick diagonal lines.

There are two things to note here, before we move on.  First is that the spaces around the operators in the calc() values are intentional and, more to the point, necessary.  If you remove one or both of those spaces, calc() will simply fail to work.  In other words, calc(50%-1px) will fail—no background for you!  This is as designed, and there are reasons for it I don’t want to go into here, but suffice to say they exist and are arguably sensible.  calc(50% - 1px), on the other hand, works as intended.

Well, mostly: this is where Chrome comes up a bit short.  In large boxes, Chrome creates fuzzy lines thicker than 2 pixels.  I’m not sure what it’s doing to fudge the numbers here, but it sure seems like it’s fudging something.  The lines also don’t go into the corners quite as precisely as they should.  Firefox’s lines, on the other hand, come out correctly sized no matter what box size I set up, even if they are a bit jagged at times, and they go exactly into the corners of all the boxes I tested.  Chrome’s sloppiness here isn’t a deal-breaker, as far as I’m concerned, but it’s there and you should know about it.

So that’s an element with an outer edge and two diagonal lines.  This is great as long as the box contains no actual content, which will sit on top of the diagonals, as you can see with the “hero image” in the top right.  Maybe that’s what you want, in which case great, but I specifically wanted overlays.  That way I could stick them on a live page and sort of fade out the contents while sticking wireframe boxes on top, to make the boxes the focus while still showing the stuff inside them.

Enter generated content.  If I create a pseudo-element and attach the diagonal background gradients to that, they can sit on top of all the content.  That’ll also let me throw in a translucent background color to fill the box and fade out the contents.  Like so:

.wireframe {outline: 2px solid gray;
   position: relative; z-index: 1;}
.wireframe::before {
   position: absolute; z-index: 8675309;
   top: 0; bottom: 0; right: 0; left: 0;
   background:
      linear-gradient(to top right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px)),
      linear-gradient(to bottom right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px)),
      #FFF9;
      content: "";
}
Placing the diagonals, and a translucent color, over the elements

I used ::before mostly because hey, why not, but also because clearfix is usually an ::after and I hear people are still using clearfix, more’s the pity.  So this avoids it.  If you’ve moved beyond the need for clearfix, then you can use ::after just as easily.  Whatever floats your fancy.  (Get it?  Floats?  Yeah?  Clearfix?  Floats?  Ah, I kill me.)

The stupidly large z-index on the ::before is there to put the box overlay above any gridded, flexed, or positioned content that has an automatic z-index, or at least a sensible one.  You can raise it as high as you’d like (and your browser’s bit-depth will allow).  The small z-index on the elements themselves, on the other hand, makes sure they get an explicit stacking placement instead of an automatically-assigned place on the Z axis.  I find this generally settles a number of odd behaviors in various browsers.  Your experience may vary.

It was at this point that I realized there was a whole other level here.  I mean, wireframe boxes stretched over content is pretty nifty all by itself.  That could have been enough.  But it wasn’t.

Because what I realized was that I didn’t just want wireframe boxes, I wanted labeled wireframe boxes.  If a box was being applied to a list of articles, then I wanted a great big “Articles” label sitting in the middle of it, to make it obvious what was being placed there.

Well, there was already a content property just sitting there, waiting to throw in actual content instead of an empty string, but how to fill it?  And that’s when I knew that .wireframe’s days were numbered.

That’s because the easiest way to label each box was to use an HTML data attribute to attach the label I wanted to display.  And once that attribute was there, why not apply the wireframe styles based on the presence of the attribute, instead of adding class names that might get in the way of some unexpected DOM script?  So I changed the markup and CSS like this:

<div data-wf="Articles">…(content goes here)…</div>
[data-wf] {outline: 2px solid gray;
   position: relative; z-index: 1;}
[data-wf]::before {
   position: absolute; z-index: 8675309;
   top: 0; bottom: 0; right: 0; left: 0;
   background:
      linear-gradient(to top right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px)),
      linear-gradient(to bottom right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px)),
      #FFF9;
      content: "";
}

(True story: I almost called it data-wtf instead.  Almost.)

Having done that, I could modify the CSS to insert the attribute value, style the inserted text to look nice, and use flexbox properties to center it in the box.  So I did.

[data-wf] {outline: 2px solid gray;
   position: relative; z-index: 1;}
[data-wf]::before {
   position: absolute; z-index: 8675309;
   top: 0; bottom: 0; right: 0; left: 0;
   background:
      linear-gradient(to top right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px)),
      linear-gradient(to bottom right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px)),
      #FFF9;
      content: attr(data-wf);
      font: bold 2em Jubilat, Georgia, serif;
      color: gray;
      display: flex; justify-content: center; align-items: center;
}
Adding centered labels

That yielded big beautiful bold Jubilat labels (Jubilat is one of AEA’s brand font faces), sitting right on top of the center of the box, the crossing of the two diagonal lines behind them.

Which actually turned out to be a small problem for me.  That text is certainly readable, but I wanted it to stand out a bit more from the diagonals.  I decided to stack text shadows in order to semi-simulate outside text stroking.

[data-wf] {outline: 2px solid gray;
   position: relative; z-index: 1;}
[data-wf]::before {
   position: absolute; z-index: 8675309;
   top: 0; bottom: 0; right: 0; left: 0;
   background:
      linear-gradient(to top right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px)),
      linear-gradient(to bottom right,
         transparent calc(50% - 1px), gray calc(50% - 1px),
         gray calc(50% + 1px), transparent calc(50% + 1px)),
      #FFF9;
      content: attr(data-wf);
      font: bold 2em Jubilat, Georgia, serif;
      color: gray;
      text-shadow:
         0 0 0.25em #FFF9, 0 0 0.25em #FFF9,
         0 0 0.25em #FFF9, 0 0 0.25em #FFF9,
         0 0 0.25em #FFF9;
      display: flex; justify-content: center; align-items: center;
}
“Stroking” the box labels

It’s possible to use just four offset shadows with minimal or zero blur, but I find it sometimes creates weird jags on serif fonts, so I like stacking blurred shadows better.  But, again, you do you.

As I looked over the results, it slowly dawned on me that the white-on-gray box scheme works well enough for a starting wireframe setup with no branding applied, but I was planning to drop these on pages with actual design and colors and that sort of thing.  I didn’t want the boxes to fill with translucent white; I wanted them to be translucent versions of the page background color.  And, furthermore, I wanted a way to be able to easily alter that color, when applied to different designs.

Custom properties to the rescue!  Which is to say, native CSS variables to the rescue!

Our page background color at An Event Apart is #F7F6F1, a combo I actually have memorized at this point.  Since I wanted to fill the boxes with a roughly three-quarters-opaque variant, I settled on #F7F6F1BB.  (Actual 75% is BF, if you care.)  So I defined a custom property for it:

html {
   --fill: #F7F6F1BB;
}

I could have assigned the variable to the [data-wf] rule instead of html, but I felt like setting them globally.  Because that’s how I roll, yo—Wulf & Shaw have no strings on me.  If you want to bring the variables in closer, go for it.

While I was there, I figured, why not, let’s also define a variable for the shared color of the outlines, diagonals, and label text.

html {
   --fill: #F7F6F1BB;
   --wire: gray;
}

Then all I needed was to sprinkle variable calls where the colors were sitting.  I ended up here:

html {
   --fill: #F7F6F1BB;
   --wire: gray;
}
[data-wf] {outline: 2px solid var(--wire);
   position: relative; z-index: 1;}
[data-wf]::before {
   position: absolute; z-index: 8675309;
   top: 0; bottom: 0; right: 0; left: 0;
   background:
      linear-gradient(to top right,
         transparent calc(50% - 1px), var(--wire) calc(50% - 1px),
         var(--wire) calc(50% + 1px), transparent calc(50% + 1px)),
      linear-gradient(to bottom right,
         transparent calc(50% - 1px), var(--wire) calc(50% - 1px),
         var(--wire) calc(50% + 1px), transparent calc(50% + 1px)),
      var(--fill);
      content: attr(data-wf);
      font: bold 2em Jubilat, Georgia, serif;
      color: var(--wire);
      text-shadow:
         0 0 0.25em var(--fill), 0 0 0.25em var(--fill),
         0 0 0.25em var(--fill), 0 0 0.25em var(--fill),
         0 0 0.25em var(--fill);
      display: flex; justify-content: center; align-items: center;
}
The final product, with color themes and everything

The label could be broken out to use its own variable (e.g., --text or --label) easily enough, but I wanted a minimum of things to change.  I know myself too well to set up a bunch of controls to fiddle with, especially where color is concerned.

And with that, I had a ready-to-hand, easily theme-able wireframing style block that I can drop into any development page and invoke simply by adding a few data attributes to the markup.  Data attributes, I might add, that would be trivially easy to later find and remove with regular expressions.  It’s a quick way to make it clear to stakeholders that a work in progress is, in fact, in progress, as well as a handy way to visualize which pieces of a prototype layout are going where.

Now that we’ve come to the end and you’re still hanging in there with me, let me just say that I hope you’ve enjoyed this little trip through various parts of CSS.  If you have any questions, feel free to drop them in the comments below.  I’ll do my best to respond in reasonable amounts of time, travel and such permitting.


P.S. And one final note, as Kai Ryssdal would say: every bit of CSS I used here is covered in CSS: The Definitive Guide, 4th Edition.  I turned to my print copy twice in the process of working all this out, as it happens, to remind myself of specific syntax (for custom properties) and whitespace requirements (for calc() operators).  It really feels good to have a thing I made be useful to me!

Declining Complexity in CSS

At the end of last week, I posted this picture to Twitter and Facebook, and on Twitter it kind of took off.

The fourth edition of “CSS: The Definitive Guide” sits on a desk to the right.  To the left are the second and third editions of the same book, one atop the other.  The two stacked books are, together, almost exactly the same height as the single book on the right.
On the left: the 2nd and 3rd editions of “CSS: The Definitive Guide”. On the right, a single copy of the fourth edition. 😳

My intent in posting it was to say, in not nearly so many words, “Look at how CSS has dramatically expanded its capabilities since the previous edition, and wow, I can’t believe Estelle and I did that much work!”  I know we have 280 characters now, but I try not to blog places other than, well, my actual blog.  (Welcome!)

The Twitter reaction was…interesting.  And by interesting, I really do mean interesting.  There were the people who responded with excitement and anticipation—thanks to you all!—but a whole lot of people who said, in effect, “This is what’s wrong with front end, all this accelerating complexity.”

Which was not what I was saying.  And which is not, I think, what’s actually happened here, but it depends on what you mean by ”complexity”.

CSS has a great deal more capabilities than ever before, it’s true.  In the sense of “how much there potentially is to know”, yes, CSS is more of a challenge.

But the core principles and mechanisms are no more complicated than they were a decade or even two decades ago.  If anything, they’re easier to grasp now, because we don’t have to clutter our minds with float behaviors or inline layout just to try to lay out a page.  Flexbox and Grid (chapters 12 and 13, by the way) make layout so much simpler than ever before, while simultaneously providing far more capability than ever before.

“How?  How is that even possible?” you might ask, to which I would reply, “That’s what happens when you have systems that were designed from the outset to be used for layout.”  Floats weren’t; they were a necessary hack.  Inline-block wasn’t; that was a necessary hack.  People did ingenious, brilliant things to make those tools work, yes.  But they were always a perversion of original intent.

Whereas with Grid and Flexbox, we have things that were always meant to handle layout.  That’s why, for example, they make vertical centering of elements a breeze.  A breeze, people.  I’ve been working with the new stuff long enough that I literally forget vertical centering is supposed to be difficult.  I have similar amnesia about the struggle to balance layout needs with accessible source order.  These problems are not 100% banished, but it’s to the point now that when I do run into these problems, it’s a surprise, and almost a personal affront.  Like how you feel when you’ve been zooming along a near-empty highway for hours, enjoying the rush of wind and power, and then you come around a curve and all of a sudden there’s a roadblock of two slow-moving cars side by side, doing exactly the speed limit of all things, each refusing to pass the other.

I envy “the kids”, the ones just starting to learn front end now.  They’re likely never going to know the pain of float drop, or wrestling with inline blocks, or not being able to center along one axis.  They’re going to roll their eyes when we old-timers start grumbling about the old days and say, “Floats?!?  Who ever thought floats would be a good way to lay out a page? That’s totally not what they’re for, anyone can see that!  Were you all high as a kite, or just utterly stupid?”  You know, the way “the kids” talked ten years ago, except then it was about using tables for layout.

So if you’ve written CSS in the past, CSS today is not significantly harder to understand, and probably a bit easier.  There’s just a lot more of it.  You might not be able to remember every single property and value, but that’s okay.  Neither can I.  I don’t think many (or any) of us can hold every last tiny piece of a serious programming language in our heads, either.  We know the core things, and the patterns we learned, and some cool techniques, and there are the things we always have to look up because we don’t often use them.

I also think people saw the books in the picture and forgot about the time component.  I checked the page number at the end of the last chapter for each book (thus omitting appendices and the index) and came up with the following chart.

A chart showing four columns with values of 393, 437, 447, and 1016, respectively.
Editions of CSS: The Definitive Guide

Whoa, right?  But let’s chart those numbers again, this time taking date of publication into account.

A chart showing four columns with values of 393, 437, 447, and 1016, respectively. These have been plotted against a 17-year span of time.  The 393 column in is 2000, the 436 column in 2005, the 447 column in 2006, and the 1016 column in 2017.
Editions of CSS: The Definitive Guide over 18 years

Rather less crazy, I would say.  It’s still an apparent upward trend, but think about all the new features that have come out since the 3rd Edition, or are coming out right now: gradients, multiple backgrounds, sticky positioning, flexbox, Grid, blending, filters, transforms, animation, and media queries, among others.  A lot of really substantial capabilities.  They don’t make CSS more convoluted, but instead extend it into new territories.

Speaking of which, a few people asked how I got the books to line up so neatly.  I admit they’re being supported by a table there, but the real secret?  Grid.  So easy.  Here, have a set of three “book spines” (each one a cite element) gridded out in supporting browsers, and still laid out just fine in older browsers.

Cascading Style Sheets The Definitive Guide Meyer CSS The Definitive Guide Meyer CSS The Definitive Guide Meyer & Weyl

See what I mean?  That took me about 20 minutes all told, even though I’m using internal markup that’s probably not ideal, by putting grids in my grid so I can grid while I grid.  I rearranged the 2nd-3rd-4th source order into the visual arrangement seen in the photo, and centered the text blocks vertically without using margins or padding or line height to fake it, just because I could.  The grid layout is an enhancement: in older browsers, the spines render as a vertical stack, one atop the other, in chronological order.

Another five minutes, and I could neaten that rendering up further so the spines looked more consistent between grid-capable and grid-incapable browsers.  Five to ten more minutes could get the O’Reilly logo and fish graphics into the black areas.  Five more, and it would be neatly responsive.  Maybe I’ll come back and fix it up to do those things, but for now, as far as I’m concerned, this will do nicely.

The other common response I got was, “Well, looks like it’s time for ‘CSS: The Good Parts’!”  Fam, we already have “CSS: The Good Parts”.  Estelle and I just wrote it.  You can see it on the right side of the picture up above.  Available now on paper or in electronic form!

“CSS: The Definitive Guide, 4th Edition” Release and Contents

CSS: The Definitive Guide, 4th Edition is wending its way to the reading public, and I have some updates on that.

The O’Reilly catalog still says October 2017, but for the physical copy, Barnes & Noble and Amazon are now listing a release date of November 5th, 2017, so we seem to have just missed that October release window I was hoping to hit.  But not by much!  The DRM-free version at eBooks is apparently available now, as are Nook and Kindle versions.

For those of you with access to O’Reilly’s Safari subscription service, there’s an older version of the book currently available.  Apparently, so many people have joined the queue to get it that the content-update process breaks.  (Our production editor was impressed.)  O’Reilly’s engineering staff is aware of the problem and working on it, so hopefully by the time you read this, the problem will be resolved and the final copy online.  If not, our apologies, and thanks for your patience.

If you’re wondering if this edition is for you, absolutely it is!  But I would say that, wouldn’t I?  As would my co-author Estelle.  To help you decide, here’s the Table of Contents with a few brief notes on the new things contained therein (chapters marked ALL NEW! are chapters that didn’t exist at all in the 3rd Edition):

  1. CSS and Documents – a brief overview of what CSS is for, how to apply it (including via HTTP headers!), basic syntax, media and feature queries
  2. Selectors – all the selectors as of mid-2017, including :not(), validity pseudo-classes, the case-insensitivity modifier in attribute selectors, and more
  3. Specificity and the Cascade – probably the least-changed chapter, this lays out the cascade in some detail
  4. Values and Units – adds viewport units, ch (which does not actually mean “one character”), calc(), and various new color syntaxes like HSL and #RRGGBBAA patterns
  5. Fonts – includes a lot about @font-face and the process of loading custom fonts, in addition to the classics like weight, style, variant, family, etc.
  6. Text Properties – adds a fair amount of material on non-horizontal writing and alignment, writing modes, hyphenation, and so forth
  7. Basic Visual Formatting – this is another chapter that didn’t change a huge amount from the 3rd Edition, though it does touch on the new values for display
  8. Padding, Borders, Outlines, and Margins – to all the existing details on those basic topics, we’ve added border-radius and all the properties that affect image borders
  9. Colors, Backgrounds, and Gradients – there are all the new background-related properties like background-size and background-clip, handling multiple background images, and the wonder world of linear and radial gradients, explained in more detail than anyone probably thought reasonable, plus there’s a section on box-shadow
  10. Floating and Shapes – floating hasn’t changed much, but the section on Float Shapes is all new and pretty nifty, if I do say so myself
  11. Positioning – this got a section on sticky positioning to go along with the classic positioning material
  12. Flexible Box Layout – ALL NEW! – the ins and outs, the nitty-gritty, the pros and cons of Flexbox
  13. Grid Layout – ALL NEW! – Grid is here and it’s hot; this chapter explores it in up-to-the-minute detail
  14. Table Layout in CSS – the third of the minimally-updated chapters, this discusses how data tables are laid out
  15. Lists and Generated Content – a surprisingly large amount of new material in this chapter, pretty much all centered around @counter-style and its capabilities and how you can create emoji counting systems
  16. Transforms – ALL NEW! – rotating, scaling, translating, 3D effects, and more, all with a minimum of matrix math
  17. Transitions – ALL NEW! – state-based animations and how to define them, introducing some of the basic animation concepts along the way
  18. Animation – ALL NEW! – stateless animations, which can happen at any time, for any reason you choose to define, made possible through @keyframes and a bevy of new properties
  19. Blending, Filtering, Compositing, and Masking – ALL NEW! – all (okay, almost all) the nifty things you used to do in Photoshop, now available natively in browsers, so you can do grayscale images that pop color on hover or click without having to produce two separate images
  20. Media-Dependent Styles – this was almost ALL NEW!, but it’s a radically reworked chapter from the 3rd Edition with fewer bits about printing, no bits on audio, and a whole lot of details about media queries

And then the Appendices:

  1. Animatable Properties – a list of CSS2.1 properties that are animatable, with a note on exactly what can be animated
  2. Basic Property Reference – a compact table of properties, their default values, and the complete value syntax
  3. Color Equivalence Table – the 148 color names defined in CSS Color Level 4 with their equivalents in RGB decimal, RGB percentage, HSL, and hexadecimal formats

Whew!  After all that, you might be thinking that, much like Emacs, this book has everything.  And I’d like to say that it does, but… it doesn’t.  For example, I decided fairly late in the process to drop multicolumn properties.  It was a tough decision, but when I started testing browser support and looking at the state of the specification, it felt too unstable to include.  I’ve rushed explanations in past editions, and usually regretted it.  (Although, fun fact: the 2nd Edition contains the only known documentation of the CSS Working Group’s multi-hour discussion on how the old clip property was supposed to work.)  So I put multicolumn off for the next edition.

Still, there are far far far more examples of things added in than things left out, enough to make this edition twice as long as the previous.  There’s been a lot of growth in CSS over the past decade, and I think Estelle and I have brought together something that will get you up to speed on very nearly all of it.  For those of you eagerly waiting on a copy, we really hope you enjoy the result!

“CSS: The Definitive Guide, 4th Edition” Goes to Print

Yesterday afternoon, CSS: The Definitive Guide, 4th Edition went to the printers.  Eighteen years after the First Edition hit shelves, eleven years after its predecessor came out, five years after I first started working on this edition, and thanks in no small part to Estelle Weyl and a parade of long-suffering editors at O’Reilly, the last changes were entered, the pages were locked, and the repository closed.

It comes in at 1,088 pages: almost exactly twice the length of the Third Edition, with six new chapters and a lot of overhauling of old chapters.  Flexbox, Grid, filtering, blending, clipping and masking, float shapes, animations and transitions, transforms, image borders, counting systems, custom properties (a.k.a. CSS variables), media and feature queries—they’re all in there, and a whole lot more besides.  Gradients got a major new section in what used to be called just “Colors and Backgrounds” and is now “Colors, Backgrounds, and Gradients”.  And all the new background properties!  So many new background properties.

We didn’t skimp on the visuals, either.  The book has, if I counted correctly, a total of 778 figures.  Almost all of them were captured in-browser, and you can download or clone all the files from GitHub.  If you’d rather just browse them online, you can do so thanks to GitHub Pages.  That’s also where to find the transition and animation examples that are referenced in the text, but not figures themselves (detailed animation being somewhat difficult to represent on paper).  If we add figures and animation examples together, there are 826 elements supporting the main text.  Which feels like a lot to me.

The book will be available in both tree-wafer and glowing-display formats from your favorite supplier of such things; e.g., Amazon.  (If you’re going to buy through Amazon and are inclined to support another aspect of my life, please designate Rebecca’s Gift as your Amazon Smile recipient before buying the book.)  I also hear tell it will be available DRM-free from eBooks.com, and potentially in PDF form for those who prefer it.  O’Reilly doesn’t sell books directly any more, but I do believe it will be avialable to those with Safari subscriptions.

I’ll have more to say about the book and its contents as the release date draws closer.  Last I heard, it should be out by the end of this month, but as always, release dates can slip for any number of reasons.  Even if this release does slip, it should still come out no later than early November.

(Let’s hope I didn’t just jinx that.)

This is always a tense and exhilarating time.  What if I got a huge piece completely wrong?  What if I made the wrong calls on what to include and what to defer to the next edition?  What if I missed egregious typos?  What if nobody likes it?  Basically, the same doubts that strike most any author.  But there’s also the incredible feeling of a project brought to its conclusion and the anticipation of getting it into readers’ hands.  This has been a longer-than-usual time coming, but as it usually does, the time has come at last.  I hope you’re looking forward to it half as much as I am.

Adding Backgrounds to Directly Loaded SVGs

My primary SVG viewer is Firefox.  This is partly because it’s always running, so the startup time is essentially zero.  It also allows me to directly inspect and modify elements of the SVG element through the Web Inspector, which can be handy.

But I’ve run into a problem more than once, which is that if I load an SVG file in Firefox, the browser window’s background defaults to white, and a lot of times I’m trying to view images that are partially or entirely white.  I started thinking that if there were a way to make the window background medium gray, that would solve the problem with rare downsides, since I can’t remember trying to view an all-medium-gray SVG.

After a question on Twitter and some ideas from Tibor Martini, I realized I could use Stylish to give the SVG files a background through CSS.  I didn’t want to select all SVGs, only those I was loading directly, so I tried this:

svg:root {background: gray;}

And it worked!  So I decided to make it more robust by doing a multicolor gradient, and grayscaling it on hover.  I couldn’t use filter because that would grayscale the whole image, rather than just the background, but that was easy to work around.  I ended up with this:

svg:root {background: linear-gradient(135deg, hsl(0,50%,60%), hsl(180,50%,40%));}
svg:root:hover {background: linear-gradient(135deg, hsl(0,0%,60%), hsl(180,0%,40%));}

Which works great!  Except that I discovered Firefox applies it to all SVGs, even those loaded into HTML documents via img.  SVGs apparently define their own roots, which I hadn’t expected, but I can see how it might make sense.  So I poked around in MDN until I came up with this:

@-moz-document url-prefix(file:) {
    svg:root {background: linear-gradient(135deg, hsl(0,50%,60%), hsl(180,50%,40%));}
    svg:root:hover {background: linear-gradient(135deg, hsl(0,0%,60%), hsl(180,0%,40%));}
}

And that’s exactly what I wanted.  If it’s useful to you, have at it.  Just paste that into a new Stylish rule in Firefox, and you should be good to go.

If you’re on Chrome, you can import the above into Stylish and create a new rule, but it hasn’t worked for me, and I’m not sure why not.  Removing :root didn’t fix it when I tried, and that shouldn’t matter anyway: I can see in Chrome’s user styles that svg:root is used and applied.  And my Stylish toolbar icon shows the rule is being applied.  It just doesn’t do anything I can see.  If anyone can figure out how to make it work, or explain why it can’t work, I’d love to know in the comments!

CSS: The Definitive Guide, 4th Edition

On Monday, July 3rd, as I sat in the living room of a house just a bit north of New York City, I pushed the last writing and editing changes to CSS: The Definitive Guide, Fourth Edition and notified the production department at O’Reilly that it was ready.

All twenty chapters, three appendices, and associated front matter are now in their hands.

It’s been a long and difficult journey to get here.  Back in 2011-2012, I started updating chapters and releasing them as standalone books, for those who wanted to grab specific topics early.  In mid-2013, I had to stop all work on the book, and wasn’t really able to get back into it until mid-2015.  At that point, I realized that several new chapters had to be added—for example, when I started out on this edition, Flexbox and Grid were pie-in-the-sky ideas that might or might not come to pass.  Feature queries weren’t a thing, back then.  Filters and masks and blend modes were single-browser at best, when I started out.  And forget about really complex list counters.

Now all those topics (and more!) have chapters, or at least major sections.  Had I not been delayed two years, those topics might not have made it into the fourth edition.  Instead, they’re in there, and this edition may well end up twice as long as the previous edition.

I also might not have brought on a co-author, the inestimable Estelle Weyl.  If not for her contribution in new material and her close, expert review of the chapters I’d already written, this book might have been another year in the making.  The Guide was always my baby, but I couldn’t be happier that I decided to share it with Estelle, nor prouder that her name will be on the cover with mine.

Speaking of major changes, I probably wouldn’t have learned AsciiDoc, nor adopted Atom as an authoring environment (I still use BBEdit for heavy-lift text processing, as well as most of my coding).  O’Reilly used to be a “give us your Word docs!” shop like everyone else, but that toolchain doesn’t really exist any more, from what I can tell.  In fact, the first few chapters I’d given them were in Word.  When I finally returned to writing, they had to give me those chapters back as AsciiDoc exports, so I could make updates and push them to O’Reilly’s internal repository.  The files I created to create figures in the book went into their own public repository, which I’ll get to reorganizing once the text is all settled and the figure numbers are locked in.  (Primary to do: create chapter lists of figures, linked to the specific files that were used to create those figures.  Secondary to do: clean up the cruft.)

As of this moment, the table of contents is:

  • Preface
  1. CSS and Documents
  2. Selectors
  3. Specificity and the Cascade
  4. Values, Units, and Colors
  5. Fonts
  6. Text Properties
  7. Basic Visual Formatting
  8. Padding, Borders, Outlines, and Margins
  9. Colors, Backgrounds, and Gradients
  10. Floating and Shapes
  11. Positioning
  12. Flexible Box Layout
  13. Grid Layout
  14. Table Layout in CSS
  15. Lists and Generated Content
  16. Transforms
  17. Transitions
  18. Animation
  19. Filters, Blending, Clipping, and Masking
  20. Media-Dependent Styling
  • Appendix A: Animatable Properties
  • Appendix B: Basic Property Reference
  • Appendix C: Color Equivalence Table

Disclaimer: the ordering and titles could potentially change, though I have no expectation of either.

I don’t have a specific timeline for release as yet, but as soon as I get one, I’ll let everyone know in a post here, as well as the usual channels.  I expect it to be relatively speedy, like the next couple of months.  Once production does their thing, we’ll get it through the QC process—checking to make sure the figures are in the right places and sizes, making sure no syntax formatting got borked, that kind of thing—and then it’ll be a matter of getting it out the door.

And just in case anyone saw there was news about O’Reilly’s change in distribution and is wondering what that means: you can still buy the paper book or the e-book from your favorite retailer, whether that’s Amazon or someone else.  You just won’t be able to buy direct from O’Reilly any more, except in the sense that subscribing to their Safari service gives you access to the e-book.  That does mean a tiny bit less in royalties for me and Estelle, since direct paper sales were always the highest earners.  Then again, hardly anyone ever bought their paper copies direct from O’Reilly, so honestly, the difference will be negligible.  I might’ve been able to buy an extra cup of coffee or two, if I drank coffee.

It feels…well, honestly, it feels weird to have finally reached this point, after such a long time.  I wish I’d gotten here sooner for a whole host of reasons, but this is where we are, and regardless of anything else, I’m proud of what Estelle and I have created.  I’m really looking forward to getting into your hands.

Gridded Headings v. Justified Headings

Amongst the reactions to Gridded Headings, Benjamin de Cock pointed out there’s another way to arrive at the same place I did.  Instead of this:

grid-template-columns:
    minmax(1em,1fr)
    minmax(min-content,max-content)
    minmax(1em,1fr);

…Benjamin pointed out one could instead do this:

justify-content: center;

That’s right: without explicitly specifying any grid columns, but just setting the grid items themselves to be centered, the same behaviors emerge.  Clever!

What’s interesting is that the behaviors are not precisely the same.  While mostly identical behaviors occur with either approach, there are a few subtle differences and a much different possibility space.  I’ll consider each in turn.

First, the differences.  First of all, the small gutters defined by the first and third grid column tracks—the ones defined to be minmax(1em,1fr)—aren’t present in the justify-content version.  This means the headings will jam right up against the edge of the grid container if things get narrow enough.

Side separation versus side smashing.  Grid on the left, justify-content on the right.

So we either need to re-establish them with grid-template-columns, which would seem to put us right back where we were, or else apply side margins to the heading and subheading.  Something like this:

div h2, div h3 {margin-right: 1rem; margin-left: 1rem;}

Either way, that side separation has to be defined (assuming you want it there).  Having to set those separations as margins feels a little clumsy to me, though not hugely so.  Doing all the sizing and separation in a single grid-template-columns declaration feels cleaner to me, though I admit that may be partly due to my current Gridfatuation.

There is another difference worth exploring.  If the content gets wider than the space available, the grid-template-columns approach means the content will overflow to the right (in LTR writing modes).  If it falls offscreen, it can be scrolled to read.  With justify-content: center, the content stays centered within the box, overflowing to both sides.  The content to the left may not be accessible via scrollbar.

How track sizing and content justification handle overspill.  Grid on the left, justify-content on the right.

So if you have a large headline containing a lengthy unhyphenated word, like “Kazakhstan” or “emoluments”, you might prefer one result over the other.

Beyond that, the further possibilities are a lot richer with Grid than with content justification.  Center-justifying the content means exactly that: the element boxes are centered.  So if you were interested in taking the heading and subheading, acting as an apparent unit, and shift them toward one side or another, this would be much easier to accomplish with Grid.

Suppose we want there to be three times as much space to one side of the headings’ column as the other.  Here’s what that would look like:

grid-template-columns:
    minmax(1em,1fr)
    minmax(min-content,max-content)
    minmax(1em,3fr);

That’s it.  One number changed, and the whole setup is offset from the center without losing the coherence of the original demo.

The same thing could likely be approximated with justify-content using side margins on the heading elements, but it wouldn’t be precisely the same, even with percentages.  fr is a very special beast, and permits very unique results.

The other major difference in possibilities is that with Grid, we can rearrange elements visually without ever touching the source.  Suppose we wanted to put the subhead above the heading in some layouts, but not others.  (Whether those different designs live on different pages or at different breakpoints, it really doesn’t matter.)  With Grid, that’s as simple as rewriting the grid template in a line or three of CSS.  The h2 remains ahead of h3 in the HTML.

With justify-content, you’d still have to write that same grid template, or else switch to flexbox and use flex-direction: column-reverse or some such.  That would work if you want to just switch the display order of two headings in a single column.  It tends to fall down for anything more demanding than that.

This is not to say Benjamin came up with a bad alternative!  I like it quite a bit, precisely because it has similar outcomes to my original idea, thus shedding light on creative ways Grid and content alignment can be combined.  But I like it even more for its differences, which shed even more light on how the two things operate.

In that combination of similarity and difference, I can sense an incredible range of capability, chock full of nuance and brimming with possibility.  There are going to be ways to put these things together that nobody has figured out yet.  I know I keep saying this, but there’s a vast landscape opening, so vast that I don’t think we can even guess how far it extends yet, let alone have mapped its terrain.

Gridded Headings

In my ongoing experiments with both a realignment of meyerweb’s design and CSS Grid, I came up with an interesting heading-and-subheading technique I’d like to share.  It allows two elements to be centered as a block, while letting them text-align with respect to each other, while still line-wrapping if necessary.

Here’s a little demobox.

These Are Grid Headings

A useful technique

Boxes and Alignment

It’s the new hotness

Cool

This is pretty darned easy to implement

Gridded Headings

Wednesday, 19 May 2017

Each heading-subheading pair is composed of two heading elements wrapped in another element.  The wrapping element is the grid container for the headings, each of which become grid items.  This is the markup I used:

<div>
    <h2>These Are Grid Headings</h2>
    <h3>A useful technique</h3>
</div>

If you resize your browser window, or select the “Narrow” option, you should see that the boxes surrounding the headings stays as wide as the wider of the two headings.  It “shrink-wraps” them, visually speaking.  In addition, those boxes stay centered within the grid container.

Furthermore, given the demo’s defaults, the two headings are left-aligned with respect to each other.  You can change this: for example, if you choose to “Center-align headings”, the h2s will center when they’re shorter than the subheadings (the h3s).  On the other hand, if you select “Right-align subheads”, then the subheads will right-align themselves with respect to the headings whenever the subhead is shorter in length.

That was actually a bit misleading: if the headings are centered, they’re centered whether or not they’re shorter than the subhead.  It’s just that, if they’re longer, you can’t see that they’re centered, because left-, center-, and right-aligning them has the same effect.  Ditto for right-aligning the subheads: if they’re longer, they sit in the same place regardless of their text alignment.

The alignments hold even when line-wrapping kicks in.  Try narrowing things down to the point that the text starts wrapping.  If you’re having trouble visualizing the two elements, turn on “Separate backgrounds” to given the heads and subheads visually distinct background colors.

So: a centered box as wide as the longest of the two elements, inside which they can align themselves with respect to each other.  Here’s the CSS that makes this possible:

display: grid;
grid-template-columns:
    minmax(1em,1fr)
    minmax(min-content,max-content)
    minmax(1em,1fr);

That’s pretty much it.  The first and third grid tracks are set to be a minimum of 1em, and a maximum of 1fr.  Given the second track (which I’ll get to in a moment), this means the two tracks will split any free space within the grid container, down to a minimum of 1em.  That’s how the centering of the box work; or, if you turn off “Boxes”, how the unbounded text sticks together in the center of the layout area.

That second track, minmax(min-content,max-content), is what makes all the unusual aspects of this possible.  What that says is: “make this grid track no narrower than the narrowest of the grid items in the track, and no wider than the widest grid item”.  In practice, it’ll most likely be as wide as its widest element.

But if I just said max-content (without having the minmax() and min-content parts) for that track width, the track would always be as wide as the widest element at its widest possible layout, which in this case means without line-wrapping the contents.  That would force particularly long headings to run outside of the track, and possibly out of the grid container altogether.  You can see this by enabling “Remove minmax” and narrowing things until text lines should wrap.

It’s the minmax(min-content,max-content) that avoids this fate, because that means that while the grid track (the column the head and subhead share) can’t get any wider than the widest element it contains, it’s allowed to get narrower.  Thus, if the grid container gets too narrow to fit all the grid items’ maximum widths, the contents of the grid items are able to line-wrap, thus avoiding overspill.  In fact, the grid items can keep getting more narrow until they reach min-content, which is to say, the narrowest the track can get without having content of any grid item stick out of the track.  Then it will stop shrinking.

And finally, if you want to see how the options you’ve selected will look in a Gridless browser, select “Remove grids” and see what happens.  Some combinations may not be palatable without Grid, but remember: you can always use @supports(display: grid) to quarantine any styles that are particularly egregious in older UAs.

So there you have it.  While I’m not certain the Grid drop quotes I wrote about last month will be used in the final version of my styles—I’m still looking to see if they’ll fit with more than 17 years of vaguely ad-hoc markup patterns—it’s pretty close to certain I will use these headings, minus the boxes.  I think they’re a neat effect for blog post titles and dates.

Addendum: As of May 2017, WebKit browsers (e.g. Safari) require vendor prefixes for the min-content and max-content keywords.

December 2017
SMTWTFS
November  
 12
3456789
10111213141516
17181920212223
24252627282930
31  

Archives

Feeds

Extras