
Customizing Multi-Colored Vector Fonts with CSS font-palette
Typography on the web has traditionally been monochromatic, constrained to single-fill outlines rendered by standard OpenType and TrueType font engines. Whenever user interfaces required vibrant duotone iconography, multi-shaded display lettering, or colorful badges, teams were forced to choose between complex inline SVG sprites, multi-layer canvas elements, or multiple stacked font spans positioned with CSS absolute coordinates. The OpenType COLRv1 and CPAL (Color Palette Table) standards modernized vector typography by embedding rich vector paths, paint operations, and multiple predefined color palettes directly into lightweight, scalable WOFF2 font files.
While COLRv1 fonts ship with author-defined color schemes, enterprise design systems require dynamic theming, dark mode transitions, and brand consistency. The CSS Fonts Module Level 4 introduces the font-palette property along with the @font-palette-values at-rule, granting stylesheets complete runtime authority over font color layers. Developers can select built-in vendor palettes using keywords like light or dark, define custom palette overrides mapped to specific layer indices, and wire individual palette indices directly to CSS custom properties to maintain accessible contrast across reactive UI themes.
Example
/* Declaring a custom palette linked to a COLRv1 font */
@font-palette-values --cyberpunk-palette {
font-family: "Nabla";
base-palette: 0;
override-colors:
0 #00f0ff,
1 #ff0077,
2 #7000ff;
}
/* Applying the custom palette to headings */
.hero-title {
font-family: "Nabla", system-ui, sans-serif;
font-palette: --cyberpunk-palette;
font-size: 4rem;
}
Implementation
<!-- HTML Structure -->
<article class="theme-card" data-theme="dark">
<header class="theme-card__header">
<h1 class="theme-card__headline">Modern Vector Palettes</h1>
<span class="theme-card__badge">COLRv1 Enabled</span>
</header>
<p class="theme-card__body">
Notice how both the headline and icon glyphs inherit brand-accurate colors
without loading separate vector images or raster graphics.
</p>
</article>
<style>
/* 1. Define the COLRv1 Color Font */
@font-face {
font-family: "PaletteDisplay";
src: url("/fonts/nabla-colrv1.woff2") format("woff2") tech("color-COLRv1");
font-display: swap;
font-weight: 400;
}
/* 2. Declare Color Palettes using @font-palette-values */
/* Default Light Brand Palette */
@font-palette-values --brand-light {
font-family: "PaletteDisplay";
base-palette: 0;
override-colors:
0 #1e293b, /* Primary shadow/depth */
1 #0ea5e9, /* Mid-tone highlight */
2 #38bdf8, /* Accent gradient fill */
3 #f8fafc; /* Specular highlight */
}
/* High-Contrast Dark Theme Palette */
@font-palette-values --brand-dark {
font-family: "PaletteDisplay";
base-palette: 1;
override-colors:
0 #030712, /* Deep outline */
1 #f43f5e, /* Vibrant brand rose */
2 #fb7185, /* Secondary rose tint */
3 #ffe4e6; /* Bright illumination */
}
/* Dynamic Variable-Driven Palette */
@font-palette-values --brand-dynamic {
font-family: "PaletteDisplay";
base-palette: 0;
override-colors:
0 var(--font-layer-shadow, #0f172a),
1 var(--font-layer-primary, #6366f1),
2 var(--font-layer-secondary, #a855f7);
}
/* 3. Component Styling and Theme Integration */
.theme-card {
--font-layer-shadow: #1e1b4b;
--font-layer-primary: #818cf8;
--font-layer-secondary: #c084fc;
max-width: 640px;
margin: 2rem auto;
padding: 2.5rem;
border-radius: 1rem;
background-color: #0f172a;
color: #e2e8f0;
border: 1px solid #334155;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4);
}
.theme-card__headline {
font-family: "PaletteDisplay", system-ui, sans-serif;
font-size: 3rem;
line-height: 1.1;
margin: 0 0 1rem 0;
/* Apply light palette by default, switch via property */
font-palette: --brand-light;
transition: font-palette 0.3s ease;
}
/* Automatic Dark Mode Adaptation */
@media (prefers-color-scheme: dark) {
.theme-card__headline {
font-palette: --brand-dark;
}
}
/* Explicit data-attribute theming overrides */
[data-theme="custom"] .theme-card__headline {
font-palette: --brand-dynamic;
}
.theme-card__badge {
display: inline-block;
padding: 0.25rem 0.75rem;
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
background-color: rgba(99, 102, 241, 0.15);
color: #a5b4fc;
border-radius: 9999px;
border: 1px solid rgba(99, 102, 241, 0.3);
}
.theme-card__body {
margin-top: 1.25rem;
font-size: 1.125rem;
line-height: 1.6;
color: #94a3b8;
}
</style>
Main Point: The CSS font-palette property and font-palette-values rule unlock full theme customization of COLRv1 color vector fonts directly in stylesheets without requiring SVG assets or font file rebuilds.