1. Introduction
This section is not normative.
This module introduces additional ways of representing 2D images, for example as a URL with color fallback, as conic gradients, or as the rendering of another element in the document.
1.1. Value Definitions
This specification follows the CSS property definition conventions from [CSS2] using the value definition syntax from [CSS-VALUES-3]. Value types not defined in this specification are defined in CSS Values & Units [CSS-VALUES-3]. Combination with other CSS modules may expand the definitions of these value types.
In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the CSS-wide keywords as their property value. For readability they have not been repeated explicitly.
2. 2D Image Values: the <image> type
The <image> value type denotes a 2D image. It can be a url reference, image notation, or gradient notation. Its syntax is:
<image> = <url> | <image () > | <image-set () > | <cross-fade () > | <element () > | <gradient>
An <image> can be used in many CSS properties, including the background-image, list-style-image, cursor properties [CSS2] (where it replaces the <url> component in the property’s value).
In some cases an image is invalid, such as a <url> pointing to a resource that is not a valid image format or that has failed to load. An invalid image is rendered as a solid-color transparent image with no natural dimensions. However, invalid images can trigger error-handling clauses in some contexts. For example, an invalid image in list-style-image it is treated as none, allowing the list-style-type to render in its place. [CSS2]
While an image is loading, is a loading image. Loading images are not invalid images, but have similar behavior: they are rendered as a solid-color transparent image with no natural dimensions, and may trigger fallback rendering in contexts that offer it, but must not trigger loading of fallback resources. Alternately, if a loading image happens to be replacing an already-loaded image (for example due to changes in the document or style sheet) and the UA is tracking this information, it may continue to render the already-loaded image in place of the loading image.
Partially-loaded images (whose natural dimensions are known, but whose image data is not fully loaded) may be either treated as loading images or as loaded images rendered with partial data. For example, a UA may render an interlaced GIF in place as soon as its first pass of pixel data has loaded or even as soon as the image header (which contains sizing data) has parsed and refresh the rendering as more data loads; or it may wait until the entire image has loaded before using it.
A computed <image> value is the specified value with any <url>s, <color>s, and <length>s computed.
2.1. Image File Formats
At minimum, the UA must support the following image file formats when referenced from an <image> value, for all the properties in which using <image> is valid:
- PNG, as specified in [PNG]
- SVG, as specified in [SVG11], using the secure static mode (See [SVG-INTEGRATION])
- If the UA supports animated <image>s, SVG, as specified in [SVG11], using the secure animated mode (See [SVG-INTEGRATION])
The UA may support other file formats as well.
2.2. Image References: the url() notation
Note: No change from [css-images-3].
2.3. Fetching External Images
To fetch an external image for a stylesheet, given a <url> url and a CSS declaration block declaration, fetch a style resource given url, with ruleOrDeclaration being declaration, destination "image", CORS mode "no-cors", and processResponse being the following steps given response res and null, failure or a byte stream byteStream: If byteStream is a byte stream, load the image from the byte stream.
2.4. Resolution/Type Negotiation: the image-set() notation
Delivering the most appropriate image resolution for a user’s device can be a difficult task. Ideally, images should be in the same resolution as the device they’re being viewed in, which can vary between users. However, other factors can factor into the decision of which image to send; for example, if the user is on a slow mobile connection, they may prefer to receive lower-res images rather than waiting for a large proper-res image to load. The image-set() function allows an author to ignore most of these issues, simply providing multiple resolutions of an image and letting the UA decide which is most appropriate in a given situation.
This solution assumes that resolution is a proxy for filesize, and therefore doesn’t appropriately handle multi-resolution sets of vector images, or mixing vector images with raster ones (e.g. for icons). For example, use a vector for high-res, pixel-optimized bitmap for low-res, and same vector again for low-bandwidth (because it’s much smaller, even though it’s higher resolution).
The syntax for image-set() is:
<image-set () > =image-set ( <image-set-option>#) <image-set-option> =[ <image> | <string>] [ <resolution> ||type ( <string>) ] ?
We should add "w" and "h" dimensions as a possibility to match the functionality of HTML’s picture.
Each <string> inside image-set() represents a <url>.
The image-set() function can not be nested inside of itself, either directly or indirectly (as an argument to another <image> type).
Each <image-set-option> defines a possible image for the image-set() function to represent, composed of three parts:
-
An image reference (required). This can be a URL, or a CSS generated image, such as a linear-gradient().
-
A <resolution> (optional). This is used to help the UA decide which <image-set-option> to choose. If the image reference is for a raster image, it also specifies the image’s natural resolution, overriding any other source of data that might supply a natural resolution.
If not specified, it behaves as 1x for the purpose of selecting which <image-set-option> to use. It also defaults the image’s natural resolution to 1x, but if some other source of data supplies a natural resolution, that resolution must be honored instead.
-
A type( <string> ) function (optional), specifying the image’s MIME type in the <string>.
If the <string>, when parsed as a valid MIME type string, is either not valid, or is valid but doesn’t specify a supported image format, the <image-set-option> does not define a valid option. (This has no effect on the validity of the image-set() function.)
It does not have any effect on the image itself; an <image-set-option> like
is valid, and if chosen will display the linked PNG image, even though it was declared to be a JPEG.url ( "picture.png" ) 1 x type ( "image/jpeg" ) If not specified, it has no effect on the <image-set-option>.
Tests
- image-set-all-options-invalid.html (live test) (source)
- image-set-calc-x-rendering-2.html (live test) (source)
- image-set-calc-x-rendering.html (live test) (source)
- image-set-computed.sub.html (live test) (source)
- image-set-conic-gradient-rendering.html (live test) (source)
- image-set-content-rendering.html (live test) (source)
- image-set-dpcm-rendering.html (live test) (source)
- image-set-dpi-rendering-2.html (live test) (source)
- image-set-dpi-rendering.html (live test) (source)
- image-set-dppx-rendering.html (live test) (source)
- image-set-empty-url-rendering.html (live test) (source)
- image-set-first-match-rendering.html (live test) (source)
- image-set-linear-gradient-rendering.html (live test) (source)
- image-set-negative-resolution-rendering-2.html (live test) (source)
- image-set-negative-resolution-rendering-3.html (live test) (source)
- image-set-negative-resolution-rendering.html (live test) (source)
- image-set-no-res-rendering-2.html (live test) (source)
- image-set-no-res-rendering.html (live test) (source)
- image-set-no-url-rendering.html (live test) (source)
- image-set-parsing.html (live test) (source)
- image-set-radial-gradient-rendering.html (live test) (source)
- image-set-rendering-2.html (live test) (source)
- image-set-rendering.html (live test) (source)
- image-set-repeating-conic-gradient-rendering.html (live test) (source)
- image-set-repeating-linear-gradient-rendering.html (live test) (source)
- image-set-repeating-radial-gradient-rendering.html (live test) (source)
- image-set-resolution-001.html (live test) (source)
- image-set-resolution-002.html (live test) (source)
- image-set-resolution-003.html (live test) (source)
- image-set-type-first-match-rendering.html (live test) (source)
- image-set-type-rendering-2.html (live test) (source)
- image-set-type-rendering-3.html (live test) (source)
- image-set-type-rendering.html (live test) (source)
- image-set-type-skip-unsupported-rendering.html (live test) (source)
- image-set-type-unsupported-rendering-2.html (live test) (source)
- image-set-type-unsupported-rendering.html (live test) (source)
- image-set-unordered-res-rendering.html (live test) (source)
- image-set-zero-resolution-rendering-2.html (live test) (source)
- image-set-zero-resolution-rendering.html (live test) (source)
An image-set() function contains a list of one or more <image-set-option>s, and must select only one of them to determine what image it will represent:
-
First, remove any <image-set-option>s from the list that specify an unknown or unsupported MIME type in their type() value.
-
Second, remove any <image-set-option>s from the list that have the same <resolution> as a previous option in the list.
-
If there are no <image-set-option> left at this point, the function represents an invalid image.
-
Finally, among the remaining <image-set-option>s, make a UA-specific choice of which to load, based on whatever criteria deemed relevant (such as the resolution of the display, connection speed, etc).
-
The image-set() function then represents the <image> of the chosen <image-set-option>.
UAs may change which <image-set-option> they wish to use for a given image-set() over the lifetime of the page, if the criteria used to determine which option to choose change significantly enough to make it worthwhile in the UA’s estimation.
background-image : image-set ( "foo.png" 1 x , "foo-2x.png" 2 x , "foo-print.png" 600 dpi );
background-image : image-set ( "foo.avif" type ( "image/avif" ), "foo.jpg" type ( "image/jpeg" ) );
Note that the AVIF image is given first; since both images have the same resolution (defaulting to 1x since it’s unspecified), the JPEG image, coming second, is automatically dropped in UAs that support AVIF images.
In older UAs, however,
the AVIF image is ignored
(because the UA knows it doesn’t support files),
and so the JPEG is chosen instead.
For example, in this code snippet a high-resolution image with subtle details is used on screens that can do it justice, while an ordinary CSS linear-gradient() is used instead for low-resolution situations:
background-image : image-set ( linear-gradient ( cornflowerblue, white) 1 x , url ( "detailed-gradient.png" ) 3 x );
2.5. Image Fallbacks and Annotations: the image() notation
The image() function allows an author to easily generate a solid-color image from any color. Its syntax is:
image () =image ( <color>)
The image() function represents a solid-color image of the specified color with no natural dimensions.
background-image : image ( rgba ( 0 , 0 , 255 , .5 )), url ( "bg-image.png" );
This is equivalent to a single color stop gradient:
background-image : linear-gradient ( rgba ( 0 , 0 , 255 , .5 )), url ( "bg-image.png" );
background-color does not work for this, as the solid color it generates always lies beneath all the background images.
Note: This function previously defined a number of additional behaviors, but those have been shifted to [css-images-5].
2.6. Combining images: the cross-fade() notation
When transitioning between images, CSS requires a way to explicitly refer to the intermediate image that is a combination of the start and end images. This is accomplished with the cross-fade() function, which indicates the two images to be combined and how far along in the transition the combination is.
Note: Authors can also use the cross-fade() function for many simple image manipulations, such as tinting an image with a solid color or highlighting a particular area of the page by combining an image with a radial gradient.
The syntax for cross-fade() is defined as:
cross-fade () =cross-fade ( <cf-image>#) <cf-image> =[ <image> | <color>] && <percentage[ 0 , 100 ] >?
The function represents an image generated by combining one or more images.
The <percentage> represents how much of each image is retained when it is blended with the other images. The <percentage> must be between 0% and 100% inclusive; any other value is invalid.
If any percentages are omitted, all the specified percentages are summed together and subtracted from 100%, the result is floored at 0%, then divided equally between all images with omitted percentages at computed-value time.
On the other hand, when the sum is less than 100%, the sizing/painting details effectively act like there’s an additional transparent argument, with its percentage set to the remaining value necessary to make the sum equal 100%.
If a <color> is provided, it represents a solid-color image with “automatic” dimensions (it doesn’t participate in the sizing of the result image at all; see details in the sizing details below).
Tests
- cross-fade-basic.html (live test) (source)
- cross-fade-computed-value.html (live test) (source)
- cross-fade-legacy-crash.html (live test) (source)
- cross-fade-legacy-2-crash.html (live test) (source)
- cross-fade-natural-size.html (live test) (source)
- cross-fade-premultiplied-alpha.html (live test) (source)
- cross-fade-target-alpha.html (live test) (source)
2.6.1. cross-fade() Sizing
The dimensions of the image represented by a cross-fade() are a weighted average of dimensions of the <image> arguments to the function; the <color> arguments have no effect. They are calculated as follows:
-
Normalize mix percentages from the function’s arguments, and let args and leftover be the result.
-
If leftover is 100%, return no natural dimensions.
-
Let images be an empty list.
-
For each <cf-image> argument of the function’s arguments:
-
If argument is not an <image>, or is an <image> with no natural dimensions, continue.
-
Let item be a tuple consisting of a width, a height, and a percentage.
-
Run the object size negotiation algorithm for the <image>, as appropriate for the context in which the cross-fade() appears, and set item’s width and height to the width and height of the resulting concrete object size.
-
Set item’s percentage to the argument’s percentage.
-
-
If images is empty, return no natural dimensions.
-
Return a natural width and natural height that are weighted averages of the width and height of each item in images, according to their corresponding percentages.
Note: The percentages might sum to a value less than 100%, so a naive weighted-averaging process might need to normalize them first.
2.6.2. cross-fade() Painting
The image represented by a cross-fade() is a weighted average of the input arguments to the function, calculated as follows:
-
Normalize mix percentages from the function’s arguments, and let args and leftover be the result.
-
Let images be an empty list.
-
Let size be a tuple of width and height, initialized to the result of finding the concrete object size of the cross-fade() function (using the natural dimensions of a cross-fade()).
-
For each argument of the cross-fade() function:
-
Let item be a tuple consisting of an image and a percentage.
-
If argument has an <image>, rescale it to size’s width and height and set item’s image to the result. Otherwise, argument has a <color>; set item’s image to a solid-color image of the <color>, with size’s dimensions.
-
Set item’s percentage to the argument’s percentage.
-
-
If leftover is greater than 0%, append a tuple to images consisting of a solid-color transparent-black image with size’s dimensions, and a percentage equal to leftover.
-
Let final image be an image with size’s dimensions, and every pixel being the weighted linear average of the corresponding pixels of each item’s image in images, weighted according to the item’s percentage. (Average both the color channels and the alpha channel of the pixels.) For the purpose of this calculation, each pixel’s color must be in pre-multiplied sRGB.
Details on the above operation
This is applying an N-way Porter-Duff
dissolveoperation to the source images. Wikipedia definesdissolveas a stochastic operation, with the result pixels independently randomly chosen from the source images’ corresponding pixels according to their source images’ weights, but as pixels shrink to infinitely small, this converges to doing color-averaging in pre-multiplied color space.In particular, this means that `cross-fade(white 50%, transparent 50%)` will produce a partially-transparent solid white image. (Rather than a partially-transparent gray, which is what you’d get if you averaged the opaque white and transparent black pixels in non-premultiplied space.)
As converting to pre-multiplied does entail some loss of precision, and graphics libraries may or may not support this operation natively, as per usual any method can be used so long as it achieves the specified effect.
For example, one can instead rebalance the percentages according to the alphas of each pixel, then do the color-channel averages in non-premultiplied space. E.g., to render cross-fade(rgb(255 0 0 / 1) 40%, rgb(0 255 0 / .5) 20%, rgb(0 0 255 / 0) 40%), rebalancing the percentages according to the 1 / .5 / 0 alphas would produce 40% / 10% / 0% (which renormalizes to 80% / 20% / 0%), at which point you can average the raw color channel values and end up with an rgb(204 51 0 / .5) image. (Note that the alpha channel is still averaged using the original percentages, not the rebalanced ones.)
-
Return final image.
2.6.3. Simplifying Complex cross-fade()
Per WG resolution, define a notion of "equality" for images, and combine "same" images at computed-value time, summing their percentages.
Per WG resolution, simplify directly-nested cross-fade() at computed-value time by just distributing the percentage and flattening; cross-fade(A 10%, cross-fade(B 30%, C 70%) 90%) becomes cross-fade(A 10%, B 27%, C 63%).
2.7. Using Elements as Images: the element() notation
The element() function allows an author to use an element in the document as an image. As the referenced element changes appearance, the image changes as well. This can be used, for example, to create live previews of the next/previous slide in a slideshow, or to reference a canvas element for a fancy generated gradient or even an animated background.
Note: The element() function only reproduces the appearance of the referenced element, not the actual content and its structure. Authors should only use this for decorative purposes, and must not use element() to reproduce an element with significant content across the page. Instead, just insert multiple copies of the element into the document.
The syntax for element() is:
element () =element ( <id-selector>)
where <id-selector> is an ID selector [SELECT].
Do we need to be able to refer to elements in external documents (such as SVG paint servers)? Or is it enough to just use url() for this?
This name conflicts with a somewhat similar function in GCPM. This needs to be resolved somehow.
Want the ability to do "reflections" of an element, either as a background-image on the element or in a pseudo-element. This needs to be specially-handled to avoid triggering the cy