Re: [Proposal] CSS gradients

On Dec 13, 2007, at 10:33 AM, John Oyler wrote:

>>> Unlike this proposal, I'd roll all the various parameters into  
>>> the gradient() function though. Something like:
>>>
>>> gradient(linear, #000, x1, y1, #777, x2, y2, #999, d1, #fff, d2 ...)
>>>
>>> Where the first color is for the first XY pair, the second color  
>>> is for the second XY pair (this gives direction), and every  
>>> subsequent color/d# is a distance and color combo. Variations  
>>> could be worked up for radial and other types of gradients.
>>
>> To me, using x/y coordinates for the first two stops and then  
>> distances for the remaining stops seems cumbersome. I would much  
>> rather see angles indicated by degrees, as that is how I tend to  
>> think of them (especially with typical 45 or 90 degree  
>> increments), and is typically how they are specified in other  
>> applications (such as PhotoShop). What if it were more like the  
>> following, with the word "linear" optional for linear gradients,  
>> and the distance measures only required if there were not just 0%  
>> to 100%:
>>
>
> Angles are problematic. First, I'm assuming that we may want  
> gradients other than linear at some time in the future, and parsing  
> would be easier if the first argument is the "type".

Agreed, that the first argument should be type, as in my example (a  
single word). If omitted then default of "linear", and with the  
syntax I showed it would be easy to tell if it was omitted.

> If it's radial, we need x,y for the center anyway. Why not keep it  
> consistent? Besides, if you give it only an angle, there's no way  
> to specify at what x,y the thing starts... so it must start at the  
> top left corner or something. What if you wanted the bright blue to  
> not face immediately, but give you half an inch before starting to  
> face to transparent?

That would be the first color/distance pair. So, for blue starting at  
1/2 inch and then going to transparent at the opposite edge, I would  
write it thusly:

	gradient(linear, 90deg, blue .5in, transparent 100%)

For radial and diamond gradients the default would be center,  
otherwise you need one more x or y to begin with. Perhaps, since  
degrees are not needed for those we could say that the second  
argument will be the horizontal measurement. So, if we wanted the  
radial gradient to start 1 inch to the right and 1/2 inch down, then  
that could be written as this:

	gradient(radial, 1in, blue .5in, transparent 100%)

So parsing would go something like this:

1. If the first argument is not a keyword for "type", such as  
"linear", "radial", or "diamond", then assume "linear". Go to step 2
2a. If linear, then the second argument needs to be either degrees or  
a keyword indicating angle. Go to step 3.
2b  If not linear:
	2b1.  If the second argument begins with  a color, then assume  
"center".  Go to step 3.
	2b2.  If not "linear" from step 1 then this second argument is a  
measure of distance (percentage, absolute measure, ems, etc.) from  
the left edge. Skip to 3b, as 3a would not be an option for this more  
complex gradient.
3a. If the next argument is a color and nothing more, then it is  
assumed to be for the 0% distance, and there can be only one more  
argument of color, for the 100% distance.
3b. Otherwise, all other arguments would be pairs of colors and  
distances. The first pair would be where the gradient begins (for non- 
linear that would be either from the center or it would be the  
distance from the top, depending on 2b1 or 2b2 respectively) and the  
last pair would be where it ends. Outside of the starting and ending  
points the color would be solid continuations of the starting and  
ending colors.

The one downside of that scheme is that if you wanted to specify a  
radial gradient that started from somewhere other than center, and be  
solid for a certain distance before it started to blend, then you  
would have to specify the same color in two places, just as you would  
if you wanted a section of solid color somewhere in the middle of a  
blend. So, for instance, liek this:

	gradient(radial, 1in, blue .5in, blue 50%, transparent 100%)


> Also, 90 degrees is by far the least interesting (though possibly  
> would be the most used) example you could give... small background  
> images can simulate this to a degree. It's only when you're wanting  
> something diagonal that the images become cumbersome in size.

When  I said cumbersome, I wasn't really referring to the size. I was  
referring to the need to fire up an image editor, create the file,  
optimize for the Web and save, note the file name and reference it in  
the css, upload the file to the server, etc. Also, you would need to  
use image stretching to go from 0% to 100% unless you know the size  
of the box ahead of time. Some blends would require either 24 bit  
color (which increases file size) or rendered dithering (which can  
make CSS pattern repeats a little dicy). The idea of the original  
proposal was to avoid all that sort of thing, and similar  
complications of SVG files, etc. in order to be able to just do  
simple little gradients.

It is because 90 degree increments would be most common that I think  
the syntax should be simplest for 90 degree increments, and should be  
much simpler to accomplish than with images or SVG.

>> gradient(linear, 90deg, #000 20px, #777 10%, #999 50%, #fff 60% ...)
>>
>> I'm not sure if you'd want to mix pixels with percentages like  
>> that, although I could see that doing so might be useful. If you  
>> wanted the angle to be dependant on the box size, then maybe you  
>> have some optional key words to replace the angle measurement:
>>
>
> Certainly percentages are necessary. And there are probably cases  
> where you would want to mix percentages and other units. Unless it  
> became difficult to compute (and it shouldn't), mixing would be  
> fine with me.

I would like to mix them. I was thinking along the lines of what the  
UAs would do for error handling might be complex if the validity of  
the rule depended on the size of the box. For instance, with a 10  
inch wide box, this would be OK:

gradient(linear, 0deg, #000 5in, #765 75%, #999 100%)

But I'm not sure what it would do on a 4 inch wide box, as the color  
stops would have to be drawn out of order or else skipped. I guess as  
long as the error cases are clearly spelled out what to do, then it  
should be fine.

> Really though, look at it... by going with degrees, you're only  
> save yourself two units in the whole gradient. Your first two stops  
> still need 1 measurement, mine would have it at two.

I like yours, much better than SVG or image. It inspired me to  
suggest this improvement to it. I find the color/distance pairings as  
a single parameter to be much easier to read and understand than a  
long list of comma separated values of which the first 7 values have  
different meanings than the alternating color/distance pattern of the  
remaining comma separated vlaues. The pattern of  
"color,measure,measure,color,measure,measure,color,measure,color,measure 
,color,measure..." is harder to read and write than "color measure,  
color measure, color measure...".

Also, the pattern I am suggesting would lead more naturally to using  
defaults for simple gradients. If I understand it, your proposal in  
its shortest form would look like this:

	gradient(type, color, x1, y1, color, x2, y2)

That would be similar to the form I would use without any defaults:

	gradient(type, angle, color d1, color d2)

So, very similar, but I think mine is easier to read. But my shortest  
form would look like this:

	gradient(angle, color, color)

And if 90 degrees is most common, it could be a default as well  
(along with "center" for non-linear gradients). So for 90 degree  
linear gradients, it could be further shortened:

	gradient(color, color)

Which I would really love for its simplicity. Much simpler than using  
an image. Maybe 270 degrees (-90°) would be a better default in order  
to specify color top-to-bottom, but that's probably just quibbling.

> And it would leave you with being able to do less complex  
> gradients. As for the keywords, I think angles are already a CSS  
> unit that can be defined several ways. Degress, radians, and if I'm  
> not mistaken, compass directions. So if angles were used, I think  
> you already have that.

I could not find reference in the working draft to compass directions  
(it does mention "turns", but I don't know what that is, and it seems  
to be undefined). If you could specify "NE" or "northeast" to mean  
from the lower left corner to the upper right corner, then that would  
be cool. Otherwise degrees or radians wouldn't work because the angle  
would change depending on the size of the box.

Does anyone other than mathematicians use radians? I have a hard time  
imagining how a radian would ever be a useful measurement for CSS  
design. But I suppose that is a separate conversation.

>
>> gradient(linear, bottom-left to top-right, #000 20px, #777 10%,  
>> #999 50%, #fff 60% ...)
>>
>
> John Oyler
> john@discrevolt.com
>
>
>
>

Received on Friday, 14 December 2007 17:22:28 UTC