Decimated

Published 2 weeks, 3 days ago
Rebecca blows out the candles on a birthday cake.

In another timeline, an early alarm woke Kat and me this morning so we could sneak into Rebecca’s room with her siblings and wish her a happy birthday at the moment she turned ten, 7:24am, June 7th, 2018.

Two digits.  It’s a big milestone, in its way.  Rebecca’s best friend Ruth passed it a few days ago.  Ruth, who she called “Ruthie”.  Who shared all three of her initials, and practically had the same birthday.  Who was the last person to whom Rebecca ever spoke a complete sentence in her full voice, the morning of the day before she died: “Goodbye Ruthie, I love you, MWAH!”

Ruth, who still dreams of Rebecca, happy dreams that make her waking sad.

I have dreams like that too, when I remember them.  I don’t often remember my dreams.  But sometimes, I get to spend a little time with her, free of sorrow, on a nighttime walk or at an amusement park my subconscious constructed out of all the parks we ever took her to.

Kat and Carolyn and Joshua and I went to the grave marker this morning, because Kat works all afternoon into the evening and Joshua has an all-day LEGO and chess camp and Carolyn has friends to see before summer vacation gets crazy.  Because life moves on even when a part of you can’t understand why the sky doesn’t collapse and the world doesn’t crack open and time doesn’t shatter into a million sharded memories.  Classes get taken, grades get graduated, camps get attended, trips get planned, work has to be done.  Each day follows on the one before, pulling you further and further away from the last moments your life was normal.

We stood or sat or huddled around the flecked slate blue granite slab under the gray clouds of morning, emotions flaring and fading, subsumed by a profound sorrow without many tears.  We’re too used to it, now.  The sobs of previous years have given way to a steeled mourning.  Sometimes there is resentment at the stupid blind unfairness of the holes shot through all our hearts, the hole in our lives, and all the things she and we never got to experience.

Her playgroup friends still talk of her with their parents.  Rebecca was a good friend, she was funny, she was fun, she was so nice.  In their way, still trying to come to grips with what happened to her.  To them.

They don’t mention her to us.  Children, trying to protect the grown-ups.

Which makes sense, since they know, now, that sometimes grown-ups can’t protect the children.  Sometimes the killer gets into the house and there is nothing you can do to cast it out.

Sometimes there is nothing anyone can do, except hold the victim’s hand as her life ebbs away, and wish your desperate pleas to take her place had been heard.  That there was something to hear, anything to hear, and accept a frantic parent’s bargain of life for life.

Ten years ago today, Rebecca came into this world.  Four years ago today, she left it.

I can’t remember if I ever told her I would never forget her, or if I was too afraid of frightening her.

I clearly remember when and where she told me, sobbing, knowing she would die, that she would never forget me.

I can still recall the terrified strength in her arms, locked around my neck.

I hope I told her then.

Today she should have been ten.


Specificity in :not(), :has(), and :matches()

Published 2 weeks, 5 days ago

A few years back, I wrote a short post on specificity, element proximity, and the negation pseudo-class.  Everything in it is still accurate and relevant, but I have some updates to share.

First off, I’d like to clarify something that some people may have found confusing.  In that post, I said:

But it turns out that the negation pseudo-class isn’t counted as a pseudo-class.

That might leave some people with the idea that the entire negation portion of the selector is ignored for the purposes of specificity, especially if you don’t speak spec.

So consider the following:

div:not(.one) p

In order from left to right, that’s an element selector (div), a negation pesudo-class (:not) a class selector (.one), and another element selection (p).  Two element selectors and one class selector are counted towards the specificity, yielding a total of 0,0,1,2.  That’s the same specificity as div.one p, though the two selectors select very different things.

In Ye Olden Days, that was easy enough to work out, because :not() could only ever contain a simple selector.  Things are looking to get more complicated, however—:not() is set to accept grouped selectors.  So we will at some point be able to say:

div:not(.one, .two, #navbar) p

So any p element that is not descended from a div that has a class containing either one or two (or both), or that has an id of navbar, will be selected.

But how do we calculate the specificity of that whole selector?  Just add up all the pieces?  No.  The Working Group recently decided that the specificity contributed from inside a :not() will be equal to the single selector with the highest specificity.  So given div:not(.one, .two, #navbar) p, the #navbar will contribute 0,1,0,0 to the overall specificity of the selector, yielding a total of 0,1,0,2.  The specificities of .one and .two are ignored.

This same approach will be taken with the :has() and :matches() pseudo-classes.  Thus we get the following:


:matches(nav, header, footer#pageend) a[href] {color: silver;}  /* 0,1,1,2 */
article:has(a.external, a img)  /* 0,0,1,2 */
input:not([type="radio"], [type="checkbox"])  /* 0,0,1,1 */

In the first instance, the bits that are added together are footer#pageend and a[href], so that’s one ID, one attribute, and two elements.  In the second, it’s article and a.external for one class and two elements.  And last, we add up input and either of the [type=""] attribute selectors, since their specificities are equal, which means we add up one attribute and one element.

There is still, so far as I’m aware, no concept of DOM-tree proximity in CSS.  I would still continue to wager that will remain true, though I’d put a fair bit less money down now than I would have six years ago.


GDPR Compliance Notice

Published 1 month, 1 day ago

Hi there!  This is a statement regarding this web site and the data associated with it as compared to the GDPR.  You might think this is ridiculous, but as my site is at least somewhat business-related—it promotes my work, invites people to contact me for consulting or speaking engagements, and the like—here we are.

So:

  • Meyerweb does not set any cookies in your browser, nor does it track you.  This has always been the case, except for a brief period in which I enabled Jetpack to do something or other and then later discovered it was pulling in… other things.  I disabled it immediately, and have no intention of ever enabling it again.
  • Meyerweb’s web host keeps copies of the server’s access logs, which contain the IP address of the device you use to access meyerweb.  It does not, to the best of my knowledge, record any other personally identifying information, unless you hacked your browser’s UA string to contain such information.  Then it will be in the server access logs, and probably next to impossible to get out.
  • As an anti-spam measure, commenters have always been required to supply an email address in order to comment.  Optionally, they may supply a name and URL.  If you have commented in the past, whatever information you provided is still stored in a local database, associated with that comment.  If you wish to have that information removed, contact me and I’ll do my best to remove it.  This may also end up with me removing your comment(s), though I will always try to preserve them.
  • If you have enabled the “email me about followup comments” or “email me about new posts” features of the site, those are managed by WordPress.com.  I do not store that information locally, nor do I have access to it in any way.
  • If you wish to have any personal information about you removed from meyerweb, you can always contact me, and I’ll do my best to handle the request as soon as possible.  If you haven’t heard back from me within ten days, please assume the first attempt got spam-canned or buried in the ongoing avalanche that is my inbox, and ping me on Twitter about the silence.  Please don’t use Twitter as a method of first contact about this, since we’ll have to take any conversation about personally identifying information off Twitter and into email anyway.

And I believe that’s it.  If I missed anything, let me know and I’ll update as needed.


A St. Baldrick’s Appeal From Joshua

Published 3 months, 5 days ago

In March of 2014, our son Joshua, then a newly-minted three-year-old, shaved his head for St. Baldrick’s for the first time, in support of his sister Rebecca, who at the time seemed to be in remission.  This coming Sunday, now in support of all St. Baldrick’s beneficiaries and in memory of the sister with whom he shared so much love, he’ll shave his head for the fifth time.  He’s been letting his hair grow out since the start of the year just for this occasion, and he’s already looking forward to 2020, when he will officially become a Knight of the Bald Table—at the age of nine.

As he was last year, Joshua is a member of Team Fairfax, representing the elementary school all three of our kids have attended.  This year he was designated a Team Captain despite only being a first-grader.

Joshua surpassed his initial goal and set a new, much more ambitious threshold of $1,200.  As I write this, he’s just over $150 away.  If you can help him get over and beyond that line, he—and I—would very much appreciate it.


Displaying CSS Breakpoint Information with Generated Content

Published 4 months, 2 days ago

In the course of experimenting with an example design for my talks at An Event Apart this year, I came up with a way to keep track of which breakpoint was in force as I tested the design’s responsiveness.  I searched the web to see if anyone else had written about this and didn’t come up with any results, so I’ll document it here.  And probably also in the talks.

What I found was that, since I was setting breakpoints in ems instead of pixels, the responsive testing view in browsers didn’t really help, because I can’t maintain realtime mapping in my head from the current pixel value to however many rems it equals.  Since I don’t think the browser has a simple display of that information, I decided I’d do it myself.

It starts with some generated content:

body::before {content: "default";
   position: fixed; top: 1px; right: 1px; z-index: 100; padding: 1ch;
   background: rgba(0,0,0,0.67); color: rgba(255,255,255,0.75);
   font: bold 0.85rem Lucida Grande, sans-serif;}

You can of course change these to some other placement and appearance.  You can also attach these styles to the html element, or your page wrapper if you have one, or honestly even the footer of your document—since the position is fixed, it’ll be viewport-relative no matter where it originates.  The real point here is that we’re generating a bit of text we can change at each breakpoint, like so:

@media (max-width: 38em) {
   body::before {content: "<38em";}
   /* the rest of the breakpoint styles here */
}
@media (max-width: 50em) {
   body::before {content: "<50em";}
   /* the rest of the breakpoint styles here */
}
@media (min-width: 80em) {
   body::before {content: ">80em";}
   /* the rest of the breakpoint styles here */
}

The labels can be any string you want, so you can use “Narrow”, “Wide”, and so on just as easily as showing the measure in play, as I did.

The downside for me is that we automatically can’t make the labels cumulative in native CSS.  That means the order the @media blocks appear will determine which label is shown, even if multiple blocks are being applied.  As an example, given the styles above, at a width of 25em, the label shown will be <50em even though both the 38em and 50em blocks apply.

There are ways around this, like switching the order of the max-width blocks so the 38em block comes after the 50em block.  Or we could play specificity games:

@media (max-width: 38em) {
   html body::before {content: "<38em";}
   /* the rest of the breakpoint styles here */
}
@media (max-width: 50em) {
   body::before {content: "<50em";}
   /* the rest of the breakpoint styles here */
}

That’s not a solution that scales, sadly.  Probably better to sort the max-width media blocks in descending order, if you think you might end up with several.

The upside is that it’s easy to find and remove these lines once the development phase moves to QA.  Even better, before that point, you get a fully customizable in-viewport indication of where you are in the breakpoint stack as you look at the work in progress.  It’s pretty trivial to take this further by also changing the background color of the little box.  Maybe use a green for all the block above the “standard” set, and a red for all those below it.  Or toss in little background image icons of a phone or a desktop, if you have some handy.

So that’s the quick-and-dirty little responsive development hack I came up with this morning.  I hope it’s useful to some of you out there—and, if so, by all means share and enjoy!


Addendum: Emil Björklund proposes a variant approach that uses CSS Custom Properties (aka CSS variables) to implement this technique.


“CSS Pocket Reference, 5th Edition” to Production

Published 4 months, 1 week ago

Just over an hour before I started writing this post, I handed off CSS Pocket Reference, 5th Edition to the Production department at O’Reilly.  What that means, practically speaking, is that barring any changes that the editors find need to be made, I’m done.

Besides all the new-new-NEW properties included in this edition (flexbox and grid being just two of the most obvious examples), we put a lot into improving the formatting for this edition.  Previous editions used a more sprawling format that led to the 4th edition getting up to 238 pages, which cast serious shade on the word “Pocket” there in the title.  After all, not all of us live in climates or cultures where 24/7 cargo pants are a viable option.

So with a few ideas from me and several more from the production team, we managed to add in all the new properties and still bring the page count down below 200.  My guess is the final copy will come in about 190 pages, but much will depend on how crazy the indexer gets, and how much the formatting gets changed in the final massaging.

We don’t have a firm release date yet; I’m pulling for April, but it’s really not up to me.  I’ll make announcements via all the usual channels when pre-order is available, and of course when publication day arrives.

For now, for the first time in many years, I don’t have a book project on my to-do list.  I don’t even have a book proposal on my to-do list.  It’s a slightly weird feeling, but not an unwelcome one.  I’ll be putting the extra time into my content for An Event Apart: I’m giving a talk this year on using the new CSS tools to make our jobs easier, and doing Day Aparts in Boston and San Francisco where I spend six hours diving deep into guts of stuff like flexbox Grid, writing modes, features queries, and a whole lot more.

So my time will continue to be fully spoken for, is what I’m saying.  It’ll all be fun stuff, though, and it’s hard to ask for more out of my work.


My Contribution to “Modern Loss”

Published 4 months, 4 weeks ago

 

My wife Kat and I tell ourselves we’d love another child for who they are, not for who they replace. We even believe it. But we can’t be sure of it—and that keeps us from shutting our eyes, jumping back into the adoption process, and hoping it will turn out okay. We know all too horribly well that sometimes, it doesn’t.

That’s the opening of my essay “The Second Third Child”, included in the new book from Modern Loss titled Modern Loss: Candid Conversation About Grief. Beginners Welcome, published this week.

I’m deeply honored to be one of the 40+ contributors to the book, some of whom you may know—Dresden Dolls co-founder Amanda Palmer, CNN’s Brian Stelter, author Lucy Kalanithi, Dear Evan Hansen director Michael Greif, Stacy London of What Not To Wear—and many of whom you may not, as I will be unknown to the vast majority of the book’s readers. I’ve written articles for Modern Loss in the past, but to be entrusted with a part of their first book was humbling.

Several of the essays in the book are intentionally funny, but mine is not one of them. It’s quiet, reflective, and elegiac in more than one way, but never anything but honest. It appears in the first section of the book, titled “Collateral Damage”.

As Stephen Colbert put it: “Talking about loss can feel scary. This book isn’t. It’s about grieving deeply over the long term, and the reassurance that you’re far from broken because of it.” I hope my essay, and the book as a whole, helps readers to come to terms with their own grief, by seeing that they are not alone, and that they did the best they could even if it doesn’t feel that way at all.

All my thanks to Rebecca Soffer and Gabrielle Birkner for making me a part of their incredible, inspiring work.


Headings and Labels

Published 5 months, 5 days ago

Following on my last two posts about accessibility improvements to meyerweb, I’ve made two more adjustments: better heading levels and added ARIA labels.

For the heading levels, the problem I face is one familiar to many authors: what makes sense as an <h1> in some situations needs to be an <h2> in others.  The most common example is the titles of blog posts like this one.  On its permalink page, the title of the page is the title of the post.  There, it should be an <h1>.  On archive pages, including the home page of meyerweb, there are a number of posts shown one after the other.  In those situations, each post title should be an <h2>.

Part of the redesign’s changes were to write a single PHP routine that generated posts and their markup, which I could then simply call from wherever.  So I added an optional function parameter that allowed me to indicate the context in which a post was being placed.  It goes something like this:

<?php blogpostMarkup("archive"); ?>
function blogpostMarkup($type = "standalone") {
    if ($type == "archive") $titletag = "h2"; else $titletag = "h1";
    // …markup is all generated here…
    echo $output;
}

Or code to that effect.  (I did not go copy-paste from my actual code base.)

So now, heading levels are what they should be, at least on most pages (I may have missed updating some of my old static HTML pages; feel free to point them out in the comments if you find one).  As a part of that effort, I removed the <h1> from the masthead except on the home page, being the one place it makes sense to be an <h1>.

As for ARIA labels, that came about due to a comment from Phil Kragnes on my last post, where he observed that pages often have multiple elements with a role of navigation.  In order to make things more clear to ARIA users, I took Phil’s suggestion to add aria-label attributes with clarifying values.  So for the page-top skiplinks, I have:

<nav role="navigation" aria-label="page" id="skiplinks">

Similarly, for the site-navigation bar, I have:

<nav role="navigation" aria-label="site" id="navigate">

The idea is that screen readers will say “Page navigation region” and “Site navigation region” rather than just repeating “Navigation region” over and over.

Other than cleaning up individual pages’ heading levels and the occasional custom layout fix (e.g., the Color Equivalents Table needed a local widening of the content column’s maximum size), I think the redesign has settled into the “occasional tinkering” phase.  I may do something to spruce up my old Web Review articles (like the very first, written when HTML tags were still uppercase!) and I’m thinking about adding subnavigation in certain sections, but otherwise I think this is about it.  Unless I decide to go really over the top and model my Tools page after Simon St. Laurent’s lovely new Grid design, that is…

Of course, if you see something I overlooked, don’t hesitate to let me know!  I can’t guarantee fast response, but I can always guarantee careful consideration.