meyerweb.com

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

Archive: 'Tech' Category

Gradient Repetition

Yesterday, I shared a test of repeating linear gradients and the madness they embody in various browsers.  There were some suggestions for fixes both on the intertubes as well as the comments section of the post, so I should take a moment to explore the reasons for my post and test, and also what I would consider to be stable alternatives to the patterns I was creating.

Primarily the test was to find out how browsers handle repeating-linear-gradient().  Badly, as it turns out, at least for many of them.  Chrome is the worst; far worse than Safari, which I found fascinating.  So I wasn’t actually posting in search of a way around those problems, though in re-reading the post I can see where that impression might have developed.  I was actually running an experiment where my starting hypothesis was that repeating gradients were safe to use.  This was proven to be false.  (Science!)  Having found out that there are glitches and inconsistencies that are sensitive to element size, and seeing how wildly, almost hilariously wrong some engines have gotten this, I came to the conclusion that repeating-linear-gradient() isn’t yet ready for use.

That’s okay.  Not everything in CSS is ready for use.  Almost everything in CSS wasn’t ready for use, once upon a time.  I think color is the one property that was probably stable from the outset, and even that had its quirks in Netscape 4, albeit in the handling of unknown values.  (color: inherit resulted in a shade we lovingly referred to as “monkey-vomit green”.)

Now, as for useful alternatives to repeating-linear-gradient(): the most obvious (as in traditional, as in boring) method is to create a PNG or other pixel image and use the various background-related properties.  For example, given a desire to have a 5-on-5-off pattern (as seen in test #5), you could create a 10×10 PNG and then tile it something like this:

background-image: url(5on5off.png);
background-repeat: repeat-x;
background-position: bottom center;
background-size: 10px 10px;

The advantages here are that A) pixel images are about as safe as you get; and B) if you want to stretch the image vertically, you can do so without having to produce a new image.

A second alternative, only fractionally less safe but rather more efficient, is to replace the external PNG with a regular non-repeating linear gradient.  I much prefer this to the suggestion of sizing and tiling a repeating gradient, because the test shows we can’t have any confidence in consistency with repeating gradients right now.  (This is particularly true in Chrome, which is the worst with small repeated gradients.)  Plain old non-repeating linear gradients, on the other hand, are predictable once you get the syntax right.  Thus:

background-image: linear-gradient(left,
	rgba(255,0,0,0.5) 0px,
	rgba(255,0,0,0.5) 5px,
	rgba(255,0,0,0) 5px,
	rgba(255,0,0,0) 10px);
background-repeat: repeat-x;
background-position: bottom center;
background-size: 10px 10px;

…with, of course, the various vendor-prefixed versions of that first declaration blatted out by your favorite CSS preprocessor, framework, JavaScript shim, brain and fingers, or other tool of choice.  The repeating pattern here is handled by the background-repeat declaration instead of relying on repeating-linear-gradient() to do it for you.  It’s exactly the same as the first alternative except the pixel image has been replaced with a textually-described image.

So why do browsers not just do that internally?  Well, I really don’t know, though it’s quite probable that performance plays an important role.  For repetitions along the primary axes, they could certainly do it very easily.  But the big advantage of repeating-linear-gradient(), and the place where both alternatives can fall flat on their faces unless you are very careful, is in creating repeating patterns that don’t march on one of the primary axes.  Repeating a static linear gradient along the X axis is fine as long as it’s perfectly perpendicular to the X axis, but what happens when you want to repeat a pattern that’s tilted 30 degrees?

Yes, this sort of effect can certainly be worked out by hand or tool—after all, we’ve seen those kinds of patterns done with GIFs and PNGs and the like for decades now—but it’s a lot harder to do.  It’s still what I’d recommend right now, because having a reliably repeated background is usually far better than one whose rendering you can’t predict.

The goal of repeating-linear-gradient() was to make it easy to specify a repeating pattern at any angle and not have to worry about the minutiae.  Unfortunately, until rendering engines actually start properly handling the minutiae, we need to do it by hand if we do it at all.

Repeating Linear Madness

My detailed studies of CSS3 have, of late, taken me into the realm of repeating linear gradients.  I’m not going to attempt a Lovecraft parody for this post, though I seriously considered it.  Instead, I’m going to give you a summary of where we stand with repeating linear gradients, followed by some details.

The summary is as follows: NOT READY FOR PRIME TIME.  In fact, not even ready for safe harbor in Europe.  Whether they will become ready for use is up to the various browser makers.

I came to this conclusion after creating and evolving a test case for pattern regularity.  The test compares a repeated PNG (red) with two theoretically equivalent repeating-linear-gradient images (blue and blue).  The two repeating linear gradients are expressed differently, but should yield the same result.  The visual result of the test should be a perfect interleaving where the blue and red patterns overlap.

To see what I mean, load up the test in Opera; or take a look at this screenshot of the first eight cases, taken in Opera.  Either one will show you the reference rendering for this test case.  Regular repetition and seamless interleaving, no matter what you do with the browser window’s size.  That was and is the intended result.

If you want to go all the way to the other end of the spectrum, load up the same test in Chrome or Canary.  It will be…different, at least in my testing on OS X and Windows.  For extra fun, try dragging the browser window to resize.  AHHHHGGGH.

In Firefox 12/Aurora 14 and Safari 5.1.7, all on OS X, I see something very close to Opera, except there are little one-pixel missteps here and there.  Even better, the positions of these missteps will be different between the two gradient patterns; that is, for a given test the missteps on the top test will almost certainly be different than those on the bottom—assuming there are any at all.  And all that was about as vague as can be because the missteps depend on the width of the element; again, try drag-resizing the browser window.  Crawling artifacts!

I’m sorry, I promised no Lovecraft.

I’ve been told that Firefox 12 for Windows is rock-steady and Opera-regular, but I haven’t yet been able to verify that.  I also haven’t tried out IE10 to see where, if anywhere, they stand with this.  I imagine every build of every Linux browser ever has this nailed 100%, because that’s all Linux users say every time I launch one of these tests.  Go you!

The point of all this being, as if I needed to restate it: don’t depend on repeating-linear-gradient for much of anything right now.  There is pretty clearly a metric massload of work to be done before we can start calling these safe to use.

A Precise CSS3 Color Table

In the course of expanding my documentation of color values, I failed to find a table that listed all 147 SVG-and-CSS3-defined keywords along with the equivalent RGB decimal, RGB percent, HSL, hexadecimal, and (when valid) short-hex values.  There were some tables that listed some but not all of those value types, and one that listed all the value types (plus CMYK) along with a few hundred other keywords, but none that listed all of the CSS keywords and value types.  And none that I saw used precise values for the RGB percent and HSL types, preferring instead to round off at the expense of some subtle differences in color.

So I created my own table, which you can now find in the CSS area of meyerweb.  Most of it is dynamically generated, taking a list of keywords and RGB decimal equivalents and then calculating the rest of the values from there.  The presentation is still a work in progress, and may change a little or a lot.  In particular, if I can’t find a better algorithm for determining which rows should have white text instead of black, I’ll probably shift away from the full-row background colors to some other presentation.  (Update: it’s been greatly improved, so I’m sticking with the full-row backgrounds.  For now, anyway.)

My thanks to Tab Atkins for his donation of the RGB-to-HSL routine I adapted as well as help improving the pick-light-or-dark-text algorithm; and to the people who responded positively on Twitter when I mused about the idea there.

Update 25 May 12: the table now allows sorting (both directions) on the Keyword, RGB Decimal, and HSL columns.  The sorting and styling code uses methods like el.classList.remove() so it may not function well, or at all, in older versions of Internet Explorer.  The numeric sorts also appear to be borked in Opera and Chrome for no reason I can discern, and it’s not like I did anything fancy in the JavaScript—exactly the opposite, I’d wager.  (Speaking of which, I’m sure my JavaScript is an non-stop amateur-hour horrorshow.  I’m okay with that.  If you aren’t, you might want to avert your gaze.)  If there’s a simple fix that doesn’t screw up other browsers, like Safari and Firefox, I’m interested.  If not, then we’ll all just have to live with it.

Update II 25 May 12: thanks to the folks who responded to my question over at StackOverflow as well as on Twitter, the sorting is now stable across browsers.  Bonus: I feel like thanks to everything I’ve learned along the way, the JavaScript in general is getting halfway to decent.  Go me.

As always: share and enjoy!

Backgrounds, Shadows, Fonts, and the Cascade

The fact that this:

h1 {color: red;}
h1 {color: green;}

…results in green h1 text, but this:

h1 {background:
	url(red-wave.gif) repeat,
	url(green-wave.gif) repeat;}

…results in a red wavy h1 background does my head in every single time.  And it’s the same with text and box shadows, too!  In cases where backgrounds or shadows overlap, the first one you write “wins”, by virtue of being “in front of” the background images that are listed after it.

I know that font stacks are also done in order of most-to-least preferred, but I don’t see them as being equivalent.  The reason is that a font stack is a list of fallbacks—use this face unless it can’t render the glyph or doesn’t exist, in which case try the next one in the list, etc., etc.  Multiple background images and multiple shadows, on the other hand, are not a series of fallbacks.  I expect to see them all, unless I made a mistake of some kind; and I do, constantly, because of this disconnect.  Sure, one could use the multiple background image syntax to create a series of fallbacks—first an SVG file, second a PNG, third a GIF—but that’s not its primary purpose, and I certainly wouldn’t teach multiple background images that way.  That’s not what they’re designed to do.

Maybe writing the problem down here will purge this daemon, but in all honesty, my hopes are not terribly high.

Defining ‘ch’

I’m working my way through a rewrite of Two Salmon (more on that anon), and I just recently came to the ch unit.  Its definition in the latest CSS Values and Units module is as follows:

ch unit

Equal to the advance measure of the “0″ (ZERO, U+0030) glyph found in the font used to render it.

…and that’s it.  I had never heard the term “advance measure” before, and a bit of Googling for font "advance measure" only led me to copies of the CSS Values and Units module and some configuration files for the Panda 3D game engine.  So I asked the editor and it turns out that “advance measure” is a CSS-ism that corresponds to the term “advance width”, which I had also never heard before but which yielded way more Google results.  Wikipedia’s entry for “Font” has this definition:

Glyph-level metrics include … the advance width (the proper distance between the glyph’s initial pen position and the next glyph’s initial pen position)…

My question for the font geeks in the room is this:  is that the generally accepted definition for “advance width”?  If not, is there a better definition out there; and if so, where?  I’d like to be able to recommend the best known definition for inclusion in the specification; or, if there’s no agreement as to the best, then at least a good one.  The Wikipedia definition certainly sounds good, assuming it’s accurate.  Is it?

In CSS terms, if I’ve understood things correctly, 1ch is equal to the width of the character box for the glyph for “0”.  In other words, if I were to create a floated element with just a “0” and no whitespace between it and the element’s open and close tags, then the float’s width would be precisely 1ch.  But that’s if I’ve understood things correctly.  If I haven’t, I hope I’ll be corrected soon!

Vendor Tokens

It may be that from the ashes of vendor prefixes will arise a new way forward.  As proposed by François Remy, vendor tokens would serve the same basic purpose as prefixes with a different syntactical approach, and with at east a couple of extra benefits.  Instead of prefixing properties, you’d instead add vendor tokens to the end of a single declaration, much as you do !important (which of course we never ever use, amirite?).

For example, you might write:

border-radius: 1em !webkit-draft !moz-draft !o-draft;

That’s it.  The prefixed alternative, of course, runs to multiple lines and has spawned a whole subindustry of framework plugins and mixins and what-all just to take the repetitive authoring burden off our shoulders.

I’ve been contemplating this proposal all morning, and perhaps not too surprisingly I’ve come down in favor of the idea.  I’m on record as being a fan of vendor prefixes, but what I was truly a fan of was the capabilities they offer.  The syntax was never a core interest for me, and the ugliness was pretty apparent.  Vendor tokens are less tortuous, and even make it much simpler to build in versioning, like so:

border-radius: 1em !webkit-draft-2 !moz-draft !o-draft;

Not that I’m saying this proposal will or even should get to that point, but the ability is there and it feels cleaner than trying to do the same thing with prefixes.  I feel they ought to drop the -draft part of the tokens; just saying !webkit !moz !o or possibly !x-webkit !x-moz !x-o should be sufficient.  I’m also not a fan of the bang, but then I never have been, and I figure any token marker would suffice.  As before, it’s not the syntax I care about so much as the capabilities.

There is a discussion ongoing at www-style, if you’re interested in adding your perspective or even just following along as various stakeholders thrash at the idea.  I’m cautiously optimistic.  It’s kind of a nice feeling!

Linear Gradient Keywords

Linear gradients in CSS can lead to all kinds of wacky, wacky results—some of them, it sometimes seems, in the syntax itself.

Let me note right up front that some of what I’m talking about here isn’t widely deployed yet, nor for that matter even truly set in stone.  Close, maybe, but there could still be changes.  Even if nothing actually does change, this isn’t a “news you can use RIGHT NOW” article.  Like so much of what I produce, it’s more of a stroll through a small corner of CSS, just to see what we might see.

For all their apparent complexity, linear gradients are pretty simple.  You define a direction along which the gradient progresses, and then list as many color stops as you like.  In doing so, you describe an image with text, sort of like SVG does.  That’s an important point to keep in mind:  a linear (or radial) gradient is an image, just as much as any GIF or PNG.  That means, among other things, that you can mix raster images and gradient images in the background of an element using the multiple background syntax.

But back to gradients.  Here’s a very simple gradient image:

linear-gradient(45deg, red, blue)

The 45deg defines the gradient line, which is the line that defines how the gradient progresses.  The gradient line always passes through the center of the background area, and its specific direction is declared by you, the author.  In this case, it’s been declared to point toward the 45-degree angle.  red and blue are the color stops.  Since the colors don’t have stop distances defined, the distances are assumed to be 0% and 100%, respectively, which means you get a gradient blend from red to blue that progresses along the gradient line.

You can create hard stops, too:

linear-gradient(45deg, green 50%, lightblue 50%)
Figure 1

That gets you the result shown in Figure 1, to which I’ve added (in Photoshop) an arrow showing the direction of the gradient line, as well as the centerpoint of the background area.  Each individual “stripe” in the gradient is perpendicular to the gradient line; that’s why the boundary between the two colors at the 50% point is perpendicular to the gradient line.  This perpendicularness is always the case.

Now, degrees are cool and all (and they’ll be changing from math angles to compass angles in order to harmonize with animations, but that’s a subject for another time), but you can also use directional keywords.  Two different kinds, as it happens.

The first way to use keywords is to just declare a direction, mixing and matching from the terms top, bottom, right, and left.  The funky part is that in this case, you’re declaring the direction the gradient line comes from, not that toward which it’s going; that is, you specify its origin instead of its destination.  So if you want your gradient to progress from the bottom left corner to the top right corner, you actually say bottom left:

linear-gradient(bottom left, green 50%, lightblue 50%)
Figure 2

But bottom left does not equal 45deg, unless the background area is exactly square.  If the area is not square, then the gradient line goes from one corner to another, with the boundary lines perpendicular to that, as shown in Figure 2.  Again, I added a gradient line and centerpoint in Photoshop for clarity.

Of course, this means that if the background area resizes in either direction, then the angle of the gradient line will also change.  Make the element taller or more narrow, and the line will rotate counter-clockwise (UK: anti-clockwise); go shorter or wider and it will rotate clockwise (UK: clockwise).  This might well be exactly what you want.  It’s certainly different than an degree angle value, which will never rotate due to changes in the background’s size.

The second way to use keywords looks similar, but has quite different results.  You use the same top/bottom/left/right terms, but in addition you prepend the to keyword, like so:

linear-gradient(to top right, green 50%, lightblue 50%)
Figure 3

In this case, it’s clear that you’re declaring the gradient line’s destination and not its origin; after all, you’re saying to top right.  However, when you do it this way, you are not specifying the top right corner of the background area.  You’re specifying a general topward-and-rightward direction.  You can see the result of the previous sample in Figure 3; once more, Photoshop was used to add the gradient line.

Notice the hard-stop boundary line.  It’s actually stretching from top left to bottom right (neither of which is top right).  That’s because with the to keyword in front, you’re triggering what’s been referred to as “magic corners” behavior.  When you do this, no matter how the background area is (re)sized, that boundary line will always stretch from top left to bottom right.  Those are the magic corners.  The gradient line thus doesn’t point into the top right corner, unless the background area is perfectly square—it points into the top right quadrant (quarter) of the background area.  Apparently the term “magic quadrants” was not considered better than “magic corners”.

The effect of changing the background area’s size is the same as before; decreasing the height or increasing the width of the background area will deflect the gradient line clockwise, and the opposite change to either axis will produce the opposite deflection.  The only difference is the starting condition.

Beyond all this, if you want to use keywords that always point toward a corner, as in Figure 2 except specifying the destination instead of the origin, that doesn’t appear to be an option.  Similarly, neither can you declare an origin quadrant.  Having the gradient line always traverse from corner to corner means declaring the origin of the gradient line (Figure 2).  If you want the “magic corners” effect where the 50% color-stop line points from corner to corner, with the gradient line’s destination flexible, then you declare a destination quadrant (Figure 3).

As for actual support:  as of this writing, only Firefox and Opera support “magic corners”.  All current browsers—in Explorer’s case, that means IE10—support angles and non-magic keywords, which means Opera and Firefox support both keyword behaviors.  Nobody has yet switched from math angles to compass angles.  (I used 45deg very intentionally, as it’s the same direction in either system.)

That’s the state of things with linear gradients right now.  I’m interested to know what you think of the various keyword patterns and behaviors—I know I had some initial trouble grasping them, and having rather different effects for the two patterns seems like it will be confusing.  What say you?

Firefox Failing localStorage Due to Cookie Policy

I recently stumbled over a subtle interaction between cookie policies and localStorage in Firefox.  Herewith, I document it for anyone who might run into the same problem (all four of you) as well as for you JS developers who are using, or thinking about using, locally stored data.  Also, there’s a Bugzilla report, so either it’ll get fixed and then this won’t be a problem or else it will get resolved WONTFIX and I’ll have to figure out what to do next.

The basic problem is, every newfangled “try code out for yourself” site I hit is just failing in Firefox 11 and 12.  Dabblet, for example, just returns a big blank page with the toolbar across the top, and none of the top-right buttons work except for the Help (“?”) button.  And I write all that in the present tense because the problem still exists as I write this.

What’s happening is that any attempt to access localStorage, whether writing or reading, returns a security error.  Here’s an anonymized example from Firefox’s error console:

Error: uncaught exception: [Exception... "Security error"  code: "1000" nsresult: "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR)"  location: "http://example.com/code.js Line: 666"]

When you go to line 666, you discover it refers to localStorage.  Usually it’s a write attempt, but reading gets you the same error.

But here’s the thing: it only does this if your browser preferences are set so that, when it comes to accepting cookies, the “Keep until:” option is set to “ask me every time”.  If you change that to either of the other two options, then localStorage can be written and read without incident.  No security errors.  Switch it back to “ask me every time”, and the security errors come back.

Just to cover all the bases regarding my configuration:

  1. Firefox is not in Private Browsing mode.
  2. dom.storage.default_quota is 5120.
  3. dom.storage.enabled is true.

Also:  yes, I have my cookie policy set that way on purpose.  It might not work for you, but it definitely works for me.  “Just change your cookie policy” is the new “use a different browser” (which is the new “get a better OS”) and it ain’t gonna fly here.

To my way of thinking, this behavior doesn’t conform to step one of 4.3 The localStorage attribute, which states:

The user agent may throw a SecurityError exception instead of returning a Storage object if the request violates a policy decision (e.g. if the user agent is configured to not allow the page to persist data).

I haven’t configured anything to not persist data—quite the opposite—and my policy decision is not to refuse cookies, it’s to ask me about expiration times so I can decide how I want a given cookie handled.  It seems to me that, given my current preferences, Firefox ought to ask me if I want to accept local storage of data whenever a script tries to write to localStorage.  If that’s somehow impossible, then there should at least be a global preference for how I want to handle localStorage actions.

Of course, that’s all true only if localStorage data has expiration times.  If it doesn’t, then I’ve already said I’ll accept cookies, even from third-party sites.  I just want a say on their expiration times (or, if I choose, to deny the cookie through the dialog box; it’s an option).  I’m not entirely clear on this, so if someone can point to hard information on whether localStorage does or doesn’t time out, that would be fantastic.  I did see:

User agents should expire data from the local storage areas only for security reasons or when requested to do so by the user.

…from the same section, which to me sounds like localStorage doesn’t have expiration times, but maybe there’s another bit I haven’t seen that casts a new light on things.  As always, tender application of the Clue-by-Four of Enlightenment is welcome.

Okay, so the point of all this: if you’re getting localStorage failures in Firefox, check your cookies expiration policy.  If that’s the problem, then at least you know how to fix it—or, as in my case, why you’ll continue to have localStorage problems for the next little while.  Furthermore, if you’re writing JS that interacts with localStorage or a similar local-data technology, please make sure you’re looking for security exceptions and other errors, and planning appropriate fallbacks.

April 2014
SMTWTFS
March  
 12345
6789101112
13141516171819
20212223242526
27282930  

Archives

Feeds

Extras