To Comma-Separate, or Not to Comma-Separate, That is The Question

An interesting debate popped up on the weekly CSS Working Group phone call yesterday, and I’m sitting here eating lunch, still thinking about it.

So I want to know what you think — you people who write CSS all the time, who care, who will be living with the results of this decision.

So here’s the deal.

The oldest values you can use to specify a color look like this: #eee or #fefefe or red. More recently we gained RGB and HSL. They look like this:

color: rgba(255, 255, 255, 0.5);
color: hsl(240, 100%, 50%);
background-color: rgba(108, 210, 136, 0.65);
border: 1px solid color: rgb(0, 0, 0);

Note the commas that separate the values.

There’s a new property coming in the world of color, it’s called color(). There is a proposal to make it look like this:

background-color: color(0.1 0.2 0.3 50%);

Note the lack of commas.

Meanwhile, there are other properties in CSS where a list of values specifies something, and they may or may not have commas.

Here are a few examples:

margin: 0 2em;
padding: 1em 2em 0.5em;
border: 1px solid #000;
grid-template-rows: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: repeat(8, 15vw);
grid-template-columns: repeat(5, 1fr 1.2fr 1.2fr 0.5fr);
shape-outside: circle(at 50% 50%);
clip-path: polygon(0% 0%, 100% 3%, 98% 99%, 3% 93%);
color: rgba(255, 255, 255, 0.6);
color: hsl(240, 100%, 50%);

There are people in the CSS Working Group who want to get rid of the commas in the new color function, because to them, it feels more consistent with the rest of CSS. They know it’s inconsistent with the other color values, but think those other color values are dumb — and never should have been created with commas. They want to fix that now by making the new thing not have commas.

Then there are other people who think it will be very confusing to have some color values use commas (like rgb() and hsl()) while the new color() function doesn’t. Like many things in CSS, perhaps we would do it differently if we were starting from scratch now, but once something is shipped, we need to stick to it. Values for specifying colors have commas, the new one should be the same.

Some folks are proposing that the new function not have commas, while the old functions (rgb and hsl) get new rules — where you could use commas (which we have to do to support older websites) but you could instead “switch” and no longer use commas. You’d be required to be comma-less for color(), while using commas or not — your choice — for rgb() and hsl().

Some folks think, ok, this comma-optional idea has merit. Let’s make this so the people who don’t want to use commas can write new code across all our color functions (color, rgb, rgba, hsl, hsla) without commas. But let’s also allow commas in the new color() function so that people who are used to commas don’t have to change their practice, and they can do what they would expect, and use commas in the new thing. Basically, make commas optional everywhere.

Then there are people who think, OMG, we are going to make this overly complex and crazy-making by allowing commas but not requiring them. Let’s just keep things simple. We’ve already started out with commas in color functions. Just keep it that way. color() should use commas so that the new thing is consistent with the older things. Maybe it’s not “pure” when thinking about code syntax across all of CSS, but it’s easier for people who write CSS, and that’s important.

What do you think?

Comments

For my money, the commas are important.

Consistency is nice, but perhaps less important than efficiency, and removing the commas for the sake of efficiency has some merit.

That said, there’s a difference between the existing comma-ed and un-comma-ed syntaxes — the un-comma-ed values almost always have a unit associated with them, padding: 1em 20px 10% 0 versus color: rgba0, 255, 56, 50%). This makes them easier to visually parse without commas.

If the color values no longer have commas (color: color(0 255 56 50%)) and spaces are the only thing demarcating each individual value, things will get confusing at times. Perhaps your eyes are tired or weak, or you’re in bright light and your display is dim, or (the first case that came to mind) you’re using a tightly-tracked font in your editor and the spaces are (by design) narrow to save space.

Removing the commas may provide some extra efficiency in the code itself, it makes parsing the code (by humans) less efficient, which, IMO, should take precedence.

I think the key question is what’s going to let users/CSS writers develop a mental model that makes sense and is internally consistent? Ie, if I see an arbitrary new property or function, what’s my heuristic for determining if I should put commas there or not? Figure out that heuristic and stick to it. Otherwise, you’re breaking people’s mental models.

Based solely on the examples shown above (as I am not a CSS wizard that’s memorized all of the ins and outs of CSS), the mental models that I start developing while looking for a pattern are (in the order I think of them):

* Properties that are a short hand for multiple other properties (eg, margin) don’t use commas. This one seems consistent.
* Things inside parentheses use commas, others don’t. Wait, no, a few things use commas on SOME elements within parentheses. (eg, polygon) Er, why?
* Oh wait, some properties (like grid-template rows) seem to not be a short-hand, but they don’t use commas. Wait, why?
* OK, at least colors seem to always have commas. Because, reasons? So what makes color different from the others?
* Guess: The ones without commas in parentheses are where the values form a sort of implicit tuple, rather than being a list. But, a tuple is a list. So wait, what?
* Parentheses in every language I use (Javascript, PHP, Python, Java, C, C++) mean function call. And in those languages there’s always a comma. So anything that is like passing multiple parameters to a function call should use commas. I hope…
* OK, so given that, if I assume that function calls use commas, no comma means it’s a tuple of some kind that’s a sort of anonymous data format (really?), then polygon is a function that takes 4 parameters (in this case), each of which is a 2-tuple. What each of those mean I have no idea.
* But then circle takes one anonymous tuple, but WTF, how is one anonymous tuple as a parameter different than 3 parameters? It’s not. That’s just stupid, CSS!

So my concluding mental model is:
1) Function calls have commas.
2) Tuples do not.
3) Except where CSS is just stupid.

Since the new function, like the other color functions, looks/feels like a function, I would expect it to take commas. And for the pattern above to hold in the future, too, while minimizing case 3. :-)

Keep the commas!

There are several reasons for my point of view. Mainly, it’s part of the current syntax for colors, and for consistency should remain part of the color syntax.

Thinking about how colors may be expanded in the future, what if the CSSWG decides to add the ability to provide different opacity values (Ov), for example for R, G and B: colorFunction(Rv Ov, Gv Ov, Bv Ov)? Similarly, lightening and darkening values. Having commas better enables expanding on existing syntax. Then, of course, there may be expansions that would benefit from not having commas yet, as commas will be needed to separate multiple values.

The example of “padding: 1em 2em 0.5em;” is a good example of why we should keep commas. One of the things that was most difficult to get students of CSS to memorize was TRBL - and what having 1, 2, 3 and 4 values meant.

The “border: 1px solid #000;” example is a completely different beast, as those are three different value that can’t get confused: a length, a type, and a color. It doesn’t need to have commas.

The border example is also an example of how not having commas would allow for the spec to change by including commas: why doesn’t “border: 1px solid #000, 3px dashed #F00;” not mean the top and bottom borders should be black solid and thin with both the left and right borders being medium, dashed and red? Not having commas means this property could be expanded upon to do that.

While there are many other reasons I can argue for commas, the one I’ll close with is legibility. When checking my work to see if I’ve declared the color correctly, I always count the commas. Without a separator, it’s harder to read. rgba(27 56 48 1) is harder to read than rgba(27, 56, 48, 1) or even rgba(27,56,48,1) . Float numbers aren’t supported in the hexi 0-255 values, but they are for percent values. While rgba(27 56 48 1) might still be legible, rgba(27.64528% 56.4441298% 48.51969% 0.95623) is really, really hard to read.

Stick with commas.

I strongly prefer continuing to use commas. It would be confusing to have some color functions use commas, while others don’t. If all color functions were changed so that commas were optional, I could live with that, but only as long as new color functions, like color(), supported the optional commas. Having some function support optional commas and others not would be less confusing, but still confusing. I do think that optional commas are a risk, because it would imperil possible future functions where there might be a desire to have two kinds of separators, as Estelle points out.

They’re also, as others have pointed out, a useful authorial aid, in that they provide a stronger visual signal and reduce the chances of overlooked error.

Things like this stress me out. I see little reason to change this syntax at this point and create the added cognitive load to developers looking to learn or write css. Functional Notations** (as the specs named them - https://www.w3.org/TR/css3-values/#functional-notations) should all behave the same, and we already have a ton of precedent with other functions (I’ll add the various transform keywords to the list you already listed, Jen - https://developer.mozilla.org/en-US/docs/Web/CSS/transform#Syntax)

Here’s the mental model I have of CSS value syntax:

If you have a statement with multiple distinct values you use spaces - for example, you’re assigning 3 separate keywords to a single transform, you’re assigning 3 different values to a border. Order of all these values are subject to their various syntax rules in the spec (some optional, some flexibility in ordering of values, etc)

If you have a functional notation — which after processing, represent a single value — each of the parameters/arguments you send to that function have a specific order, and should always follow the same syntax rules — in this case, due to precedent, separated by commas.

This model holds up even with complex functions like calc(), linear-gradient(), polygon(), etc: calc() takes one argument — a single mathematical expression, thus no commas needed; linear-gradient may look mixed, but the spaces in the keyword style angle parameter are just defining the one, first, parameter; likewise, polygon() takes any number of distinct points, where each point is separated by a comma. [inset() could arguably break that mold… arguably… are you passing it 4 points or a box?].

** Note, I don’t like the language in this part of the spec either wrt rgb().

Add new comment

By submitting this form, you accept the Mollom privacy policy.