and to change slides. 2 for comments.


Due to CanIUse quirks, please click on headers that read "Browser support:" to load caniuse

CSS Images

CSS <image> functions

  • url() function
  • Gradients
  • cross-fade() function
  • element() function
  • image() function
  • image-set() function
  • paint() function - a.k.a. Houdini

<image> functions

<image> functions

linear-gradient(blue, red)
radial-gradient(blue, red)
conic-gradient(blue, red)
repeating-linear-gradient(blue, red 20%)
repeating-radial-gradient(blue, red 20%)
repeating-conic-gradient(blue, red 20%)
cross-fade(url(twenty.png) 20%, url(eighty.png)) 
image(ltr 'arrow.png#xywh=0,0,16,16', red) 
image-set('test.jpg' 1x, 'test-2x.jpg' 2x)

Where <image> is used.

symbols: /* for @counter-style */
content:  /* for ::after and ::before pseudo elements (/)

Default image sizes

Some images have default sizes when used:

Kind of Object (CSS Property) Default object size
background-image The size of the element's background positioning area
list-style-image The size of a 1em character
border-image-source The size of the element's border image area
cursor* The browser-defined size matching the usual cursor size on the client's system
symbols for @counter-style The usual cursor size on the client's system
content for a pseudo-element (::after/::before) A 300px × 150px rectangle

The cursor takes an url() with an .cur file, but no other type of image.


url() function

The url() function for images works wherever the image value works. It is the only global image function right now.

background-image: url("");
list-style-image: url('../images/bullet.jpg');
content: url("pdficon.jpg");
border-image-source: url(/media/diamonds.png);
mask-image: url("masks.svg#mask1");

The url() function is not just for images

cursor: url(mycursor.cur);
src: url('fantasticfont.woff');
offset-path: url(#path);

url() values





url("data:image/svg+xml;utf8,<svg xmlns='' width='220' height='200'><circle cx='55' cy='190' r='25' fill='#FFF' />^lt;path d='M160 213h-34a82 82 0 0 0 -82 -82v-34a116 116 0 0 1 116 116z' fill='#666'/><path d='M184 213A140 140 0 0 0 44 73 V 38a175 175 0 0 1 175 175z' fill='#666'/></svg>"); SVG Example

Media fragment will not break backwards... hash will be ignored

url() Example

Gradient Functions


They get their own chapter

6 Gradient Types

  • linear-gradient();
  • radial-gradient();
  • conic-gradient();
  • repeating-linear-gradient()
  • repeating-radial-gradient()
  • repeating-conic-gradient()


cross-fade() function

Used to blend two or more images at a defined transparency.

cross-fade( [<percentage>? && [ <image> | <color> ] ]# )

the cross-fade() image function takes other image functions as a parameter

cross-fade(40% url(image1.jpg), 
           30% url(image2.jpg), 
           35% url(image3.jpg))

If any %s are omitted, the missing split the difference up to a total of 100%.

This syntax is not yet supported anywhere.

cross-fade() Example

Browser support: cross-fade() image value



element() function

Defines an <image> value generated from an HTML element. Allows the use of any element, including <canvas> anywhere CSS images can be used (since FF4).


Pass the ID of an element

background-image: -moz-element('#someID');
background-image: element('#someID')

This image is live: if the HTML changes, the image is automatically updated.

Works prefixed. In FF only

element() Example

element() Example


image() function

Not supported anywhere yet!

Similar to url() but with additional features, including directionality, fallback image, fallback color, and image fragments.

image( <direction>? [ <image-src>? , <color>? ]! )
Optional, either ltr or rtl
Zero or more <url>s or <string>s specifying the image sources, with optional image fragment identifiers. image(sprite.png#xywh=40,0,20,20);
Optional solid color fallback.
image("sprite.webp#xywh=0,20,40,60", red);
image(ltr 'leftarrow.png');

More on image()

Define which portion of the image to show:

    -moz-image-rect(url(ico_sprite.jpg), 32, 64, 16, 16);
background-image: image('ico_sprite.jpg#xywh=32,64,16,16')

Fallback in case your images doesn't load:

     image("try1.svg", "try2.png", "try3.gif", blue)

Flip the image if the direction is rtl.

background-image: image("arrow.png" rtl)


image-set() function

Provide a set of images and information, allowing the browser to pick the most appropriate option.

image-set( <image> <resolution># ) 

General goal is serving high resolution images.

background-image: image-set( "cat.png" 1x,
   "cat-2x.png" 2x,
   "cat-print.png" 600dpi);
  • Resolution in x or dppx, dpi, or dpcm
  • Every image within an image-set() must have a unique resolution.
  • Can not be nested inside another image-set() function.

Browser support: image-set() image value



a.k.a. “Houdini”

paint() function

Enables pulling in JavaScript drawing directly into an element's background, border, or content.

background-image: paint(myJSDrawing);

To programmatically create a CSS image with JavaScript:

  1. Define a paint worklet using the registerPaint() function
  2. Register the worklet
  3. Include the paint() CSS function

Has to be over HTTPS!!

A JS Worklet

registerPaint('nameOfMyworklet', class {
  // use this function to retrieve any custom props defined for the element, 
  // return them in the specified array
  static get inputProperties() { return ['--myColor']; }

  // Input arguments that can be passed to the `paint` function
  // static get inputArguments() { return ['']; }
  // Whether Alpha is allowed? - This is set to true by default, 
  // if it is set to false all colours used on the canvas will have full opacity, or alpha of 1.0
  static get contextOptions() { return {alpha: true}; }

  paint(ctx, size, props) {
    // ctx -> drawing context
    // size -> size of the box being painted
    // props -> list of custom properties available to the element

    // set where to start the highlight & dimensions
    const x = 0;
    const y = size.height * 0.3;
    const blockWidth = size.width * 0.33;
    const highlightHeight = size.height * 0.85;

    // Paint uses Typed OM to retireve the custom property 
    // value, so we have to use the get method on it
    ctx.fillStyle = props.get( '--myColor' );

    // block
    ctx.moveTo( x, y);
    ctx.lineTo( blockWidth, y );
    ctx.lineTo( blockWidth + highlightHeight, highlightHeight );
    ctx.lineTo( x, highlightHeight );
    ctx.lineTo( x, y );
    // dashes
    for ( let i = 0; i < 4; i++ ) {
      let start = i * 2;
      ctx.moveTo( ( blockWidth ) + ( start * 10 ) + 10, y );
      ctx.lineTo( ( blockWidth ) + ( start * 10 ) + 20, y );
      ctx.lineTo( ( blockWidth ) + ( start * 10 ) + 20 + (highlightHeight ), highlightHeight );
      ctx.lineTo( ( blockWidth ) + (start * 10 ) + 10 + ( highlightHeight ), highlightHeight );
      ctx.lineTo( ( blockWidth ) + ( start * 10 ) + 10, y );
  } // paint

Register the worklet

Add the module, or "register" the worklet


Now it can be referenced with the paint() function with the name of the worklet

 element {
  background-image: paint(nameOfMyworklet);
h1 { --myColor: hsla(155, 90%, 60%, 0.7); }
h3 { --myColor: hsla(255, 90%, 60%, 0.5); }
h6 { --myColor: hsla(355, 90%, 60%, 0.3); }

CSS Painting API

This is a header

This is a heading level 3 with more text than the h1

Hello H6

Browser support: paint() image value



Next ➹