Title: CSS Images Module Level 4
Status: WD
Work Status: Exploring
Shortname: css-images
Level: 4
Group: csswg
ED: https://drafts.csswg.org/css-images-4/
TR: https://www.w3.org/TR/css-images-4/
Editor: Tab Atkins Jr., Google, http://xanthir.com/contact/, w3cid 42199
Editor: Elika J. Etemad / fantasai, Apple, http://fantasai.inkedblade.net/contact, w3cid 35400
Editor: Lea Verou, Invited Expert, http://lea.verou.me/about, w3cid 52258
Abstract: This module contains the features of CSS level 4 relating to the <> type and replaced elements.
It includes and extends the functionality of CSS level 2 [[CSS2]] and in the previous level of this specification [[css-images-3]].
The main extensions compared to "CSS Images Module Level 3" [[css-images-3]] are several additions to the <> type, such as the ''image()'' notation, the ''element()'' notation, and conic gradients.
This level is currently maintained as a diff spec over the level 3 module.
!Delta Spec: yes
Issue Tracking: Tracker http://www.w3.org/Style/CSS/Tracker/products/27
Previous Version: https://www.w3.org/TR/2017/WD-css-images-4-20170413/
Ignored Terms: , background positioning area, border image area, , Map, , invalid image, invalid images, concrete object size, linear-gradient(), radial-gradient(), default object size, CSS
Ignored Vars: H, P
Include Can I Use Panels: yes
Default Highlight: css
Complain About: missing-example-ids true
WPT Path Prefix: css/css-images/
WPT Display: open
spec: css-color-4; type: type; text:
Introduction {#intro}
=====================
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.
Value Definitions {#values}
---------------------------
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.
2D Image Values: the <> type {#image-values}
===================================================
The <> value type denotes a 2D image. It can be a
url reference,
image notation,
or gradient notation.
Its syntax is:
<image> = <> | <> | <> | <> | <> | <>
An <> can be used in many CSS properties,
including the 'background-image', 'list-style-image', 'cursor' properties [[!CSS2]]
(where it replaces the <> component in the property's value).
In some cases an image is invalid,
such as a <> 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 ''list-style-type/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 value|computed=] <> value
is the [=specified value=]
with any <>s, <>s, and <>s computed.
Image File Formats {#image-file-formats}
----------------------------------------
At minimum, the UA must support the following image file formats
when referenced from an <> value,
for all the properties in which using <> 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 <>s,
SVG, as specified in [[!SVG11]],
using the secure animated mode (See [[!SVG-INTEGRATION]])
The UA may support other file formats as well.
Image References: the ''url()'' notation {#url-notation}
--------------------------------------------------------
Note: No change from [[css-images-3]].
Fetching External Images {#fetching-images}
-------------------------------------------
To fetch an external image for a stylesheet,
given a <> |url| and a [=CSS style declaration=] |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.
Resolution/Type Negotiation: the ''image-set()'' notation {#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.
Issue: 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:
Issue: We should add "w" and "h" dimensions as a possibility
to match the functionality of HTML's picture.
Each <> inside ''image-set()'' represents a <>.
The ''image-set()'' function can not be nested inside of itself,
either directly
or indirectly
(as an argument to another <> type).
Each <> 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 <> (optional).
This is used to help the UA decide which <> 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 <> 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( <> ) function (optional),
specifying the image's MIME type in the <>.
If the <>,
when parsed as a [=valid MIME type string=],
is either not valid,
or is valid but doesn't specify a supported image format,
the <> 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 <> like url("picture.png") 1x type("image/jpeg") is valid,
and if chosen will display the linked PNG image,
even though it was declared to be a JPEG.
If not specified,
it has no effect on the <>.
image-set/image-set-all-options-invalid.html
image-set/image-set-calc-x-rendering-2.html
image-set/image-set-calc-x-rendering.html
image-set/image-set-computed.sub.html
image-set/image-set-conic-gradient-rendering.html
image-set/image-set-content-rendering.html
image-set/image-set-dpcm-rendering.html
image-set/image-set-dpi-rendering-2.html
image-set/image-set-dpi-rendering.html
image-set/image-set-dppx-rendering.html
image-set/image-set-empty-url-rendering.html
image-set/image-set-first-match-rendering.html
image-set/image-set-linear-gradient-rendering.html
image-set/image-set-negative-resolution-rendering-2.html
image-set/image-set-negative-resolution-rendering-3.html
image-set/image-set-negative-resolution-rendering.html
image-set/image-set-no-res-rendering-2.html
image-set/image-set-no-res-rendering.html
image-set/image-set-no-url-rendering.html
image-set/image-set-parsing.html
image-set/image-set-radial-gradient-rendering.html
image-set/image-set-rendering-2.html
image-set/image-set-rendering.html
image-set/image-set-repeating-conic-gradient-rendering.html
image-set/image-set-repeating-linear-gradient-rendering.html
image-set/image-set-repeating-radial-gradient-rendering.html
image-set/image-set-resolution-001.html
image-set/image-set-resolution-002.html
image-set/image-set-resolution-003.html
image-set/image-set-type-first-match-rendering.html
image-set/image-set-type-rendering-2.html
image-set/image-set-type-rendering-3.html
image-set/image-set-type-rendering.html
image-set/image-set-type-skip-unsupported-rendering.html
image-set/image-set-type-unsupported-rendering-2.html
image-set/image-set-type-unsupported-rendering.html
image-set/image-set-unordered-res-rendering.html
image-set/image-set-zero-resolution-rendering-2.html
image-set/image-set-zero-resolution-rendering.html
An ''image-set()'' function contains a list of one or more <>s,
and must select only one of them
to determine what image it will represent:
1. First, remove any <>s from the list
that specify an unknown or unsupported MIME type in their ''type()'' value.
2. Second, remove any <>s from the list
that have the same <> as a previous option in the list.
3. If there are no <> left at this point,
the function represents an [=invalid image=].
3. Finally, among the remaining <>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).
4. The ''image-set()'' function then represents the <>
of the chosen <>.
UAs may change which <> 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.
This example shows how to use ''image-set()'' to provide an image in three versions:
a "normal" version,
a "high-res" version,
and an extra-high resolution version for use in high-quality printing
(as printers can have extremely high resolution):
This example shows use of the ''type()'' function
to serve multiple versions of the same image
in both new, higher-quality formats,
and older, more widely-supported formats:
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 "image/avif" files),
and so the JPEG is chosen instead.
Raster images can be mixed with vector images,
or even CSS generated images.
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:
Image Fallbacks and Annotations: the ''image()'' notation {#image-notation}
---------------------------------------------------------------------------
The ''image()'' function allows an author to:
* use media fragments to clip out a portion of an image
* use a solid color as an image
* fallback to a solid-color image, when the image at the specified url can't be downloaded or decoded
* automatically respect the image orientation specified in the image's metadata
The ''image()'' notation is defined as:
A <> used in ''image()'' represents a <>.
As usual for URLs in CSS,
relative URLs are resolved to an absolute URL
(as described in Values & Units [[!CSS-VALUES-3]])
when a specified ''image()'' value is computed.
If the image has an orientation specified in its metadata,
such as EXIF,
the UA must rotate or flip the image to correctly orient it
as the metadata specifies.
### Image Fallbacks ### {#image-fallbacks}
If both a URL and a <> are specified in ''image()'',
then whenever the URL represents an [=invalid image=] or [=loading image=],
the ''image()'' function renders as if the URL were not specified at all;
it generates a solid-color image as specified in [[#color-images]].
If just a URL is specified (no <>)
and it represents an [=invalid image=] or [=loading image=],
the ''image()'' function represents the same.
css-image-fallbacks-and-annotations.html
css-image-fallbacks-and-annotations002.html
css-image-fallbacks-and-annotations003.html
css-image-fallbacks-and-annotations004.html
css-image-fallbacks-and-annotations005.html
The fallback color can be used to ensure that text is still readable
even when the image fails to load.
For example, the following legacy code works fine if the image is rectangular and has no transparency:
When the image doesn't load,
the background color is still there to ensure that the white text is readable.
However, if the image has some transparency,
the black will be visible behind it,
which is probably not desired.
The ''image()'' function addresses this:
Now, the black won't show at all if the image loads,
but if for whatever reason the image fails,
it'll pop in and prevent the white text from being set against a white background.
### Image Fragments ### {#image-fragments}
When a URL specified in ''image()'' represents a portion of a resource
(e.g. by the use of media fragment identifiers)
that portion is clipped out of its context and used as a standalone image.
...the background of the element will be the portion of the image that starts at (40px,0px) and is 20px wide and tall,
which is just the circle with a quarter filled in.
So that authors can take advantage of CSS's forwards-compatible parsing rules to provide a fallback for image slices,
implementations that support the ''image()'' notation
must support the xywh=#,#,#,# form of media fragment identifiers
for images specified via ''image()''. [[!MEDIA-FRAGS]]
Note that image fragments can also be used with the ''url()'' notation.
However, a legacy UA that doesn't understand the media fragments notation
will ignore the fragment and simply display the entirety of the image.
Since the ''image()'' notation requires UAs to support media fragments,
authors can take advantage of CSS's forward-compatible parsing rules
to provide a fallback when using an image fragment URL:
background-image: url('swirl.png'); /* old UAs */
background-image: image('sprites.png#xywh=10,30,60,20'); /* new UAs */
If a URL uses a fragment identifier syntax that the implementation does not understand,
or does not consider valid for that type of image,
the URL must be treated as representing an invalid image.
Note: This error-handling is limited to ''image()'',
and not in the definition of URL,
for legacy compat reasons.
### Solid-color Images ### {#color-images}
If the ''image()'' function is specified with only a <> argument (no URL),
it represents a solid-color image of the specified color with no [=natural dimensions=].
For example,
one can use this as a simple way to "tint" a background image,
by overlaying a partially-transparent color over the top of the other image:
'background-color' does not work for this,
as the solid color it generates always lies beneath all the background images.
### Bidi-sensitive Images ### {#bidi-images}
Before listing any <image-src>s,
the author may specify a directionality for the image,
similar to adding a dir attribute to an element in HTML.
If a directional image is used on or in an element with opposite direction,
the image must be flipped in the inline direction
(as if it was transformed by, e.g., scaleX(-1), if the inline direction is the X axis).
Note: Absent this declaration,
images default to no directionality at all,
and thus don't care about the directionality of the surrounding element.
A list may use an arrow for a bullet that points into the content.
If the list can contain both LTR and RTL text,
though, the bullet may be on the left or the right,
and an image designed to point into the text on one side will point out of the text on the other side.
This can be fixed with code like:
<ul style="list-style-image: image(ltr 'arrow.png');">
<li dir='ltr'>My bullet is on the left!</li>
<li dir='rtl'>MY BULLET IS ON THE RIGHT!</li>
</ul>
This should render something like:
⇒ My bullet is on the left!
!THGIR EHT NO SI TELLUB YM ⇐
In LTR list items, the image will be used as-is.
In the RTL list items, however,
it will be flipped in the inline direction,
so it still points into the content.
Combining images: the ''cross-fade()'' notation {#cross-fade-function}
----------------------------------------------------------------------
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:
The function represents an image generated by
combining one or more images.
The <> represents how much of each image is retained
when it is blended with the other images.
The <> 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.
While this is not reflected in the computed value,
when all the arguments’ percentages sum to greater than ''100%'',
the sizing/painting details effectively rescale them so that they sum to exactly ''100%''.
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 <> 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).
cross-fade-basic.html
cross-fade-computed-value.html
cross-fade-legacy-crash.html
cross-fade-legacy-2-crash.html
cross-fade-natural-size.html
cross-fade-premultiplied-alpha.html
cross-fade-target-alpha.html
### ''cross-fade()'' Sizing ### {#cross-fade-sizing}
The dimensions of the image represented by a ''cross-fade()''
are a weighted average of dimensions of the <> arguments to the function;
the <> arguments have no effect.
They are calculated as follows:
To determine the [=natural dimensions=] of a cross-fade():
1. [=Normalize mix percentages=] from the function's arguments,
and let |args| and |leftover| be the result.
2. If |leftover| is 100%,
return no [=natural dimensions=].
3. Let |images| be an empty list.
4. For each <> |argument| of the function's arguments:
1. If |argument| is not an <>,
or is an <> with no natural dimensions,
[=iteration/continue=].
2. Let |item| be a [=tuple=] consisting of a width, a height, and a percentage.
3. Run the [=object size negotiation=] algorithm for the <>,
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=].
4. Set |item|’s percentage to the |argument|’s percentage.
5. If |images| is empty,
return no [=natural dimensions=].
6. 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.
### ''cross-fade()'' Painting ### {#cross-fade-painting}
The image represented by a ''cross-fade()''
is a weighted average of the input arguments to the function,
calculated as follows:
To determine the appearance of a cross-fade():
1. [=Normalize mix percentages=] from the function's arguments,
and let |args| and |leftover| be the result.
1. Let |images| be an empty list.
2. 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()=]).
3. For each |argument| of the ''cross-fade()'' function:
1. Let |item| be a [=tuple=] consisting of an image and a percentage.
2. If |argument| has an <>,
rescale it to |size|’s width and height
and set |item|’s image to the result.
Otherwise, |argument| has a <>;
set |item|’s image to a solid-color image of the <>,
with |size|’s dimensions.
3. Set |item|’s percentage to the |argument|’s percentage.
5. 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|.
6. Let |final image| be an image
with |size|’s dimensions,
and every pixel being the weighted linear average of the corresponding pixels of [=list/for each|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 dissolve operation to the source images.
Wikipedia defines dissolve as 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.)
7. Return |final image|.
### Simplifying Complex ''cross-fade()'' ### {#cross-fade-complex}
Issue: Per WG resolution,
define a notion of "equality" for images,
and combine "same" images at computed-value time,
summing their percentages.
Issue: 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%)''.
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: