How to Use CSS cross-fade() to Blend Backgrounds

The CSS cross-fade() function enables developers to blend two graphical images together at defined opacity levels directly in stylesheets, eliminating the need for pre-rendered image files or stacked HTML elements. This article explains the underlying mechanics of cross-fade(), its syntax, how pixel blending works mathematically, and practical implementation considerations for modern web design.

Understanding the cross-fade() Syntax

The cross-fade() function is used anywhere an <image> value is accepted in CSS, such as within the background-image property. It takes two image sources and a percentage value that determines the balance between them:

.element {
  background-image: cross-fade(url("image-a.jpg"), url("image-b.jpg"), 35%);
}

In this syntax:

  • The first argument is the base image.
  • The second argument is the overlay image.
  • The percentage defines the opacity of the second image. The opacity of the first image automatically becomes 100% - percentage. In the example above, image-b.jpg is displayed at 35% opacity, while image-a.jpg is displayed at 65% opacity.

Earlier browser implementations, particularly WebKit, supported a vendor-prefixed syntax (-webkit-cross-fade()), which accepted a percentage alongside the second image:

.element {
  background-image: -webkit-cross-fade(url("image-a.jpg"), url("image-b.jpg"), 0.35);
}

How the Blending Process Works

The blending performed by cross-fade() operates via linear alpha transparency interpolation. Unlike CSS mix-blend-mode or background-blend-mode, which apply complex blend modes like multiply, screen, or overlay based on color luminance, cross-fade() relies strictly on opacity-based cross-dissolving.

The browser renders the blend using the following sequence:

  1. Geometry Normalization: Both images are scaled according to standard background sizing rules (background-size). If dimensions differ, the images are rendered within the context of the container boundaries.
  2. Channel Interpolation: For every overlapping pixel, the browser calculates the resulting color and alpha channels using the formula: \[\text{Output} = (\text{Pixel}_A \times (1 - p)) + (\text{Pixel}_B \times p)\] where \(p\) is the blend percentage converted to a fraction between 0.0 and 1.0.
  3. Composite Rendering: The calculated pixels are flattened into a single image layer, preventing extra rendering layers from being composited into the DOM tree.

Supported Image Types

The function is not limited to static raster images (such as JPEG or PNG). It accepts any valid CSS <image> data type:

  • CSS Gradients: Linear, radial, or conic gradients can be blended with photographic backgrounds or with other gradients to generate complex surfaces.
  • SVGs: Vector graphics can be combined with bitmap textures.
  • Canvas or Element Sources: Any dynamic CSS image sources can be blended programmatically.
.card {
  background-image: cross-fade(
    url("texture.png"),
    linear-gradient(to right, #3498db, #8e44ad),
    50%
  );
}

Practical Use Cases

  • State Transitions: Animating the percentage value using CSS transitions creates smooth fades between two images on hover or state change without changing DOM elements.
  • Dynamic Theming: Applying a semi-transparent color tint or secondary branding pattern across a standard hero image.
  • Progressive Image Loading: Fading from a low-resolution placeholder to a high-resolution asset without layout shifts.

Implementation Considerations

While cross-fade() provides a clean, single-property solution for image blending, native browser adoption has historically varied. WebKit and Chromium browsers require the -webkit-cross-fade() vendor prefix for legacy compatibility, whereas modern specifications continue to standardize un-prefixed multi-image syntax. When implementing in production, provide a standard fallback background-image for older rendering engines.