Posts in the Guide Category

A Leap of Decades

Published 1 year, 3 weeks past

I’ve heard it said there are two kinds of tech power users: the ones who constantly update to stay on the bleeding edge, and the ones who update only when absolutely forced to do so.  I’m in the latter camp.  If a program, setup, or piece of hardware works for me, I stick by it like it’s the last raft off a sinking island.

And so it has been for my early 2013 MacBook Pro, which has served me incredibly well across all those years and many continents, but was sliding into the software update chasm: some applications, and for that matter its operating system, could no longer be run on its hardware.  Oh and also, the top row of letter keys was becoming unresponsive, in particular the E-R-T sequence.  Which I kind of need if I’m going to be writing English text, never mind reloading pages and opening new browser tabs.

Stepping Up

An early 2013 MacBook Pro sitting on a desk next to the box of an early 2023 MacBook Pro, the latter illuminated by shafts of sunlight.
The grizzled old veteran on the verge of retirement and the fresh new recruit that just transferred in to replace them.

So on Monday, I dropped by the Apple Store and picked up a custom-built early 2023 MacBook Pro: M2 Max with 38 GPU cores, 64GB RAM, and 2TB SSD.  (Thus quadrupling the active memory and nearly trebling the storage capacity of its predecessor.)  I went with that balance, or perhaps imbalance, because I intend to have this machine last me another ten years, and in that time, RAM is more likely to be in demand than SSD.  If I’m wrong about that, I can always plug in an external SSD.  Many thanks to the many people in my Mastodon herd who nudged me in that direction.

I chose the 14” model over the 16”, so it is a wee bit smaller than my old 15” workhorse.  The thing that surprises me is the new machine looks boxier, somehow.  Probably it’s that the corners of the case are not nearly as rounded as the 2013 model, and I think the thickness ratio of display to body is closer to 1:1 than before.  It isn’t a problem or anything, it’s just a thing that I notice.  I’ll probably forget about it soon enough.

Some things I find mildly-to-moderately annoying:

  • DragThing doesn’t work any more.  It had stopped being updated before the 64-bit revolution, never mind the shift to Apple silicon, so this was expected, but wow do I miss it.  Like a stick-shift driver uselessly stomping the floorboards and blindly grasping air while driving an automatic car, I still flip the mouse pointer toward the right edge of the screen, where I kept my DragThing dock, before remembering it’s gone.  I’ve looked at alternatives, but none of them seem like they’re meant as straight up replacements, so I’ve yet to commit to one.  Maybe some day I’ll ask Daniel to teach me Swift to I can build my own. (Because I definitely need more demands on my time.)
  • The twisty arrows in the Finder to open and close folders don’t have enough visual weight.  Really, the overall UI feels like a movie’s toy representation of an operating system, not an actual operating system.  I mean, the visual presentation of the OS looks like something I would create, and brother, that is not a compliment.
  • The Finder’s menu bar has no visually distinct background.  What the hell.  No, seriously, what the hell?  The Notch I’m actually okay with, but removing the distinction between the active area of the menu bar and the inert rest of the desktop seems… ill-advised.  Do not like.  HARK, A FIX: Cory Birdsong pointed me to “System Settings… > Accessibility > Display > Reduce Transparency”, which fixes this, over on Mastodon.  Thanks, Cory!
  • I’m not used to the system default font(s) yet, which I imagine will come with time, but still catches me here and there.
  • The alert and other systems sounds are different, and I don’t like them.  Sosumi.

Oh, and it’s weird to me that the Apple logo on the back of the display doesn’t glow.  Not annoying, just weird.

Otherwise, I’m happy with it so far.  Great display, great battery life, and the keyboard works!

Getting Migratory

The 2013 MBP was backed up nightly to a 1TB Samsung SSD, so that was how I managed the migration: plugged the SSD into the new MBP and let Migration Assistant do its thing.  This got me 90% of the way there, really.  The remaining 10% is what I’ll talk about in a bit, in case anyone else finds themselves in a similar situation.

The only major hardware hurdle I hit was that my Dell U2713HM monitor, also of mid-2010s vintage, seems to limit HDMI signals to 1920×1080 despite supposedly supporting HDMI 1.4, which caught me by surprise.  When connected to a machine via DisplayPort, even my 2013 MBP, the Dell will go up to 2560×1440.  The new MBP only has one HDMI port and three USB-C ports.  Fortunately, the USB-C ports can be used as DisplayPorts, so I acquired a DisplayPort–to–USB-C cable and that fixed the situation right up.

Yes, I could upgrade to a monitor that supports USB-C directly, but the Dell is a good size for my work environment, it still looks pretty good, and did I mention I’m the cling-tightly-to-what-works kind of user?

Otherwise, in the hardware space, I’ll have to figure out how I want to manage connecting all the USB-A devices I have (podcasting microphone, wireless headset, desktop speaker, secondary HD camera, etc., etc.) to the USB-C ports.  I expected that to be the case, just as I expected some applications would no longer work.  I expect an adapter cable or two will be necessary, at least for a while.

Trouble Brewing

I said earlier that Migration Assistant got me 90% of the way to being switched over.  Were I someone who doesn’t install stuff via the Terminal, I suspect it would have been 100% successful, but I’m not, so it wasn’t.  As with the cables, I anticipated this would happen.  What I didn’t expect was that covering that last 10% would take me only an hour or so of actual work, most of it spent waiting on downloads and installs.

First, the serious and quite unexpected problem: my version of Homebrew used an old installation prefix, one that could break newer packages.  So, I needed to migrate Homebrew itself from /usr/local to /opt/homebrew.  Some searching around indicated that the best way to do this was uninstall Homebrew entirely, then install it fresh.

Okay, except that would also remove everything I’d installed with Homebrew.  Which was maybe not as much as some of y’all, but it was still a fair number of fairly essential packages.  When I ran brew list, I got over a hundred packages, of which most were dependencies.  What I found through further searching was that brew leaves returns a list of the packages I’d installed, without their dependencies.  Here’s what I got:

automake
bash
bison
chruby
ckan
cmake
composer
ffmpeg
gh
git
git-lfs
httpd
imagemagick
libksba
lynx
minetest
minimal-racket
pandoc
php
php@7.2
python@3.10
ruby
ruby-install
wget
yarn

That felt a lot more manageable.  After a bit more research, boiled down to its essentials, the New Brew Shuffle I came up with was:


$ brew leaves > brewlist.txt

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)"

$ xcode-select --install

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

$ xargs brew install < brewlist.txt

The above does elide a few things.  In step two, the Homebrew uninstall script identified a bunch of directories that it couldn’t remove, and would have to be deleted manually.  I saved all that to a text file (thanks to Warp’s “Copy output” feature) for later study, and pressed onward.  I probably also had to sudo some of those steps; I no longer remember.

In addition to all the above, I elected to delete a few of the packages in brewlist.txt before I fed it back to brew install in the last step — things like ckan, left over from my Kerbal Space Program days  —  and to remove the version dependencies for PHP and Python.  Overall, the process was pretty smooth.  I just had to sit there and watch Homrebrew chew through all the installs, including all the dependencies.

Cleanup

Once all the reinstalls from the last step had finished, I was left with a few things to clean up.  For example, Python didn’t seem to have installed.  Eventually I realized it had actually installed as python3 instead of just plain python, so that was mostly fine and I’m sure there’s a way to alias one to the other that I might get around to looking up one day.

Ruby also didn’t seem to reinstall cleanly: there was a library it was looking for that complained about the chip architecture, and attempts to overcome that spawned even more errors, and none of them were decipherable to me or my searches.  Multiple attempts at uninstalling and then reinstalling Ruby through a variety of means, some with Homebrew, some other ways, either got me the same indecipherable erros or a whole new set of indecipherable errors.  In the end, I just uninstalled Ruby, as I don’t actually use it for anything I’m aware of, and the default Ruby that comes with macOS is still there.  If I run into some script I need for work that requires something more, I’ll revisit this, probably with many muttered imprecations.

Finally, httpd wasn’t working as intended.  I could launch it with brew services httpd start, but the resulting server was pointing to a page that just said “It works!”, and not bringing up any of my local hosts.  Eventually, I found where Homebrew had stuffed httpd and its various files, and then replaced its configuration files with my old configuration files.  Then I went through the cycle of typing sudo apachectl start, addressing the errors it threw over directories or PHP installs or whatever by editing httpd.conf, and then trying again.

After only three or four rounds of that, everything was up and running as intended  —  and as a bonus, I was able to mark httpd as a Login item in the Finder’s System Settings, so it will automatically come back up whenever I reboot!  Which my old machine wouldn’t do, for some reason I never got around to figuring out.

Now I just need to decide what to call this thing.  The old MBP was “CoCo”, as in the TRS-80 Color Computer, meant as a wry commentary on the feel of the keyboard and a callback to the first home computer I ever used.  That joke still works, but I’m thinking the new machine will be “C64” in honor of the first actually powerful home computer I ever used and its 64 kilobytes of RAM.  There’s a pleasing echo between that and the 64 gigabytes of RAM I now have at my literal fingertips, four decades later.

Now that I’m up to date on hardware and operating system, I’d be interested to hear what y’all recommend for good quality-of-life improvement applications or configuration changes.  Link me up!


Preventing Commits to the master Branch in OS X Mojave

Published 4 years, 1 month past

What happened was, I was preparing to roll out new designs for the News section and event pages of An Event Apart, and I had each rollout in its own branch.  Somewhere in the process of bringing both into the master branch, I managed to create a merge conflict that rapidly led to more and more conflicts.  I very nearly had to take off and nuke the entire site from orbit, just to start over.  (A couple of branches, including dev, did have to get erased and re-pulled.)

Part of what made it worse was that at one point, I accidentally committed a quick edit to master, because I’d forgotten to check out the branch I was trying to edit, and my attempts to undo that mistake just compounded whatever other mistakes already existed.  Once all the dust settled and things were back into good shape, I said to myself, “Self, I bet there’s a way to prevent commits to the master branch, because git is second only to emacs in the number of things you can do to/with it.”  So I went looking, and yes, there is a way: add the following to your .git/hooks/pre-commit file.

#!/bin/sh

branch="$(git rev-parse --abbrev-ref HEAD)"

if [ "$branch" = "master" ]; then
  echo "You can't commit directly to master branch"
  exit 1
fi

I got that from this StackOverflow answer, and it was perfect for me, since I use the bash shell.  So I created the pre-commit file, made a trivial README.md edit, and tried to commit to master.  That’s when OS X Mojave’s Terminal spit back:

fatal: cannot exec '.git/hooks/pre-commit': Operation not permitted

Huh.  I mean, it prevented me from committing to master, but not in a useful way.  Once I verified that it happened in all branches, not just master, I knew there was trouble.

I checked permissions and all the rest, but I was still getting the error.  If I went into .git/hooks and ran the script from the command line by ./pre-commit, I got a slightly different error:

-bash: ./pre-commit: /bin/bash: bad interpreter: Operation not permitted

So I submitted my own StackOverflow question, detailing what I’d done and the file and directory permissions and all the rest.  I was stunned to find out the answer was that Mojave itself was blocking things, through its System Integrity Protection feature.  Why did this simple file trigger SIP?  I don’t know.

The fix, shared by both Jeff and Rich, was to go into .git/hooks and then type the following to check for SIP status:

xattr -l pre-commit

It showed a com.apple.quarantine value, so I then typed:

xattr -d com.apple.quarantine pre-commit

And that was it!  Now if I try to commit a change to the master branch, the commit is rejected and I get a warning message.  At that point, I can git stash the changes, check out the proper branch (or a new one), and then git stash pop to bring the changes into that branch, where I can commit them and then merge the changes in properly.

I may modify the script to reject commits to the dev branch as well, but I’m holding off on that for now, since the dev branch is often where merge conflicts are worked out before going to master.  Either way, at least I’ll be less likely to accidentally foul up master when I’m hip-deep in other problems.


What is the CSS ‘ch’ Unit?

Published 5 years, 8 months past

I keep seeing authors and speakers refer to the ch unit as meaning “character width”.  This leads to claims that you can “make your content column 60 characters wide for maximum readability” or “size images to be a certain number of characters!”

Well… yes and no.  Specifically, yes if you’re using fixed-width fonts.  Otherwise, mostly no.

This is because, despite what the letters ch might imply, ch units are not “character” units.  They are defined as:

Equal to the used advance measure of the “0” (ZERO, U+0030) glyph found in the font used to render it. (The advance measure of a glyph is its advance width or height, whichever is in the inline axis of the element.)

So however wide the “0” character is in a given typeface, that’s the measure of one ch.  In monospace (fixed-width) fonts, where all characters are the same width, 1ch equals one character.  In proportional (variable-width) fonts, any given character could be wider or narrower than the “0” character.

To illustrate this, here are a few example elements which are set to be exactly 20ch wide, and also contain exactly 20 characters.

Courier

Look, 20 characters. abcdefghijklmnopqrst 12345678901234567890 iiiiiiiiiiiiiiiiiiii mmmmmmmmmmmmmmmmmmmm

Helvetica

Look, 20 characters. abcdefghijklmnopqrst 12345678901234567890 iiiiiiiiiiiiiiiiiiii mmmmmmmmmmmmmmmmmmmm

Georgia

Look, 20 characters. abcdefghijklmnopqrst 12345678901234567890 iiiiiiiiiiiiiiiiiiii mmmmmmmmmmmmmmmmmmmm

It’s probably no surprise that in Courier, all the elements are the exact same width as their text contents.  In Helvetica, by contrast, this is mostly not the case except for numbers, which appear to be fixed-width.  In Georgia, by contrast, none of the text contents fit the boxes, not even the numbers.

What I’ve found through random experimentation is that in proportional typefaces, 1ch is usually wider than the average character width, usually by around 20-30%.  But there are at least a few typefaces where the zero symbol is skinny with respect to the other letterforms; in such a case, 1ch is narrower than the average character width.  Trajan Pro is one example I found where the zero was a bit narrower than the average, but I’m sure there are others. Conversely, I’m sure there are typefaces with Big Fat Zeroes, in which case the difference between ch and the average character width could be around 50%.

So in general, if you want an 80-character column width and you’re going to use ch to size it, aim for about 60ch, unless you’re specifically working with a typeface that has a skinny zero.  And if you’re working with multiple typefaces, say one for headlines and another for body copy, be careful about setting ch measures and thinking they’ll be equivalent between the two fonts.  The odds are very, very high they won’t be.

It would be interesting to see the Working Group take up the idea of average character width as a unit of measure — say, 1acw or possibly just 1cw — which actually uses all the letterforms in a typeface to calculate an average value.  That would get a lot closer to “make your columns 60 characters wide!” in a lot more cases than ch does now.


Gridded Headings

Published 6 years, 9 months past

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.


Grid-Powered Drop Quotes

Published 6 years, 11 months past

I’ve been experimenting with CSS Grid for various layout treatments — not high-level, whole-page layouts, but focused bits of design.  I’d like to share one of them for a few reasons.  Partly it’s because I like what I came up with.  More importantly, though, I think it illustrates a few principles and uses of CSS Grid that might not be immediately intuitively obvious.

First, here’s an interactive demo of the thing I’m going to be talking about.  You can use the checkboxes to alter aspects of the example, whether singly or in combination.  Feel free to fiddle with them before reading the rest of the article, or but you’ll probably want to come back to the demonstration as you read.  There’s also an external version of the demo as a standalone file, if you prefer opening it in a new tab and flipping back and forth.

So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.

Besides, Grid was coming. In the run-up to Grid support being released to the public, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication.  And then, March 7th, 2017, it shipped to the public in Firefox 52.  I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass.  After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.

And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout.  It took me less than five minutes…

Let’s dig in!  The core concept here is a Grid-powered version of the big drop-quote on the left side, there, which is a relatively common treatment for blockquotes.  To make this happen, I’ve applied display: grid to the blockquote element itself, and added the opening quote using generated content, like so:

blockquote {
   display: grid;
   grid-template-columns: -webkit-min-content 1fr;
   grid-template-columns: min-content 1fr;
}
blockquote::before {
   grid-column: 1;
   content: "“";
   font-size: 5em;
   font-weight: bold;
}

There’s more to the actual styles of both rules, but that’s the central thesis: set up a two-column grid, and generate a great big opening quote.

The first thing to note here is that generated content also generates a pseudo-element that can be styled.  You may already realize this, since it’s known we can style generated content separately from the main content of the element.  But given that, if a grid is applied to the element, then any generated content’s pseudo-element, whether ::before or ::after, will become a grid item.  You can then place it in the grid.

I first came across this concept in the comments on my ALA article “Practical CSS Grid”, where Šime proposed using generated elements as a hack to get around the inability to directly style grid cells.  Here, I’m just using one to push a quote over to the side.

Why do this, when we can already use floats or relative/absolute positioning approaches to do the same?  Because it’s not quite the same: with Grid, the column containing the drop-quote responds to any changes to the quotation symbol.  Change the font, change its size, have the preferred font fail and fall back to an unexpected face, or replace the character with an SVG image, and the first column will resize thanks to the min-content track sizing, and the actual main content of the blockquote will adjust its placement to accommodate.  That didn’t happen with earlier techniques.

And yes, there is a vendor prefix in there.  Safari’s 10.1 Grid support came with -webkit- prefixed versions of min-content, max-content, and fit-content.  So I did the old pattern of prefixed first, unprefixed second.  This should be necessary only until the next release; Safari has already dropped the prefixes in its latest Technology Preview builds.  The change apparently just didn’t quite make the cut for 10.1.  It’s sad, but it’s also temporary.

In the meantime, this does mean that if you want to restrict your Grid styles only to implementations that don’t require prefixes, use that in your feature queries:

@supports (grid-template-columns: min-content) {…}

That, as well as a number of close variants like using grid-template-rows or max-content, will keep your Grid styles away from Safari until they update their Grid support in the public release channel.

That’s all nice, but there’s a great deal more to learn!  If you use the “Border” checkbox in the demo, you’ll see a dotted red border around the drop quote’s pseudo-element.  Notice that it matches the height of the opening paragraph, not the entire height of the blockquote.  That’s because the pseudo-element and the first paragraph share a row track.  The following paragraphs are in their own row tracks.

This brings up two things to consider.  First, all the child elements of the blockquote are now grid items.  That means the drop quote’s pseudo-element, but also all the paragraphs contained by the blockquote.  The same would happen to any child elements.  We could get around that by wrapping all the contents of the blockquote in a div or something like that, but I’d rather not.  So, this grid has four grid items: the pseudo-element, and three paragraphs.

This leads us to the second consideration: without placing the paragraphs into the same column, they’ll auto-flow into whatever grid cells are available.  You can see this by selecting the “Auto placement” option.  The first column will contain the quote and the second paragraph, as narrow as they both can be due to min-content.  The second column will contain the first and third paragraphs.

How I get around this in the working version is to explicitly put all the paragraphs — really, all child elements of the blockquote, which just happen in the case to be paragraphs — into the second column, like this:

blockquote > * {grid-column: 2;}

Okay, but how do they end up stacked vertically?  After all, I didn’t assign each of those child elements to a row, did I?

Wait a minute.  What rows?

If you go back and look at the CSS I showed, there is nothing about rows.  The property grid-template-rows exists, but I didn’t use it.  All I did was define columns.

Each child element goes into a row of its own anyway, because Grid has the ability to automatically create columns or rows when needed.  Suppose you define a three-by-three grid, and then assign a grid item to the fifth column of the fourth row.  What should happen?  The browser should auto-create as many columns and rows as needed.  Any auto-created tracks will have zero width or height if they don’t contain any grid items, unless you size them using grid-auto-columns or grid-auto-rows, but we’re not going there today.  The point is, here I’ve said all of the blockquote’s child elements should go into column 2.  Given that, they’ll auto-fill rows as available and auto-create rows as needed, filling them in once they’re created.

So the blockquote in the demo above has two columns because I explicitly defined them, and three rows because that’s what it needed to create to handle the three child elements.  If I’d added two more paragraphs and an unordered list, the grid would have had two columns and six rows (because six chid elements).

There are a lot of possible extensions to this technique.  A close quote could be created using ::after and placed in the last row of the grid, thanks to the ability to use negative track values to count back from the end of the grid.  Thus:

blockquote::after {
   grid-column: 3;
   grid-row: -1;
   content: "”";
   font-size: 5em;
   font-weight: bold;   
}

That places the close-quote in the third column, so to the right of the quoted text, and in the last row, regardless of how many rows were auto-created.  Of course, there is no third column…or there wasn’t, until assigning something to the third column.  At the point, the browser created it.

The danger there is that the auto-generated column is essentially tacked on to the trailing edge of the grid, without real consideration for what might be in the way — up to and including the edge of the viewport. Rather than auto-generate the column, we could define a third column like so:

grid-template-columns: min-content 1fr min-content;

This sets up a column on each side of the grid, one for each of the big quotes.  The second column, the one that gets all the actual child elements of the blockquote, receives all the space left over after those outer columns are sized, thanks to its 1fr value.

There’s one more drawback here, albeit one that’s easily overcome.  Grid items’ margins do not collapse.  You can see this effect by checking the “Default margins” option in the demo.  That shows what happens if default paragraph margins are allowed to remain.  We end up with two ems of space between the paragraphs, because each has top and bottom margins of 1em.

In the normal flow, margins collapse to the largest of the adjacent margins, which is why we’re used to 1em of space between adjacent paragraphs.  With grid items, what we see instead is the full element box, margins and all, placed inside the grid cell(s) they occupy.  That means any margin will create space between the edge of the grid cell and the border-edge of the element.  The fix here is straightforward: add a style to reduce margins between elements.  For example, something like:

blockquote > * {
   grid-column: 2;
   margin: 0.5em 0;
}

With a half-em margin above and below each element, any two adjacent elements will have the common 1em separation.  The demo actually has less than that because I wanted to use the print convention of paragraphs with the first lines indented, and a minor separation between paragraphs.  So the actual demo styles are more like this:

blockquote > * {
   grid-column: 2;
   margin: 0.125em 0;
   text-indent: 2.5em;
}
blockquote > *:first-child {
   text-indent: 0;
}

So there you have it: a Grid-powered drop quote.  I should note that all this by itself isn’t quite sufficient: if Grid isn’t supported, it will degrade poorly, as you can verify with the “Disable grid” option.

This is where using @supports() to encapsulate the Grid styling comes in handy.  You can put all of the quote-generation styles into the @supports() block, so that downlevel browsers just don’t get the drop quotes; or, you can set up the drop quotes with floats or positioning and then override those with @supports()-protected Grid styles.  Either one works.

Fortunately, we do have that capability, so it’s fairly easy to progressively enhance your designs with little touches like this one, even if you’re not ready for a full-on Grid plunge.  I’m looking forward to deploying this pattern here on meyerweb, as part of a site design overhaul I’ve been working on for the past couple of weeks.  That’s right: I’m working on my first redesign in a dozen years.  If that doesn’t give you some sense of the power of Grid, well, I just don’t know what will.


There is a followup to this article that explains and corrects an oversight in this article.


Not On This Day

Published 7 years, 3 months past

Suppose you use Facebook (statistically, odds are at least 1 in 5 that you do).  Further, suppose you have a period of your life, or even more than one, that you’d rather not be mined by Facebook’s “On This Day” feature.  Here’s how to set a blackout for any period(s) of time.

  1. Go to facebook.com/onthisday in a web browser while logged into Facebook.  Said browser can be either desktop or mobile.
  2. In a desktop web browser, click the “Preferences” button in the upper right quadrant of the page, to the right edge of the On This Day masthead.  In a mobile web browser, tap the gear icon in the upper right, then tap “Preferences”.
  3. Select the “Dates” line (on desktop, you have to click the “Edit” link on the right).
  4. Now select the “Select Dates” link that looks like a section heading, but is actually a point of interaction.
  5. Select start and end dates, in that order (see below).  On desktop you can type into the boxes or use the popup calendars; on mobile, you get date wheels.
  6. Select “Done” (desktop) or “Add” (mobile).
  7. If you want to add more date ranges to filter out, go back to the “Select Dates” step again and work forward.
  8. Once you’re done, select “Save”.
  9. To finish setting preferences, select “Done”.

…and that’s it, he said dryly.

Should you want to effectively disable On This Day, you can set up a date range of January 1, 1900 to December 31, 2099.  I couldn’t go past 2099 in my testing — according to the error message, anything from 2100 on is an “invalid date”.  I also discovered that setting a start date will always reset the end date to the new start date, so make sure to set your start date first and your end date second.

You might have seen that you can also filter out specific people.  The process there is similar, except you type names to find accounts to filter out instead of using date pickers.

So that’s it.  The preferences aren’t easy to find, but they are there.  I’d be a lot happier if Facebook let you pick a given date and applied it to all years — thus allowing you to block out the birthday of an ex-spouse, or the wedding anniversary of a now-defunct marriage, for example.  I’d be happier still if they surfaced these preferences more readily; say, prompting you with a date-exclusion option whenever you tell them you don’t want to see a given memory in your timeline.  I don’t mind writing how-to guides to help other people, but I do sometimes mind that their existence feels necessary, if you follow me there.


A note for the future: this guide was accurate as of the date of publication.  If you’re reading it some time later, especially if it’s been several months or years, bear in mind that things may have changed in the meantime.  In that case, please feel free to leave a comment indicating there’s been a change, so I can update the guide.  Thanks!


Gradient Flags

Published 8 years, 8 months past

With the news today of the Supreme Court’s decision in Obergefell v. Hodges, and my recent completion of the part of CSS:The Definitive Guide that deals with gradients, I thought I’d create a couple of flags using linear gradients.

First, I’ll define the basic box of the flags.  The dimensions are the same as those specified for the U.S. flag, 1:1.9.  I added a couple of box shadows for visual constrast with the background.

div {height: 10em; width: 19em; margin: 3em;
    box-shadow: 0 0 0.5em rgba(0,0,0,0.25),
        0.4em 0.6em 0.5em rgba(0,0,0,0.25);}

Okay, with that set, first up is what’s often called the pride flag, which is to say the “rainbow flag”.  There’s an interesting history to the design of the flag, but I’m going to stick with “the six-color version popular since 1973”, as Wikipedia puts it.

For such a flag, we just need color stripes with hard stops between them.  That means putting the color stops right up against each other, like so:

div#rainbow {
    background: linear-gradient(180deg,
        red 0%, red 16.7%, 
        orange 16.7%, orange 33.3%,
        yellow 33.3%, yellow 50%, 
        green 50%, green 66.7%, 
        blue 66.7%, blue 83.3%, 
        purple 83.3%, purple 100%);
}

The first red 0% isn’t really necessary, nor is the last purple 100%, but I left them in for the sake of consistency.  You could remove them both in order to make the CSS a little smaller, and still get the same result.  I decided to go from red to purple, as the spectrum is usually described, which meant having the gradient ray point from top to bottom.  Thus 180deg, although to bottom would be completely equal in this case.

Now for the US flag.  In this case, things get a little more interesting.  I’ll note right up front that I’m not going to put in any stars, in order to keep this simple and gradient-focused, and yet it’s still interesting.  We could use a repeating linear gradient, like so:

repeating-linear-gradient(180deg,
    #B22234, #B22234 0.77em, white 0.77em, white 1.54em)

That would then cause each red-white pair of stripes to repeat vertically forever.  Because the specified stripes are manually calculated to be 1/13th of the height of the overall flag (10em), they’ll just fit like they should.

The problem there is that if the overall flag size ever changes, like if the height and weight are converted to pixels, the stripes will get out of sync with the dimensions of the flag.  Fortunately, we don’t have to rely on ems here; we can use percentages.  Thus:

repeating-linear-gradient(180deg,
    #B22234, #B22234 7.7%, white 7.7%, white 15.4%)

Ta-da!  The stripes are the right sizes, and scale with any changes to the height and width of the flag, and repeat as required.

That’s all well and good, but we still need the blue canton (as it’s called).  Since the canton will be on top of the stripes, it actually needs to come first in the comma-separated value list for background-image.  That gives us:

background-image:
    linear-gradient(0deg, #3C3B6E, #3C3B6E),
    repeating-linear-gradient(180deg,
        #B22234, #B22234 7.7%, white 7.7%, white 15.4%);

Wait.  A blue-to-blue gradient?  Well, yes.  I want a consistent blue field, and one way to create that is a gradient that doesn’t actually grade.  It’s a quick way to create a solid-color image that can be sized and positioned however we like.

So, now we size and position the canton.  According to the official design specifications for the flag, the canton is the height of seven stripes, or 53.85% the height of the overall flag, and 40% the width of the flag.  That means a background-size of 40% 53.85%.  The stripes we then have to size at 100% 100%, in order to make sure they cover the entire background area of the flag.  Finally, we position the canton in the top left; the stripes we can position anywhere along the top. so we’ll leave them top left as well.

The final result:

div#usa {
    background-image:
        linear-gradient(0deg, #3C3B6E, #3C3B6E),
        repeating-linear-gradient(180deg,
            #B22234, #B22234 7.7%, white 7.7%, white 15.4%);
    background-size: 40% 53.85%, 100% 100%;
    background-repeat: no-repeat;
    background-position: top left;
}

And if you, like Bryan Fischer, believe that morally speaking “6/26 is our 9/11”, you can move the canton from top left to bottom left in order to invert the flag, which is permitted “as a signal of dire distress in instances of extreme danger to life or property”.

(Of course, it’s a lot easier to do that with background positioning since I didn’t include the stars.  If the stars were there, then we’d have left the canton’s position alone and done a rotateX() transform instead.)

So, there you go: two gradient flags.  You can see both (along with the “distress” variant) on this test page.  If you’ve any desire to use any or all of them, go ahead.  No copyright, trademark, patent, etc., etc. is asserted, implied, etc., etc.  I just wanted to have a little fun with gradients, and thought I’d share.


Touchy About Faucets

Published 11 years, 11 months past

As part of last year’s renovation, we redid our kitchen, which means a new sink and faucet.  We traded up from an overmount single-bowl sink to an undermount double-bowl sink, both aspects of which we’d long wanted.

There was one thing we had to fight a bit to get, though, which was a garbage disposal for each sink bowl.  The plumber didn’t want to do it on ground of it adding weight to the sink.  Our response was, in effect: “We’ll have the sink remounted in ten years if necessary, but put in two disposals.”  So he did, and we’re really glad.

The replacement faucet, however, does not make us nearly as glad.  We decided to get a touch-activated faucet, settling on a Delta Addison single-handle faucet.  The touch activation was because many are the times we want to wash off hands that have just handled raw meat, and being able to touch-on the faucet with a forearm seemed like a great idea — and it is!  The problem is that nearly the entire faucet body, including the temperature/flow adjustment handle, is touch-sensitive.  The exception is the pull-out head, which is inert.

Thus, if you reach past the faucet and brush it by mistake, the water starts flowing.  This is true even if you bump the base of the faucet, which is annoying when you’re trying to wipe down the countertop around the faucet.  Even worse, changing the temperature or flow rate means using the touch-sensitive handle.  There’s evidently logic built into the faucet that’s meant to prevent the water from cutting off if you adjust the handle, but it only works about half the time.  So sometimes you make an adjustment and the flow cuts off, and sometimes it doesn’t.

Frankly, the inconsistency is more maddening than the unwanted cutoffs.  For example, I’ve developed an expectation that the flow will cut off after I use the handle.  So I’ll adjust and then immediately tap the faucet again so it cuts off and then comes back on tap.  Except if it didn’t cut off, then my tap cuts it off before I can stop the impulse and then I have to tap again.

Of course, any touch-sensitive faucet is a total luxury, and fortunately it’s easy to disable the touch feature — all we have to do is pull the batteries from the battery pack and it becomes a regular faucet.  The drawback there is that there are definitely times when you want to be able to turn on the water flow without smearing whatever’s all over your hands on the faucet.  (And with three kids, one of which is an infant, there are some things you definitely want to avoid smearing.)

The really incredible part is that these problems would be completely solved if only the neck of the faucet were touch-sensitive.  If the base, which is a separate part from the neck, and the adjustment handle were inert, easily 90% of our frustration would just vanish.  We could start the water flow by touching the neck and not worry about weirdness with the adjustment handle or when brushing the base.

If you’re thinking of installing a touch-sensitive faucet, I can’t recommend this one, unless of course a future version of it fixes the problems plaguing this one.  And I have no idea if there’s a better touch faucet on the market; for all I know, they’re all like this.  Definitely do your homework, and if at all possible play with a functioning model before taking the plunge.  The touch feature doesn’t add a ton to the price of the base faucet, but it’s enough to be annoying when you’re seriously considering disabling it.


Browse the Archive

Earlier Entries