Color fonts are a real thing. However...
... Support for OpenType SVG fonts in browsers is in active development, with all the caveats that apply to such functionality - see the caniuse site for current details.
This demo does not use color font technology, nor does it attempt to replicate color font functionality. Instead it demonstrates a proof-of-concept application of color design and animation to any text on the web page, typically in HTML header elements, through the use of Scrawl-canvas snippet modules.
Scrawl-canvas font snippets
The snippets in this demo allow developers to apply color, distortion and animation effects to HTML header text blocks. Each header element can personalize the snippet effect applied to it using CSS custom properties, meaning each snippet can create a range of different effects.
Heads up! This technique uses Scrawl-canvas snippet modules, which are experimental. Depending on the header size, and the complexity of the pattern design and animation effect, the technique may lead to heavy computation which can result in excessive power use and slower screen refresh rates.
Note that this demo includes many header examples. The more headers that the snippets get applied to, the longer the initial computation takes, which can lead to a delay to the effects appearing on the page - resulting in an unfortunate FOUT (flash of unstyled text).
Use snippets sparingly!
DOM text and canvas text: These snippets work by matching the font characteristics of the DOM headers and recreating the text in a <canvas> element added inside the header element (progressive enhancement). For accessibility and user experience purposes the DOM text is not removed: users should be able to copy/paste the header text as normal. Users who disable Javascript in their devices should still be able to see the normal, CSS styled header text.
Accessibility controls and checks include:
- For animated font effects, the snippets will attempt to add a navigable play|pause control button in the top-right corner of the header element
- For users who have set the prefers-reduced-motion: reduced feature on their devices, animated font effects will only play after the user clicks the Play|Pause control
- For users who have set the prefers-color-scheme: dark feature on their devices, the font effect will display using dark-mode colors (if they have been set)
- For users who have set the new prefers-contrast: more feature on their devices, the font effect will not display
Details on how to apply these Scrawl-canvas snippets to DOM elements can be found at the end of this page. The following CSS is common to all the examples:
CSS:
body {
color: black;
background-color: transparent;
@media (prefers-color-scheme: dark) {
color: white;
background-color: black;
}
}
main {
width: 100%;
max-width: 60em;
margin: 0 auto;
text-align: left;
}
.demo-header {
font-size: 2rem;
line-height: 1.15;
border: 0;
margin: 0;
-webkit-hyphens: none;
-ms-hyphens: none;
hyphens: none;
min-height: 1em;
caret-color: black;
background-color: transparent;
font-weight: normal;
@media (prefers-color-scheme: dark) {
caret-color: white;
}
@media (min-width: 30em) {
font-size: 3rem;
}
@media (min-width: 40em) {
font-size: 4rem;
}
@media (min-width: 50em) {
font-size: 5rem;
}
}
To note: Javascript is not running in this browser environment. Our apologies, but this demo has not yet been updated to support progressive enhancement.
risograph-text-gradient-snippet
This effect is inspired by Risograph printing which uses a limited color palette, stippling colors to create a gradient effect.
The snippet can be customised using the following --data-??? CSS custom properties:
- --data-top-color - any CSS color string (default: lightblue)
- --data-bottom-color - any CSS color string (default: blue)
- --data-outline-color - any CSS color string (default: black)
- --data-outline-width - (unit % of font size) outline width as a percentage of the font size (default: 0.04)
- --data-random-radius - (0 - 1) the amount of mixing of the top and bottom colors (default: 0.8)
- --data-random-level - (0 - 1) the density of the color mixing (default: 1)
... And for prefers-color-scheme: dark users:
- --data-dark-top-color - any CSS color string (default: #d7e3f5)
- --data-dark-bottom-color - any CSS color string (default: #598ad9)
- --data-dark-outline-color - any CSS color string (default: #f4f5d7)
This snippet reacts to the user preference prefers-contrast: more with the following properties:
- --data-contrast-color - any CSS color string (default: black)
- --data-dark-contrast-color - any CSS color string (default: white)
Risograph effect - default values
CSS:
.header-font-sans {
font-family: sans-serif;
--data-line-adjustment: 2;
& u {
--SC-include-underline: true;
--SC-underline-offset: 0.84;
--SC-underline-width: 3;
--SC-underline-gap: 4;
@media (min-width: 30em) {
--SC-underline-offset: 0.85;
--SC-underline-width: 4.5;
--SC-underline-gap: 5;
}
@media (min-width: 40em) {
--SC-underline-offset: 0.85;
--SC-underline-width: 6;
--SC-underline-gap: 8;
}
@media (min-width: 50em) {
--SC-underline-offset: 0.86;
--SC-underline-width: 8;
--SC-underline-gap: 10;
}
}
}
HTML:
<h4
id="header-test-1"
class="demo-header header-font-sans risograph-header"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
To note: this is a proof-of-concept demo test - do not use this sort of code in production!
Normally we don't need to care about EnhancedLabel text matching up exactly with HTML text - even in Scrawl-canvas (highly experimental!) snippet code. But in this Demo we're deliberately adding snippets to contenteditable DOM elements, to see if we can match EL text to DOM text. Clicking in each header will reveal the DOM text as a translucent gray over the EL text, so we can compare their relative positioning.
For the most part, horizontal alignment (along the line) appears to be excellent across Chrome/Safari (and Firefox - though that browser doesn't seem to like contenteditable elements with child canvas elements very much). Vertical alignment of the lines of text, however, appears very problematic: experimentation indicates that browsers position lines depending on individual font characteristics and CSS line-height values for the header element.
This demo attempts to fix this by including a CSS custom property - --data-line-adjustment - which we can add to the CSS font declaration to adjust the EL's vertical alignment to match (as closely as possible) the DOM header's text. (Even with this fix, Firefox appears to stamp the canvas text higher than the other browsers, which has a knock-on effect on each snippet's graphical effect.) But this is not a good fix for anything beyond experimentation and/or personal projects.
Risograph effect - variant 1
CSS:
.header-font-serif {
font-family: serif;
--data-line-adjustment: 0;
& u {
--SC-include-underline: true;
--SC-underline-offset: 0.84;
--SC-underline-width: 3;
--SC-underline-gap: 4;
@media (min-width: 30em) {
--SC-underline-offset: 0.85;
--SC-underline-width: 4.5;
--SC-underline-gap: 5;
}
@media (min-width: 40em) {
--SC-underline-offset: 0.85;
--SC-underline-width: 6;
--SC-underline-gap: 8;
}
@media (min-width: 50em) {
--SC-underline-offset: 0.86;
--SC-underline-width: 8;
--SC-underline-gap: 10;
}
}
}
.risograph-v1 {
--data-random-radius: 0.15;
--data-outline-width: 0.08;
--data-top-color: red;
--data-bottom-color: black;
--data-outline-color: gold;
--data-dark-top-color: red;
--data-dark-bottom-color: white;
--data-dark-outline-color: gold;
}
HTML:
<h4
id="header-test-2"
class="demo-header header-font-serif risograph-header risograph-v1"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
worley-text-gradient-snippet
Worley noise is a form of procedural texture which can be generated and used to simulate textures which look (a bit) like stone, water or biological cells.
The snippet can be customised using the following --data-??? CSS custom properties:
- --data-base-color - any CSS color string (default: black)
- --data-highlight-color - any CSS color string (default: orange)
- --data-noise-sum-function - permitted values include: 'none', 'sine-x', 'sine-y', 'sine', 'modular', 'random' (default: random)
- --data-noise-scale - (+number) a form of zoom level (default: 50)
- --data-noise-output - permitted values include: 'X', 'YminusX', 'ZminusX' etc (default: X)
- --data-shadow-color - any CSS color string, for the text shadow (default: black)
- --data-shadow-offset-x - (number px) percentage of the font size to offset the text shadow horizontally (default: 0)
- --data-shadow-offset-y - (number px) percentage of the font size to offset the text shadow vertically (default: 0)
- --data-shadow-blur - (number px) percentage of the font size to blur the shadow (default: 0)
... And for prefers-color-scheme: dark users:
- data-dark-base-color - any CSS color string (default: white)
- data-dark-highlight-color - any CSS color string (default: orange)
- data-dark-shadow-color - any CSS color string, for the text shadow (default: white)
This snippet reacts to the user preference prefers-contrast: more with the following properties:
- data-contrast-color - any CSS color string (default: black)
- data-dark-contrast-color - any CSS color string (default: white)
Scrawl-canvas supports several types of noise generation, including Worley noise - see Demo canvas-052.
Worley effect - default
CSS:
.header-font-cursive {
font-family: cursive;
--data-line-adjustment: -22;
& u {
--SC-include-underline: true;
--SC-underline-offset: 0.75;
--SC-underline-width: 3;
--SC-underline-gap: 4;
@media (min-width: 30em) {
--SC-underline-width: 4.5;
--SC-underline-gap: 5;
}
@media (min-width: 40em) {
--SC-underline-width: 6;
--SC-underline-gap: 8;
}
@media (min-width: 50em) {
--SC-underline-width: 8;
--SC-underline-gap: 10;
}
}
}
HTML:
<h4
id="header-test-3"
class="demo-header header-font-cursive worley-header"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
To note: this doesn't work so well with the default cursive font in any of the major browsers, with the text being offset downwards thus cutting off the bottom of the last line of the text.
Worley effect - variant 1
CSS:
.justify-center-test {
text-align: center;
}
.worley-v1 {
--data-highlight-color: red;
--data-shadow-color: slategray;
--data-dark-highlight-color: red;
--data-dark-shadow-color: lightslategray;
--data-shadow-offset-x: 2;
--data-shadow-offset-y: 2;
--data-shadow-blur: 1;
--data-noise-scale: 40;
--data-noise-sum-function: none;
}
HTML:
<h4
id="header-test-4"
class="demo-header header-font-sans justify-center-test worley-header worley-v1"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Scrawl-canvas EnhancedLabel entity text can be justified within its template's dimensions; these text snippets will pick up and apply the header block text-align property.
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
Worley effect - variant 2
CSS:
.header-font-bungee {
font-family: Bungee;
--data-line-adjustment: 9;
@media (min-width: 30em) {
font-size: 2.7rem;
}
@media (min-width: 40em) {
font-size: 3.4rem;
}
@media (min-width: 50em) {
font-size: 4.1rem;
}
& u {
--SC-include-underline: true;
--SC-underline-offset: 0.94;
--SC-underline-width: 3;
--SC-underline-gap: 4;
@media (min-width: 30em) {
--SC-underline-width: 4.5;
--SC-underline-gap: 5;
}
@media (min-width: 40em) {
--SC-underline-width: 6;
--SC-underline-gap: 8;
}
@media (min-width: 50em) {
--SC-underline-width: 8;
--SC-underline-gap: 10;
}
}
}
.justify-right-test {
text-align: right;
}
.worley-v2 {
--data-base-color: white;
--data-dark-base-color: white;
--data-highlight-color: #0760f7;
--data-dark-highlight-color: #74c0f2;
--data-noise-sum-function: none;
--data-noise-output: YminusX;
--data-noise-scale: 45;
--data-contrast-color: darkred;
--data-dark-contrast-color: pink;
}
HTML:
<h4
id="header-test-5"
class="demo-header header-font-bungee justify-right-test worley-header worley-v2"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
To note: some fonts insist on pushing parts of their italicised text at the start/end of a line beyond the box. Annoying, but beyond the scope of this Demo to fix.
animated-highlight-gradient-text-snippet
A simple gradient effect using two colors, spaced along the gradient to make a series of bars. The gradient animates downwards in a repeating pattern.
The snippet can be customised using the following --data-??? CSS custom properties:
- --data-main-color - any CSS color string (default: black)
- --data-highlight-color - any CSS color string (default: lightgreen)
- --data-gradient-easing - (string) easing function, for example: 'linear', 'easeOutIn3', etc (default: linear)
- --data-gradient-skew-x - (-2 - 2) skew the gradient pattern horizontally (default: 0)
- --data-gradient-skew-y - (-2 - 2) skew the gradient pattern vertically (default: 0)
- --data-gradient-stretch-x - (0 - 4) stretch the gradient pattern horizontally (default: 1)
- --data-gradient-stretch-y - (0 - 4) stretch the gradient pattern vertically (default: 1)
... And for prefers-color-scheme: dark users:
- --data-dark-main-color - any CSS color string (default: ivory)
- --data-dark-highlight-color - any CSS color string (default: darkgreen)
This snippet reacts to the user preference prefers-contrast: more with the following properties:
- --data-contrast-color - any CSS color string (default: black)
- --data-dark-contrast-color - any CSS color string (default: white)
Animated highlight gradient effect - default
CSS:
.letter-space-px-test {
letter-spacing: 4px;
}
HTML:
<h4
id="header-test-6"
class="demo-header header-font-sans letter-space-px-test highlight-gradient-header"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Scrawl-canvas EnhancedLabel entitys include letter spacing functionality; these text snippets will use any CSS letter-spacing property value applied to the header element.
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
Animated highlight gradient effect - variant 1
CSS:
.letter-space-em-test {
letter-spacing: 0.2em;
}
.highlight-gradient-v1 {
--data-main-color: black;
--data-dark-main-color: #faf1d4;
--data-highlight-color: orange;
--data-dark-highlight-color: #e6a315;
--data-gradient-easing: easeInOut;
}
HTML:
<h4
id="header-test-7"
class="demo-header header-font-serif letter-space-em-test highlight-gradient-v1 highlight-gradient-header"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Scrawl-canvas supports eased linear gradients.
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
Animated highlight gradient effect - variant 2
CSS:
.highlight-gradient-v2 {
--data-main-color: lch(29.2345% 44.2 27);
--data-dark-main-color: #5eadd1;
--data-highlight-color: lab(52.2345% 40.1645 59.9971);
--data-dark-highlight-color: #c5d6fc;
--data-contrast-color: darkred;
--data-dark-contrast-color: pink;
--data-gradient-skew-x: -1;
--data-gradient-easing: easeOutIn;
}
HTML:
<h4
id="header-test-8"
class="demo-header header-font-bungee highlight-gradient-header highlight-gradient-v2"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Scrawl-canvas supports the use of LAB|LCH and the new OKLAB|OKLCH color strings.
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
bubbles-text-snippet
An animation effect that shows bubbles appearing, rising and expanding inside the text.
The snippet can be customised using the following --data-??? CSS custom properties:
- --data-text-color - any CSS color string (default: #c213bc)
- --data-outline-color - any CSS color string (default: #f59dcf)
- --data-outline-width - (unit % of font size) percentage of the font size for text outline width (default: 0.05)
- --data-bubble-color - any CSS color string (default: #fcdeef)
- --data-bubble-outline-color - any CSS color string (default: #c213bc)
- --data-bubble-density - the number of bubbles to generate (default: 50)
... And for prefers-color-scheme: dark users:
- --data-dark-text-color - any CSS color string (default: #fcdeef)
- --data-dark-outline-color - any CSS color string (default: #f59dcf)
- --data-dark-bubble-color - any CSS color string (default: #ed5fb0)
- --data-dark-bubble-outline-color - any CSS color string (default: #c213bc)
This snippet reacts to the user preference prefers-contrast: more with the following data- attributes:
- --data-contrast-color - any CSS color string (default: black)
- --data-dark-contrast-color - any CSS color string (default: white)
Bubbles text effect - default values
CSS:
.header-font-carter-one {
font-family: 'Carter One';
--data-line-adjustment: -18;
& u {
--SC-include-underline: true;
--SC-underline-offset: 0.78;
--SC-underline-width: 3;
--SC-underline-gap: 4;
@media (min-width: 30em) {
--SC-underline-width: 4;
--SC-underline-gap: 6;
}
@media (min-width: 40em) {
--SC-underline-width: 5;
--SC-underline-gap: 8;
}
@media (min-width: 50em) {
--SC-underline-width: 6;
--SC-underline-gap: 10;
}
}
}
HTML:
<h4
id="header-test-9"
class="demo-header header-font-carter-one bubbles-text-header"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
Bubbles text effect - variant 1
CSS:
.bubbles-text-v1 {
--data-text-color: white;
--data-outline-color: black;
--data-bubble-color: green;
--data-bubble-outline-color: gold;
--data-dark-text-color: black;
--data-dark-outline-color: white;
--data-dark-bubble-color: lightgreen;
--data-dark-bubble-outline-color: gold;
--data-bubble-density: 150;
--data-contrast-color: darkred;
--data-dark-contrast-color: pink;
}
HTML:
<h4
id="header-test-10"
class="demo-header header-font-carter-one bubbles-text-header bubbles-text-v1"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
swirling-stripes-text-snippet
A striped 2-color gradient effect. Animation occurs when the user hovers their browser cursor over the header, which leads to a swirl filter being applied to the text.
The snippet can be customised using the following --data-??? CSS custom properties:
- --data-main-color - any CSS color string (default: black)
- --data-stripe-color - any CSS color string (default: red)
- --data-stripe-ratio - (0 - 1) the ratio of stripe to main color; higher values show wider stripes (default: 0.5)
- --data-swirl-angle - (degrees) higher values lead to a tighter swirl; use negative values to reverse the swirl direction (default: 90)
- --data-pattern-skew-x - (-2 - 2) skew the pattern horizontally (default: -1)
- --data-pattern-skew-y - (-2 - 2) skew the pattern vertically (default: 0.5)
- --data-pattern-stretch-x - (0 - 4) stretch the pattern horizontally (default: 1)
- --data-pattern-stretch-y - (0 - 4) stretch the pattern vertically (default: 1)
... And for prefers-color-scheme: dark users:
- --data-dark-main-color - any CSS color string (default: yellow)
- --data-dark-stripe-color - any CSS color string (default: red)
This snippet makes no attempt to react to the prefers-contrast user preference.
Swirling stripes effect - default (animated)
HTML:
<h4
id="header-test-11"
class="demo-header header-font-sans swirling-stripes-header"
contenteditable="plaintext-only"
>
Lorem ipsum dolor <i>sit amet</i> <b>consectetur</b> <u>adipiscing elit</u> magna aliqua
</h4>
Lorem ipsum dolor sit amet consectetur adipiscing elit magna aliqua
Applying a Scrawl-canvas snippet to HTML header elements
HTML elements
- id="this-header-unique-name" - if applying a snippet to an HTML element, that element needs to be given a unique id value
- class="arbitrary-name" - we can use any CSS selector value to apply a snippet to HTML elements matching that selector
- contenteditable="plaintext-only" - useful during development to make sure canvas and HTML text match up as closely as possible
CSS markup
It turns out that underlining text is really difficult. Scrawl-canvas EnhancedLabel entitys have functionality to apply underline, overline and background highlight text decoration to their text units ... but to get to that stage, we need to add some Scrawl-canvas-unique custom properties to the CSS code to get the underline to appear as we want it in the EL's displayed text:
- --SC-include-underline - needs to be set to true if we want the text using the CSS block in which it appears to display an underline decoration
- --SC-underline-offset - the top position of the underline, relative to the text's line height: 0 puts the underline at the top; 1 adds it at the bottom. Values can be less than 0.0 and greater than 1.0
- --SC-underline-width - the underline's depth (in pixels, though use the value 5, not 5px)
- --SC-underline-gap - underline styling leaves a gap between the text's descender lines and the underline - as seen in, for example, g p q y . Again, this value measures pixels, but only accepts number values.
Using snippets: We apply Scrawl-canvas snippets to HTML elements using Javascript:
JS:
import * as scrawl from 'path/to/scrawl-canvas/library';
import myFontEffect from './path/to/required-SC-header-snippet.js';
const headers = document.querySelectorAll('.arbitrary-name');
headers.forEach(el => myFontEffect(scrawl, el));
Testing the responsiveness of the snippets: all the examples have been set up with media queries to change font size in line with browser's viewport width.