Posts in the Tech Category

Woodshop SVG: Studs and Shelves

Published 4 years, 11 months past

As I’ve worked on my indoor workspace, I’ve continued to find SVG useful for planning purposes, and putting it to use in my planning has pushed me to learn more about the language.  (That last sentence is actually a play on words, for reasons that I hope will become clear by the end of the post.)

For example, the basement room I’m partially turning into a workspace has a set of exposed framing studs (exposed once I removed a couple of cabinets, anyway) that I wanted to turn into a set of rough shelving, so that I could organize the various bits ‘n’ bobs I accumulate: leftover bolts, extra pullchain, and so on.  These studs are perched on foundation cinderblock, about 48 inches off the floor, and run up to the ceiling from there.

Each stud is 28 inches tall, running from a 2×6 base up to a stacked pair of 2×6 crossbeams.  They also have strips of 2×10 mounted vertically at their bottoms, running between each stud.  (I’m not entirely sure why the 2×10s are there, but I’m not about to start ripping them out now.)

The distances between subsequent studs is also not consistent: they’re mostly close to 16 inches on-center, but not perfectly so, and the last set is only 12 inches apart because the framing ends where a set of stairs begins.  So I created a schematic, including a red box to mark where a 1-gang electrical box. protrudes from the other side of the wall.

The middle stud is taller as a reminder to me that, if not for the crossbeams, it could keep going up past the ceiling joist.  The others are essentially centered on the joists above them (centered within half an inch or so, anyway).

Why does that matter?  Because to make the shelves, I decided to mount 2×6s in front of the framing studs, to allow for shelves 11 inches deep.  So in cases where the studs are centered below ceiling joists, I can run the front-mounted 2×6es up to them.  In that middle case, I’ll actually need a longer 2×6 to run up next to the joist.

This all might sound like a lot of work to deal with odd circumstances, but that was part of the point of this part of the project.  We don’t always get to work in ideal circumstances.  Learning how best to work around the existing limitations is a valuable lesson in itself.

I tried out a lot of different shelf configurations.  At first, I was just using <rect> elements like this.

<rect x="1.5" y="9"    width="14.5" height="0.5" />
<rect x="1.5" y="19.5" width="14.5" height="0.5" />

That’s two shelves, ten inches apart, in the leftmost stud bay.  (The shelves are a half-inch thick.)  That worked okay for a while, but then I decided to show the support rails that would both tie the 2×6s to the studs behind them, and also hold up the shelves.  So that meant more <rect>s, like so.

<rect x="1.5" y="9"    width="14.5" height="0.5" />
<rect x="1.5" y="19.5" width="14.5" height="0.5" />
<rect x="1.5" y="9.5"  width="0.75" height="1.125" />
<rect x="15.25" y="9.5"  width="0.75" height="1.125" />
<rect x="1.5" y="20"  width="0.75" height="1.125" />
<rect x="15.25" y="20"  width="0.75" height="1.125" />

Again, that’s just for the first stud bay: two shelves, and then four supports, two for each shelf.  And I have five bays to do.

Still, it it took deciding to show the storage bins I wanted on the shelves to push to look for a better way.  Basically, what I wanted was a way to define a primitive of a shelf and two support rails, and then just place that.  And then a way to do the same for collections of storage bins, which could be stacked atop each other.

SVG provides for exactly this, through the combination of <defs> and <use>.  I set up a basic shelf set like this:

<defs>
    <g id="shelf">
        <rect x="0" y="0" width="14.5" height="0.5" />
        <rect x="0" y="0.5"  width="0.75" height="1.125" />
        <rect x="13.75" y="0.5"  width="0.75" height="1.125" />
    </g>
</defs>

If you think of that as its own little SVG, it defines a horizontal shelf 14.5 coordinate units wide, and half a unit tall, starting at 0,0.  It then places the two support rails just below, starting half a unit down from the top.

With that in hand, the two shelves I was drawing before collapsed from six lines to two:

<use xlink:href="#shelf" x="1.5" y="9" />
<use xlink:href="#shelf" x="1.5" y="20" />

Suddenly, rather than fiddling with the X,Y coordinates of several pieces just to move a shelf, I could adjust the X,Y of one <use> element.  To say this sped up my workflow would be a monumental understament.  Trying out different shelf spacing and shelf counts went from being a chore to being almost too easy.

This was only magnified when I wrote the definitions for storage-bin primitives.  At first, I drew them the same way I had the shelves, down and right from 0,0, but that was difficult in a number of ways.  Different bin sizes meant I had to do different math to get the bins to sit on the shelves.  And then I remembered that SVG is unbounded on both axes — which meant I could draw the bins up from 0,0, meaning I could give them the same y coordinate as the shelves.

Wait, what?  Let me show you.  Inside <defs>, I wrote:

<g id="bins4">
    <rect x="0" y="-4" width=".15" height="4" />
    <rect x="4" y="-4" width=".15" height="4" />
    <rect x="0" y="-1.5" width="4.15" height="1.5" />
    <rect x="4.2" y="-4" width=".15" height="4" />
    <rect x="8.2" y="-4" width=".15" height="4" />
    <rect x="4.2" y="-1.5" width="4.15" height="1.5" />
    <rect x="8.4"  y="-4" width=".15" height="4" />
    <rect x="12.4" y="-4" width=".15" height="4" />
    <rect x="8.4"  y="-1.5" width="4.15" height="1.5" />
</g>

Everything is drawn starting from above the y=0 line, and reaches down to y=0.  So that first <rect> with height="4" starts at a Y coordinate of -4.  -4 plus 4 equals zero.

That allowed the following:

<use xlink:href="#shelf" x="1.5" y="9" />
<use xlink:href="#bins4" x="2.5" y="9" />
<use xlink:href="#shelf" x="1.5" y="20" />
<use xlink:href="#bins4" x="3.0" y="20" />

See how the y coordinate is the same for both shelf and associated bins?  If I decide to move a shelf up an inch and a half, I just take 1.5 off the y value for the shelf’s <use>, and then use that same value for the y attribute on the bins’ <use>.

Could I have made this even better by combining shelves and bins into a single primitive definition, and only having one <use>?  Yes, if there would only be one set of bins per shelf.  That’s how I dd it in this particular arrangement.  (In this case, the brown vertical studs are actually the 2×6s mounted in front of the wall studs, so they’re taller and based lower.)

However, I also considered stacking bins on each other between shelves, as in this configuration.

That wound up being pretty close to what I did, in the end.

There were a couple of things I wished I could do (or wish I had figured out how to do) in SVG.  The first was a way of varying the width on the <use> elements.  The rightmost stud bay is 12 inches wide, not the 14½ inch bays the others have.  I ended up defining a separate primitive definition for those shelves.

<g id="shelf-sm">
    <rect x="0" y="0" width="12.5" height="0.5" />
    <rect x="0" y="0.5"  width="0.75" height="1.125" />
    <rect x="11.75" y="0.5"  width="0.75" height="1.125" />
</g>

I guess I could have done X-axis scaling transforms on the regular #shelf primitive.  Actually, looking back on it, that probably makes a lot more sense than what I did.  It would have squished the support rails a tiny bit, but not enough to throw off precision cuts or anything.  (There really were no precision cuts in this project — this is carpentry at its roughest.)

The other thing I wanted was the ability to draw “backwards” by giving negative height and width values.  So as an example, I’d have liked to write the rightmost support rail like this:

<rect x="14.5" y="0.5" width="-0.75" height="1.125" />

I know, I know, a negative distance doesn’t really make sense when talking about physical units.  I still wanted to do it.  I mean, it made sense to me in my head.

Just like the idea of hand-authoring SVG to plan out workshop projects made sense to me.  I’m sure I could have done it a little faster and a little more intuitively in a vector editor, but I’d have had to buy one (my copy of Illustrator no longer runs on my Mac, more’s the pity) and if I’d gone that route, I wouldn’t have learned a lot more about SVG and its capabilities.  Either way, the end result is pleasing to me… at least for the time being.


Woodshop SVG

Published 4 years, 11 months past

For the holiday break this year, I decided to finally tackle creating an indoor work space.  I’d had my eye on a corner of our basement storage room for a while, and sketched out various rough plans on graph paper over the past couple of years.  But this time?  This time, I was doing it.

The core goal is to have a workbench where I can do small toy and appliance repair when needed, as well as things like wood assembly after using the garage power tools to produce the parts — somewhere warm in the depths of winter and cool at the height of summer, where glue and finish will always be in its supported temperature range.  But that spawns a whole lot of other things in support of that goal: places to store components like screws, clamps, drills, bits, hammers, saws, wires, and on and on.

Not to mention, many tools are powered, and the corner in question didn’t come with any outlets.  Not even vaguely nearby, unless you count the other side of the room behind a standing freezer.  Which, for the record, I don’t count.  I had to do something about that.

So anyway, a lot of stuff got cleared out of the corner and stored elsewhere, if it wasn’t just tossed outright.  Then I took a couple of cabinets off the wall and remounted one of them elsewhere in the room, which was quite the experience, let me tell you.  When I discovered I’d mis-measured the available space and the cabinet ever so slightly, I had the following conversation with myself:

“This cabinet is an eighth-inch too tall to fit. You’ll never get it in there!”

“Yeah?  Well, me and Mister Block Plane here say different.”

Reader, I got it in there.

Moving the cabinets exposed a short wall of framing studs mounted atop a cinderblock foundation wall.  I’ll get to how I used those in a future piece, but here I want to talk about something I’ve been using to help me visualize parts of this project and get cut lists out of it at the end: hand-written SVG.

You heard me.  I’ve been hand-coding SVG schematics to figure out how thing should go together, and as a by-product, guide me in both material buying and wood cutting.

This might sound hugely bespoke and artisanally overdone, but they’re not that complicated, and as a major benefit, the process has helped me understand SVG a little bit better.  Here’s one example, a top-down diagram of the (supposedly) temporary workbench I recently built out of plywood and kiln-dried framing studs.

That shows a 2’×4′ benchtop with a supporting frame (the overlapping grayish boxes) and the placement of the four legs (the brown rectangles).  Here’s how I wrote the elements to represent the supporting frame.

<g class="structure">
    <path d="M 3.75 3.75  l 40.5 0" /> <!-- back -->
    <path d="M 3.75 12.00 l 40.5 0" class="optional" />
    <path d="M 3.75 20.25 l 40.5 0" /> <!-- front -->

    <path d="M 3.75 3  l 0 18" /> <!-- left -->
    <path d="M 24.00 3.75 l 0 16.5" class="optional" />
    <path d="M 44.25 3 l 0 18" /> <!-- right -->
</g>

And here’s how I styled them.

.structure {
    stroke: #000;
    stroke-width: 0;
    fill: #000;
}
.structure path {
    opacity: 0.1;
    stroke-width: 1.5;
}
.structure .optional {
    opacity: 0.05;
}

I like using paths in this situation because they let me pick a starting coordinate, then draw a line with relative X-Y values.  So that first path starts at X=3.75 and Y=3.75, and then draws a line whose endpoint is 40.5 X-units and 0 Y-units from the starting point.  In other words, it’s 40.5 units long and purely horizontal.  Compare that to the path marked left, which starts nearby (X=3.75, Y=3) and runs 18 units straight down.

This helps with cut planning because I set things up such that each unit equals an inch.  Just by looking at the values in the SVG, I know I need two pieces that are 40.5 inches long, and two that are 18 inches long.  (Three pieces of each length, if I’d decided to use the pieces classed as optional, but I didn’t.)

And how did I get that to work?  I set the viewbox to be only a few coordinate units larger than the overall piece, which I knew would be 24 by 48 units (inches), and then made the image itself large.

<svg xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="1000"
    height="500"
    viewBox="0 0 54 30"
    >

Basically, I added 6 to each of 24 and 48 to get my viewBox values, allowing me three units of “padding” (not CSS padding) on each side.  I filled the whole thing with a rectangle with a soft gray fill, like so.

<rect height="100%" width="100%" fill="#EEE" />

Which was great, but now I had to figure out how to get the 24×48 workplan into the center of the viewbox without having to add three to every coordinate.  I managed that with a simple translation.

<g transform="translate(3,3)">
    <rect width="48" height="24" fill="hsla(42deg,50%,50%,0.5)" />
    …
</g>

And with that, everything inside that g (which is basically the entire diagram) can use coordinates relative to 0,0 without ending up jammed into the top left corner of the image.  For example, that rect, which has no x or y attributes and so defaults both to 0.  It thus runs from 0,0 to 48,24 (as is proper, X comes before Y), but is actually drawn from 3,3 to 51,27 thanks to the transform of the g container.

The drawback to this approach, in my eyes, is that if text is added, it needs a really small font size.  In this particular case, I decided to add a measurement grid to the diagram which is revealed when the SVG is printed.  You can also see it on a mouse-and-keyboard computer if you click through to the SVG and then hover the tabletop.  To all the paths I used to make the grid (and yes, there’s a better way), I added a set of labels like these:

<text x="12" y="0" dx="0.5" dy="-0.5">12</text>
<text x="24" y="0" dx="0.5" dy="-0.5">24</text>
<text x="36" y="0" dx="0.5" dy="-0.5">36</text>
<text x="48" y="0" dx="0.5" dy="-0.5">48</text>

<text x="0" y="0" dx="-0.33" dy="-0.33">0</text>
<text x="0" y="12" dx="-0.5" dy="0.5">12</text>
<text x="0" y="24" dx="-0.5" dy="0.5">24</text>

At my browser’s default of 16px, the text is HUGE, because it gets made 16 units tall.  That’s almost three-quarters the height of the viewbox!  So I ended up styling it to be teensy by any normal measure, just so it would come out contextually appropriate.

.lines text {
    font-size: 1px;
    font-family: Arvo, sans-serif;
    text-anchor: end;
}

Yes.  1px.  I know.  And yet, they’re the right size for their context.  It still grates on me, but it was the answer that worked for this particular context.  You can see the result if you load up the SVG on its own and mouse-hover the benchtop.

The legs I decided to do as rect elements, for no reason I can adequately explain other than I’d started to get a little sick of the way path forced me to figure out where the center of each line had to be in order to make the edges land where I wanted.  path is great if you want a line exactly centered on a unit, like 12.00, but if you want the edge of a board to be three inches from the left edge of the tabletop, it has to start at x="3.75" if the board is 1.5 inches wide.  If the width ever changes, you have to change the x value as well.

For the support frame, which is going to be made entirely out of boards an inch and a half wide, this wasn’t a super big deal, but the math had started to grate a bit.  So, the legs are rects, because I could use the grid I’d drawn to figure out their top left corners, and the height and width were constants.  (I probably could have set those via the CSS, but eh, sometimes it’s better to have your code self-document.)

<g class="legs">
    <rect x="4.5" y="4.5" height="1.5" width="3.5" />
    <rect x="4.5" y="18" height="1.5" width="3.5" />
    <rect x="40" y="4.5" height="1.5" width="3.5" />
    <rect x="40" y="18" height="1.5" width="3.5" />
</g>

Honestly, I probably didn’t even need to include these, but they served as a useful reminder not to forget them when I went to buy the wood.

As I said, simply by glancing at the SVG source, I can see how long the support frame’s pieces need to be — but more to the point, as I adjusted numbers to move them around, I worked their sizes into my head.  What I mean is, I had to visualize them to draw the right lines, and that means I’ve already done some visualization of the assembly.  I just need to remember that each of the four legs will be 34″ long at the most.  Taken all together, I’ll need three 8-foot 2×4 boards (which actually have a cross-section of 1.5″×3.5″ — don’t ask), chopped up and joined appropriately, to go under my 2’×4′ benchtop.

So that’s how I utterly geeked up my workbench project — and if that seems like a bit much, just wait until you see the next thing I did, and what I learned along the way.


CWRU2K

Published 4 years, 11 months past

Before I tell you this story of January 1st, 2000, I need to back things up a few months into mid-1999.  I was working at Case Western Reserve University as a Hypermedia Systems Specialist, which was the closest the university’s job title patterns could get to my actual job which was, no irony or shade, campus Webmaster.  I was in charge of www.cwru.edu and providing support to departments who wanted a Web presence on our server, among many other things.  My fellow Digital Media Services employees provided similar support for other library and university systems.

So in mid-1999, we were deep in the throes of Y2K certification.  The young’uns in the audience won’t remember this, but to avoid loss of data and services when the year rolled from 1999 to 2000, pretty much the entire computer industry was engaged in a deep audit of every computer and program under our care.  There’s really been nothing quite like it, before or since, but the job got done.  In fact, it got done so well, barely anything adverse happened and some misguided people now think it was all a hoax designed to extract hefty consulting fees, instead of the successful global preventative effort it actually was.

As for us, pretty much everything on the Web side was fine.  And then, in the middle of one of our staff meetings about Y2K certification, John Sully said something to the effect of, “Wouldn’t it be funny if the Web server suddenly thought it was 1900 and you had to use a telegraph to connect to it?”

We all laughed and riffed on the concept for a bit and then went back to Serious Work Topics, but the idea stuck in my head.  What would a 1900-era Web site look like?  Technology issues aside, it wasn’t a complete paradox: the ancestor parts of CWRU, the Case Institute of Technology and the Western Reserve University, had long existed by 1900 (founded 1880 and 1826, respectively).  The campus photos would be black and white rather than color, but there would still be photos.  The visual aesthetic might be different, but…

I decided so make it a reality, and CWRU2K was born.  With the help of the staff at University Archives and a flatbed scanner I hauled across campus on a loading dolly, I scanned a couple dozen photos from the period 1897-1900 — basically, all those that were known to be in the public domain, and which depicted the kinds of scenes you might put on a Web site’s home page.

Then I reskinned the home page to look more “old-timey” without completely altering the layout or look.  Instead of university-logo blues and gold, I recolored everything to be wood-grain.  Helvetica was replaced with an “Old West” font in the images, of which there were several, mostly in the form of MM_swapimage-style rollover buttons.  In the process, I actually had to introduce two Y2K bugs to the code we used to generate dates on the page, so that instead of saying 2000 they’d actually say 1899 or 1900.  I altered other things to match the time, like altering the phone number to use two-letters-then-numbers format while still retaining full international dialing information and adding little curlicues to things.  Well before the holidays, everything was ready.

The files were staged, a cron job was set up, and at midnight on January 1st, 2000, the home page seamlessly switched over to its 1900 incarnation.  That’s a static snapshot of the page, so the picture will never change, but I have a gallery of all the pictures that could appear, along with their captions, which I strove to write in that deadpan stating-the-obvious tone the late 19th Century always brings to my mind.  (And take a close look at the team photo of The Rough Riders!)

In hindsight, our mistake was most likely in adding a similarly deadpan note to the home page that read:

Year 2000 Issues

Despite our best efforts at averting Y2K problems, it seems that our Web server now believes that it is January of 1900. Please be advised that we are working diligently on the problem and hope to have it fixed soon.

I say that was a mistake because it was quoted verbatim in stories at Wired and The Washington Post about Y2K glitches.  Where they said we’d actually suffered a real, unintentional Y2K bug, with Wired giving us points for having “guts” in publicly calling “a glitch a glitch”.  After I emailed both reporters to explain the situation and point them to our press release about it, The Washington Post did publish a correction a few days later, buried in a bottom corner of page A16 or something like that.  So far as I know, Wired never acknowledged the error.

CWRU2K lasted a little more than a day.  Although we’d planned to leave it up until the end of January, we were ordered to take it down on January 2nd.  My boss, Ron Ryan, was directed to put a note in my Permanent Record.  The general attitude Ron conveyed to me was along the lines of, “The administration says it’s clever and all, but it’s time to go back to the regular home page.  Next time, we need to ask permission rather than forgiveness.”

What we didn’t know at the time was how close he’d come to being fired.  At Ron’s retirement party last year, the guy who was his boss on January 2nd, 2000, Jim Barker, told Ron that Jim had been summoned that day to a Vice President’s office, read the riot act, and was sent away with instructions to “fire Ron’s ass”.  Fortunately, Jim… didn’t.  And then kept it to himself for almost 20 years.

There were a number of other consequences.  We got a quite a bit of email about it, some in on the joke, others taking it as seriously as Wired.  There’s a particularly lovely note partway down that page from the widow of a Professor Emeritus, and have to admit that I still smile over the props we got from folks on the NANOG mailing list.  I took an offer to join a startup a couple of months later, and while I was probably ready to move on in any case, the CWRU2K episode — or rather, the administration’s reaction to it — helped push me to make the jump.  I was probably being a little juvenile and over-reacting, but I guess you do that when you’re younger.  (And I probably would have left the next year regardless, when I got the offer to join Netscape as a Standards Evangelist.  Actual job title!)

So, that’s the story of how Y2K affected me.  There are some things I probably would have done differently if I had it to do over, but I’m 100% glad we did it.

  • CWRU2K was published on .
  • It was assigned to the History and Web categories.
  • There has been one reply.

Running Code Over Time

Published 4 years, 11 months past

I’m posting this on the last day of 2019.  As I write it, the second post I ever made on meyerweb says it was published “20 years, 6 days ago”.  It was published on the second-to-last day of 1999, which was 20 years and one day ago.

Up top, the date when I wrote this post.  Down below, a five-day error.

What I realized, once the discrepancy was pointed out to me (hat tip: Eric Portis), is the five-day error is there because in the two decades since I posted it, there have been five leap days.  When I wrote the code to construct those relative-time strings, I either didn’t think about leap days, or if I did, I decided a day or two here and there wouldn’t matter all that much.

Which is to say, I failed to think about the consequences of my code running over long periods of time.  Maybe a day or two of error isn’t all that big a deal, in human-friendly relative-time output.  If a post was six years and two days ago but the code says 6 and 1, well, nobody will really care that much even if they notice.  But five days is noticeable, and what’s more, it’s a little human-unfriendly.  It’s noticeable.  It jars.

I think a lot of us tend not to think about running code over long time periods.  I don’t even mean long time periods in “Web years”, though I could — the Web is now just about three decades old, depending on when you reckon the start date.  (Births of the web are like standards — there are so many to choose from!)  I mean human-scale long periods of time, code that is old enough to have been running before your children were born, or maybe even you yourself.  Code that might still be running long after you die, or your children do.

The Web often seems ephemeral.  Trends shift, technologies advance, frameworks flare and fade.  There’s always so much new shiny stuff to try, new things to learn, that it seems like nothing will last.  We say “the Internet never forgets” (even though it does so all the time) but it’s lip service at this point.  And yet, the first Web pages are still online and accessible.

Which means the code that underpins them, from the HTML to the HTTP, is all still running and viable after 30 years.  The foresight that went into those technologies, and the bedrock commitment to consistency over long time frames, is frankly incredible.  It’s inspiring.  Compatibility both forwards and backwards in time, over decades and perhaps eventually centuries, is a remarkable achievement.

As I write this, I have yet to fix my relative-time code.  It’s on my list now, and I plan to get to it soon.  I presume the folks creating Intl.RelativeTimeFormat (hat tip: Amelia Bellamy-Royds) put a lot more thought into their code than I did mine, because they know they’re writing for long time frames.

What I need to do is adopt that same mindset.  I think we all do.  We should think of our code, even our designs, as running for decades, and alter our work to match.  I don’t necessarily know what that means, but we’ll never find out unless we try.


“Flexible Captioned Slanted Images” at 24 ways

Published 5 years past

We have a lot of new layout tools at our disposal these days — flexbox is finally stable and interoperable, and Grid very much the same, with both technologies having well over 90% support coverage. In that light, we might think there’s no place for old tricks like negative margins, but I recently discovered otherwise.

That’s the opening paragraph to my 24ways piece “Flexible Captioned Slanted Images”, which I now realize I should have called “Accessible Flexible Captioned Slanted Images”.  Curse my insufficient title writing!  In just about 2,000 words, I explore a blend of new CSS and old layout tricks to take an accessible markup structure and turn it into the titular slanted images, which are fully flexible across all screen sizes while being non-rectangular.

It’s just my second piece for 24ways, coming a dozen years and a day after the first — and is very possibly my last, as Drew closed out this year by putting 24ways on hiatus.  Fifteen years is a heck of a run for any project, let alone an annual side project, and I salute everyone involved along the way.  Content is hard.  Managing content is harder.  Here’s to everyone who put in the time and energy to make such a valuable resource.  If you’ve never been through the 24 ways archives, now’s your chance.  I promise it will be very much worth your time.


Color Easing Isn’t Always Easy

Published 5 years, 8 months past

A fairly new addition to CSS is the ability to define midpoints between two color stops in a gradient.  You can do this for both linear and radial gradients, but I’m going to stick with linear gradients in this piece, since they’re easier to show and visualize, at least for me.

The way they work is that you can define a spot on the gradient where the color that’s a halfway blend between the two color stops is located.  Take the mix of #00F (blue) with #FFF (white), for example.  The color midway through that blend is #8080FF, a pale-ish blue.  By default, that will land halfway between the two color stops.  So given linear-gradient(90deg, blue 0px, white 200px), you get #8080FF at 100 pixels.  If you use a more generic 90deg, blue, white 100%, then you get #8080FF at the 50% mark.

linear-gradient(90deg, blue, white 100%)

If you set a midpoint, though, the placement of #8080FF is set, and the rest of the gradient is altered to create a smooth progression.  linear-gradient(blue 0px, 150px, white 200px) places the midway color #8080FF at 150 pixels.  From 0 to 150 pixels is a gradient from #F00 to #8080FF, and from 150 pixels to 200 pixels is a gradient from #8080FF to #FFF.  In the following case, #8080FF is placed at the 80% mark; if the gradient is 200 pixels wide, that’s at 160 pixels.  For a 40-em gradient, that midpoint color is placed at 32em.

linear-gradient(90deg, blue, 80%, white 100%)

You might think that’s essentially two linear gradients next to each other, and that’s an understandable assumption.  For one, that’s what used to be the case.  For another, without setting midpoints, you do get linear transitions.  Take a look at the following example.  If you hover over the second gradient, it’ll switch direction from 270deg to 90deg.  Visually, there’s no difference, other than the label change.

linear-gradient(<angle>, blue, white, blue)

That works out because the easing from color stop to color stop is, in this case, linear.  That’s the case here because the easing midpoints are halfway between the color stops — if you leave them out, then they default to 50%.  In other words, linear-gradient(0deg, blue, white, blue) and linear-gradient(0deg, blue, 50%, white, 50%, blue) have the same effect.  This is because the midpoint easing algorithm is based on logarithms, and is designed to yield linear easing for a 50% midpoint.

Still, in the general case, it’s a logarithm algorithm (which I love to say out loud).  If the midpoint is anywhere other than exactly halfway between color stops, there will be non-linear easing.  More to the point, there will be non-linear, asymmetrical easing.  Hover over the second gradient in the following example, where there are midpoints set at 10% and 90%, to switch it from  270deg to 90deg, and you’ll see that it’s only a match when the direction is the same.

linear-gradient(<angle>, blue, 10%, white, 90%, blue)

This logarithmic easing is used because that’s what Photoshop does.  (Not Mosaic, for once!)  Adobe proposed adding non-linear midpoint easing to gradients, and they had an equation on hand that gave linear results in the default case.  It was also what developers would likely need to match if they got handed a Photoshop file with eased gradients in it.  So the Working Group, rather sensibly, went with it.

The downside is that under this easing regime, it’s really hard to create symmetric non-linear line gradients.  It might even be mathematically impossible, though I’m no mathematician.  Regardless, its very nature means you can’t get perfect symmetry.  This stands in contrast to cubic Bézier easing, where it’s easy to make symmetric easings as long as you know which values to swap.  And there are already defined keywords that are symmetric to each other, like ease-in and ease-out.

If you’re up for the work it takes, it’s possible to get some close visual matches to cubic Bézier easing using the logarithmic easing we have now.  With a massive assist from Tab Atkins, who wrote the JavaScript I put to use, I created a couple of CodePens to demonstrate this.  In the first, you can see that linear-gradient(90deg, blue, 66.6%, white) is pretty close to linear-gradient(90deg, blue, ease-in, white).  There’s a divergence around the 20-30% area, but it’s fairly minor.  Setting an interim color stop would probably bring it more in line.  That’s partly how I got a close match to linear-gradient(90deg, blue, ease-out, white), which came out to be linear-gradient(90deg, blue, 23%, #AFAFFF 50%, 68%, white 93%).

Those examples are all one-way, however — not symmetrical.  So I set up a second CodePen where I explored recreations of a few symmetrical non-linear gradients.  The simplest example matches linear-gradient(90deg, blue, ease-in, white, ease-out, blue) with linear-gradient(90deg, blue, 33.3%, white 50%, 61.5%, #5050FF 75%, 84%, blue 93%), and they only get more complex from there.

I should note that I make no claim I’ve found the best possible matches in my experiments.  There are probably more accurate reproductions possible, and there are probably algorithms to work out what they would be.  Instead,  I did what most authors would do, were they motivated to do this at all: I set some stops and manually tweaked midpoints until I got a close match.  My basic goal was to minimize the number of stops and midpoints, because doing so meant less work for me.

So, okay, we can recreate cubic Bézier easing with logarithmic midpoints.  Still, wouldn’t it be cool to just allow color easing using cubic Béziers?  That’s what Issue #1332 in the CSS Working Group’s Editor Drafts repository requests.  From the initial request, the idea has been debated and refined so that most of the participants seem happy with a syntax like linear-gradient(red, ease-in-out, blue).

The thing is, it’s generally not enough to have an accepted syntax — the Working Group, and more specifically browser implementors, want to see use cases.  When resources are finite, requests get prioritized.  Solving actual problems that authors face always wins over doing an arguably cool thing nobody really needs.  Which is this?  I don’t know, and neither does the Working Group.

So: if you have use cases where cubic Bézier easing for gradient color stops would make your life easier, whether it’s for drop shadows or image overlays or something I could never think of because I haven’t faced it, please add them to the GitHub issue!


Color Me FACE1E55

Published 5 years, 8 months past

There’s a long history in computer programming of using hexadecimal strings that look like English words to flag errors.  These are referred to, amusingly, as “magic debug values”, and yes, Wikipedia has the lowdown.  One of the most (in)famous is DEADBEEF, which was used “on IBM systems such as the RS/6000, also used in the classic Mac OS operating systems, OPENSTEP Enterprise, and the Commodore Amiga”, among others.  It’s also become the name of a Gnu/Linux music player, and apparently does not have anything to do with Cult of the Dead Cow, at least not so far as I could determine.  Maybe someone with more knowledge can drop a comment.

Anyway, one of the things about these magic debug values is they’re usually eight characters long.  Not always, as in the case of BADC0FFEE0DDF00D (from RS/6000, again), but usually.  Nintendo used 0D15EA5E in the GameCube and Wii to indicate a normal boot (!), iOS logs DEAD10CC when an application terminates in a specific yet incorrect manner, and FEEDFACE shows up in PowerPC Mach-O binaries , as well as the VLC Player application.  Just to pick a few examples.

The eight-character nature of these magic codes has meant that, for a long time, you couldn’t also use them on the sly to define colors in CSS, because it was limited to the #RRGGBB format.  Well, those days are over.  Long over.  Eight-digit hex color values are here, have been here a while, and are widely supported.  Here are a few swatches laid over a (fully opaque) white-to-black gradient.

#abadcafe
#baaaaaaa
#deadbeef
#deadfeed
#defec8ed
#feedbacc

If you’re using Internet Explorer or Edge, those aren’t going to work for you.  At least, not until Edge switches over to Blink; then, they should work just fine.

Thanks to the way they were constructed, by only using the letters A-F, most of the colors above are mostly opaque.  The last two digits in #RRGGBBAA set the alpha channel level of the color, just like the last part of the rgba() syntax.  Thus, the EF at the end of DEADBEEF sets the alpha value to 0.937; EF is equivalent to decimal 239, and 239 ÷ 255 = 0.937 (approximately).  In other words, #DEADBEEF is essentially equivalent to rgba(222,173,190,0.937).

That’s why, of the six swatches, only the sheepish #baaaaaaa and the homophonic #feedbacc let the background gradient show through more than very slightly; their alpha channels are 0.666 and 0.8, respectively.  The rest are 0.929 and up.

Being stuck in the A-F range is fairly constraining, but that’s where hexadecimal and English overlap, so that’s how it goes.  However, if you’re willing to turn to leetspeak syntax — that is, allowing yourself to use 0 as a substitute for O, 1 for L and occasionally I, 5 for S, 7 for T, and so on — then a lot more possibilities open up.  In addition to some of the classic error codes like fee1dead (Linux), I had fun devising other eight-character color words like acc0lade and face1e55, not to mention the very nautical ccccccc5.  (Think about it.)  Behold!

#0ff1c1a1
#1337c0de
#5e1f1e55
#a114c0de
#acc01ade
#ba5e1e55
#bada55e5
#bebada55
#beefc0de
#b0bafe77
#b0a710ad
#c010ca7e
#c0de1e55
#ccccccc5
#d0d0c0de
#dabbad00
#dead10ad
#deadd0d0
#decea5ed
#face1e55
#fee1dead

There are still more l33t-compliant number substitutions available, like 6 for G, but I felt like I was already pushing it with the examples I have.  One could also use calculator spelling, where 9 is a stand-in for g, and even mix together l33t and calculator syntaxes in the same value.  So many possibilities!

You may have noticed one value which creates no color: #DABBAD00, which has 00 for its alpha, so it’s fully, completely transparent.  It’s fully transparent #DABBAD, I suppose, but there’s really no difference between one transparent color and another, as far as I’m concerned.  I mean, if a color falls transparent, then there’s nobody to see it, so is it really a color at all?  I say thee nay.

If you’re familiar with the way #RRGGBB hex values can be represented with the shortened #RGB syntax, then it will probably come as little surprise that #RRGGBBAA has a shortened #RGBA syntax, where each digit is duplicated.  This opens the world of four-letter words to us!  Here are a few:

#10ad
#1337
#b007
#ba5e
#bead
#beef
#c0de
#cafe
#cede
#dada
#dead
#deed
#f00d
#fade
#f8ed
#feed
#0b0e

Here, we finally have a fully opaque word-color: #BEEF expands out to #BBEEEEFF, making the alpha value FF, which decimal-translates to 255, which is fully opaque.  So we get a nice opaque powdery blue out of BEEF, which is counterintuitive in the best possible way.  Also, every time I see BBEEEEFF, either in print or in my head, I hear Mrs. Which ordering dinner.

And okay, yes, #F8ED isn’t a four-letter word, it’s a four-symbol license-plate word.  So it’s even cooler.

If you’re thinking about using these in your CSS, you might be concerned about backwards compatibility, since any browser that doesn’t understand four- or eight-digit hexadecimal color values will just drop them on the floor.  That might be okay for text coloring, since the text will likely have some color, even if it’s browser-default, which is usually black.  For backgrounds, having colors ignored probably less okay, particularly if you set foreground colors that depend on the background colors.

There are a couple of possibilities here.  One is to use the cascade and CSS error handling to your advantage, in the time-honored pattern of doing the simpler version first and the more sophisticated version second.

#example {
   color: #DEA;
   color: #DEAD;
}

That works in simple scenarios, but for more complicated situations — say, ones where you have foreground and background depending on each other — feature queries are an option to consider, if for no other reason than cleaner organization and legibility.

#example {
   color: red;
   background: #EEE;
}

@supports (color: #ABCD) {
   #example {
      color: #f00d;
      background: #feed;
   }
}

Naturally and as usual, you’ll have to figure out what makes the most sense for your situation.  Maybe the right answer will be to avoid using these sorts of values at all, although I don’t know where the fun is in that.

At any rate, I hope you’ve enjoyed this little tour of magic debug values, l33tspeak, and color words.  As always, #feedbacc is more than welcome in the comments!


CSS4 Color Keyword Distribution Visualization

Published 5 years, 8 months past

Long, long ago — not quite seven years ago, in fact — I built a canvas-based visualization of the distribution of CSS3/SVG color keywords and released it.  And there it’s sat, static and inert (despite being drawn with a whooooole lotta JS) ever since.

I’ve always meant to get back to it and make it more interactive.  So over the past several evenings, I’ve rebuilt it as an SVG-based visualization.  The main point of doing this was so that when you hover the mouse pointer over one of the little color boxes, it will fill the center of the color wheel with the hovered color and tell you its name and HSL values.  Which it does, now.  It even tries to guess whether the text should be white or black, in order to contrast with the underlying color.  Current success rate on that is about 90%, I think.  Calculating perceived visual brightness turns out to be pretty hard!

Other things I either discovered, or want to do better in the future:

  • Very nearly half the CSS4 (and also CSS3/SVG) color keywords are in the first 90 degrees of hue.  More than half are in the first 120 degrees.
  • There are a lot of light/medium/dark variant names in the green and blue areas of the color space.
  • I wish I could make the color swatches bigger, but when I do that the adjacent swatches overlap each other and one of them gets obscured.
  • Therefore, being able to zoom in on parts of the visualization is high on my priority list.  All I need is a bit of event monitoring and some viewbox manipulation.  Well, that and a bit more time. Done, at least for mouse scroll wheels.
  • I’d like to add a feature at some point where you type text, and a list is dynamically filtered to show keywords containing what you typed.  And each such keyword has a line connecting it to the actual color swatch in the visualization.  I have some ideas for how to make that work.
  • I’d love to create a visualization that placed the color swatches in a 3D cylindrical space summarizing hue, lightness. and saturation.  Not this week, though.
  • I’m almost certain it needs accessibility work, which is also high on my priority list.
  • SVG needs conic gradients.  Or the ability to wrap a linear gradient along/inside/around a shape like a circle, that would work too.  Having to build a conic gradient out of 360 individual <path>s is faintly ridiculous, even if you can automate it with JS.
  • And also z-index awareness.  C’mon, SVG, get it together.

Anyway, here it is: CSS4 Color Keyword Distribution.  I hope you  like it!


Browse the Archive

Earlier Entries

Later Entries