Re: [css3-background] A property to control background opacity

On 26/12/2013 4:58 AM, Dirk Schulze wrote:
>
> On Dec 25, 2013, at 2:45 PM, Alan Gresley <alan@css-class.com>
> wrote:
>
>> On 25/12/2013 6:56 AM, Simon Fraser wrote:
>>
>>> Simon
>>>
>>> On Dec 23, 2013, at 11:57 pm, Dirk Schulze <dschulze@adobe.com>
>>> wrote:
>>>
>>>>
>>>> On Dec 24, 2013, at 8:47 AM, Dirk Schulze <dschulze@adobe.com>
>>>> wrote:
>>>>
>>>>>
>>>>> On Dec 24, 2013, at 8:34 AM, Simon Fraser <smfr@me.com>
>>>>> wrote:
>>>>>
>>>>>> On Dec 23, 2013, at 7:06 PM, Rik Cabanier
>>>>>> <cabanier@gmail.com> wrote:
>>>>>>
>>>>>>> On Mon, Dec 23, 2013 at 4:33 PM, David
>>>>>>> <david.email@ymail.com> wrote: Hello,
>>>>>>>
>>>>>>> it would be great if a CSS property would be added to
>>>>>>> control the opacity of the background-image. The
>>>>>>> background-color and its opacity is already controlable
>>>>>>> via rgba() or hsla(). The opacity property itself allows
>>>>>>> just to control the opacity of the whole element.
>>>>>>>
>>>>>>> We had a short discussion on this at the last F2F during
>>>>>>> TPAC [1]. It was unfortunately not minuted. :-(
>>>>>>>
>>>>>>> During the meeting, people said that this feature has
>>>>>>> been requested for a long time but for some reason, it
>>>>>>> never was spec'ed out or implemented.
>>>>>>>
>>>>>>> Normative text could look as follows: The
>>>>>>> ‘background-opacity’ property
>>>>>>>
>>>>>> An alternative to this would be to have an image function
>>>>>> that gives an image alpha, e.g.:
>>>>>>
>>>>>> background-image: alpha-image(foo.png, 50%);
>>>>>>
>>>>>> This would seem preferable to a property that can only
>>>>>> apply alpha to background images.
>>>>>
>>>>> Just to give more alternatives: In WebKit the CSS Image
>>>>> function -webkit-filter() is implemented with the opacity
>>>>> filter function:
>>>>>
>>>>> background-image: -webkit-filter(foo.png, opacity(0.5));
>>>>
>>>> Just to give a bit more background: The filter() image function
>>>> is specified in Filter Effects[1] and allows filtering other
>>>> CSS Images:
>>>>
>>>> filter( [ <image> | <string> ], <filter-function-list> )
>>>>
>>>> opacity() is one of the filter functions beside others [2].
>>>>
>>>> Greetings, Dirk
>>>>
>>>> [1] http://dev.w3.org/fxtf/filters/#FilterCSSImageValue [2]
>>>> http://dev.w3.org/fxtf/filters/#FilterProperty
>>>
>>> Of course!
>>>
>>> Given this, I see little utility in a per-background-image
>>> background-opacity property.
>>
>> What if one also needed to control background-repeat,
>> background-attachment, background-position, background-clip,
>> background-origin or background-size?
>
> You can do all that the same way as you can do today. The filter()
> function doesn’t make any difference. It just filters your specified
> image and even allows animation of the filter operation.

In §3.1. 'Layering Multiple Background Images' is the following:

   | Each of the images is sized, positioned, and tiled
   | according to the corresponding value in the other
   | background properties. The lists are matched up from
   | the first value: excess values at the end are not used.

Considering that 'background-image: filter()' came into the discussion, 
we begun talking about a 'background tile' that is not exposed to these 
'other background properties'. The image itself in the url() buried 
within the filter function is not effected (sized, positioned, and 
tiled) by the 'other background properties'. Only the 'background tile' 
itself is effected by the 'other background properties'.

The 'background tile' is much like how view box works in a SVG and it is 
what the <image> value is in CSS Image. CSS Image does not concern 
itself with properties that can effect size, position and tiling as CSS 
Backgrounds and Borders does.

If one layer was an image (e.g. jpg, png or svg) that is exposed to 
'other background properties', then this may be the layer that you would 
want to hit with opacity. This seems to be what David (the original 
poster) has proposed.

   > it would be great if a CSS property would be added to
   > control the opacity of the background-image.

The only way to do this is to used a background-property. Earlier in 
this thread Rik mentions about the short discussion on this at the last 
F2F during TPAC and gives an example of what the normative text could 
look like [2]. Part of this has as follows:

   | Defines the opacity of each background layer.

   | The ‘background-opacity’ list must be applied in the
   | same order as ‘background-image’.


You added later in this thread about using all filter functions:

filter( [ <image> | <string> ], <filter-function-list> )

Simon then proceeds to see no merit in the proposal but says that it may 
be better to "apply opacity to the grouped background images and 
background color." Well this could simply be done by using the following 
CSS:

   background-filter: opacity(50%);

This follows the same syntax structure as the filter properties that is 
implemented with a prefix -webkit- and can be tested in Chrome but it 
effects the whole element:

   filter: opacity(50%);

Chris Lilley mentions at TPAC about controlling border-image which could 
be done as follow:

   border-filter: opacity(50%);


Restricting it to one layer makes it impossible to hit all or some 
layers at once:

   /* all images with opacity */

   background-image: url(foo.svg), linear-gradient(), url(bar.png), 
linear-gradient();

  background-filter: opacity(50%);

       or

   /* alternative images with opacity */

  background-image: url(foo.svg), linear-gradient(), url(bar.png), 
linear-gradient();

  background-filter: opacity(50%), opacity(100%);


To do that with a <image> filter function in a background-image string 
requires much more syntax and can be very confusing. The way that §13 
Filter CSS <image> values [3] reads makes it seems that it's not going 
to follow the normal syntax.

<image> = <url> | <image-list> | <gradient>


So using the example with <url> and <gradient> gives me something like 
as follows:

   /* all images with opacity */

   background-image: filter(url(foo.svg), opacity(0.5)), 
filter(linear-gradient(), opacity(0.5)), filter(url(bar.png), 
opacity(0.5)), filter(linear-gradient(), opacity(0.5));

      or

   /* alternative images with opacity */

   background-image: filter(url(foo.svg), opacity(0.5)), 
linear-gradient(), filter(url(bar.png), opacity(0.5)), linear-gradient();


Now to change the opacity of any of the images require repeating the 
whole background string (keep in mind that any of the following may 
already be sized, positioned, and tiled by the 'other background 
properties' so you can not change the order):

   /* all images with opacity */

   background-image: filter(url(foo.svg), opacity(1)), 
filter(linear-gradient(), opacity(0)), filter(url(bar.png), opacity(1)), 
filter(linear-gradient(), opacity(0));

This could simply have be done by changing this,

   background-filter: opacity(50%);

to this.

   background-filter: opacity(100%), opacity(0%);


>> Now with 'background-blend-mode', we now have another background
>> property that accepts a comma separated list of values.
>>
>> Offline testing also shows me that 'mix-blend-mode' with an
>> background-image where one can control opacity is not achievable
>> with 'background-image: filter()'. It requires
>> 'background-image:element()' instead.
>
> I do not understand your conclusion here. What does ‘mix-blend-mode’
> (blending of elements) have to do with filter() or even
> background-blend-mode (which blends background layers)?

The way they interact with the other background properties. In §3.4.3 
the ‘background-blend-mode’ property, we have as follows:

   | The ‘background-blend-mode’ list must be applied
   | in the same order as ‘background-image’[CSS3BG].
   | This means that the first element in the list will
   | apply to the layer that is on top. If a property
   | doesn't have enough comma-separated values to match
   | the number of layers, the UA must calculate its used
   | value by repeating the list of values until there are
   | enough.


>>> The only utility for a new background-opacity property that I can
>>> see is one that is not per-background-image, but rather applies
>>> opacity to the grouped background images and background color,
>>
>> Many of the effects I have used with transparency in
>> background-image has always employed the use of a fully opaque
>> background-color.
>>
>> If you don't want element() for security reasons then it best to
>> allow these filters to become a new background property since you
>> can accept a comma separated list of values.
>
> This thread is not about element() but having ‘background-opacity’ or
> not. I only said that it could be done with the filter() function. It
> doe neither mean it should be the only way or even is the best way.
> It just means it is possible with todays specifications.

That is good to read. So which of the following works in Safari?

   -webkit-filter(foo.png, opacity(0.5))

   -webkit-filter(url(foo.png), opacity(0.5))

   filter(url(foo.png), opacity(0.5))


>> background-filter: blur(), opacity(), saturate(), hue-rotate();
>>
>> Each one can be independently animated. If you just wanted to
>> animate the opacity of just one background-image in a long
>> background comma separated string, then the whole string must be
>> used in such an animation instead something simple like this.
>>
>> 0% { background-filter: opacity(100%) }
>> 100% { background-filter: opacity(0%) }
>
> If you already specify this chain, another filter function wouldn’t
> even be a problem.

See the examples with opacity above where one must repeat the whole 
background-image string.


>> Below is one background string that I have used. I have had a
>> colleague look at it and wondered what was happening. When you have
>> nested parenthesis as in linear-gradients, it is so easy to make a
>> mistake.

[snipped]

>> background:
>> radial-gradient(hsl(0, 100%, 27%) 4%, hsl(0, 100%, 18%) 9%, hsla(0, 100%, 20%, 0) 9%) 0 0,
>> radial-gradient(hsl(0, 100%, 27%) 4%, hsl(0, 100%, 18%) 8%, hsla(0, 100%, 20%, 0) 10%) 50px 50px,
>> radial-gradient(hsla(0, 100%, 30%, 0.8) 20%, hsla(0, 100%, 20%, 0)) 50px 0,
>> radial-gradient(hsla(0, 100%, 30%, 0.8) 20%, hsla(0, 100%, 20%, 0)) 0 50px,
>> radial-gradient(hsla(0, 100%, 20%, 1) 35%, hsla(0, 100%, 20%, 0) 60%) 50px 0,
>> radial-gradient(hsla(0, 100%, 20%, 1) 35%, hsla(0, 100%, 20%, 0) 60%) 100px 50px,
>> radial-gradient(hsla(0, 100%, 15%, 0.7), hsla(0, 100%, 20%, 0)) 0 0,
>> radial-gradient(hsla(0, 100%, 15%, 0.7), hsla(0, 100%, 20%, 0)) 50px 50px,
>> linear-gradient(45deg, hsla(0, 100%, 20%, 0) 49%, hsla(0, 100%, 0%, 1) 50%, hsla(0, 100%, 20%, 0) 70%) 0 0,
>> linear-gradient(-45deg, hsla(0, 100%, 20%, 0) 49%, hsla(0, 100%, 0%, 1) 50%, hsla(0, 100%, 20%, 0) 70%) 0 0;
>> background-color: #300;
>> background-size: 100px 100px;
>
> For each layer where you want to have opacity, you would need to
> write filter(…, opacity(0.5)), right.

Yes but you have to repeat the whole background-image string if you want 
to animate that one value of 'filter(…, opacity(0.5))' in it.


> Greetings, Dirk
>
>>
>>
>> 1. http://lea.verou.me/css3patterns/
2. http://lists.w3.org/Archives/Public/www-style/2013Dec/0426.html
3. http://dev.w3.org/csswg/css-images-3/#image-list-type


Alan


-- 
Alan Gresley
http://css-3d.org/
http://css-class.com/

Received on Friday, 27 December 2013 02:47:39 UTC