Refractive

Refractive glass effects for React components

TypeScriptBeta↓ 21.1k

Introduction

Refractive is a higher-order React component that adds refractive glass effects via SVG filters and backdrop-filter.

Motivation

Achieving refractive lighting effects that are realistic, performant, or cross-browser compatible is today a difficult challenge. Achieving all of these things simultaneously, while providing graceful fallbacks to stylistically similar alternatives where otherwise unsupported, is unheard of. The goal of the refractive library is to enable exactly this.

Filter components

Two <Filter> components can be found in the refractive library, to create the SVG filter that provides the refractive effect to components.

  1. lib/filter.tsx: Calculates an image for the whole displacement map and specular. This is useful for components like Switch and Slider, where refractive parts are fixed-size.
  2. lib/flexible-filter.tsx: Calculates the same images, but splits them into multiple tiles, to cover larger areas. This is useful for components like Card and Modal, where refractive parts can be large and dynamic in size.

Presently all image calculation is performed client-side, and not cached. Furthermore, every component instantiates its own <Filter> component. This may be optimized in the future, including by generating these images at build-time and proactively caching them.

Filter image splitting

A flexible filter system splits images into nine parts to handle dynamic sizing while preserving corner details. This approach allows corners to maintain their shape while middle sections can stretch to accommodate any size content.

Current status

Limitations

The refractive package is in early beta, and various known limitations exist in the current published version:

  • backdrop-filter with SVG filters, used as the primary mechanism for rendering refractive effects, is currently only supported by Chrome. Bug reports in Firefox and Safari can be used to track support in other browsers.
  • BezelWidth needs to be lower than the Radius property. This requires rework of the displacement map generation logic.
  • CSS variables do not control the SVG Filter properties, which makes it hard to create dynamic components with different sizes and keep everything in sync. This could be achieved using watchers on CSS variables, although such an approach is heavy-handed.

Fallbacks

Unsupported browsers

For now, only Chrome supports the CSS features required to render "true" refraction. In all other cases, graceful fallback mechanisms are needed for providing commensurate, or at least visually comparable, user experiences.

No single solution exists for achieving this, as fallbacks vary depending on the specific component in question and its usage context. However, the following general strategies may be used:

  1. Use classical Gaussian blur for background blurring instead of the refraction effect.
  2. Use progressive Gaussian blur, where the blur increases with the distance from the center of the component. This can be achieved using multiple layers of Gaussian blur, along with gradient-based masking. It can be slow, particularly on Safari, so it should be used with caution.
  3. Use a solid color or gradient background.

User preferences

Whether for personal preference, accessibility, or performance reasons, offering users the option of whether or not to employ refractive-style lighting effects, or transparency in general, may be desirable.

Where practical and appropriate, users should be provided with a preferences toggle or slider in an application's appearance settings enabling them to switch between fully refractive ("Liquid Glass") and fallback designs.

Credits

The Refractive library is being primarily developed by Chris Feijoo at HASH.

See Liquid Glass in the Browser: Refraction with CSS and SVG for an introduction to the original research that led to this library's creation.