Error: Attempting to parse an unsupported color function "color"
I'm using html2canvas
version 1.4.1. I'm not able to render the canvas properly because of the following error:
Error: Attempting to parse an unsupported color function "color"
Seems like color
is not supported, how to fix this?
Solution
There is an open ticket on github to address this issue but still no development has been done.
To fix this, I suggest switching to html2canvas-pro, it's a fork of html2canvas
so it has exactly the same api, but it supports all the modern color libraries like color
, lab
, lch
, oklab
, oklch
.
Alternative #1
I've been dealing with html2canvas color issues, and sometimes switching to a different library isn't an option due to licensing or compatibility concerns. One approach I've found effective is CSS preprocessing to convert modern color functions to supported formats.
Here's a solution using PostCSS with a custom plugin:
// postcss.config.js
module.exports = {
plugins: [
require('postcss-color-function'),
require('postcss-custom-properties'),
{
postcssPlugin: 'html2canvas-color-fix',
Declaration: {
color: (decl) => {
if (decl.value.includes('color(')) {
// Convert color() to rgb() or hex
decl.value = decl.value.replace(
/color\(([^)]+)\)/g,
(match, args) => {
// Convert to a supported format
return `rgb(128, 128, 128)`; // Fallback color
}
);
}
}
}
}
]
};
Or you can use CSS custom properties with fallbacks:
:root {
--modern-color: color(display-p3 0.5 0.5 0.5);
--fallback-color: rgb(128, 128, 128);
}
.element {
color: var(--fallback-color);
color: var(--modern-color); /* Modern browsers */
}
This approach maintains modern color support while providing fallbacks for html2canvas.
Alternative #2
Another approach I've used successfully is runtime CSS manipulation before calling html2canvas. This is especially useful when you can't modify your CSS build process.
Here's a solution that temporarily replaces unsupported color functions:
function prepareForHtml2Canvas(element) {
// Store original styles
const originalStyles = new Map();
// Find all elements with unsupported color functions
const elements = element.querySelectorAll('*');
elements.forEach(el => {
const computedStyle = window.getComputedStyle(el);
const color = computedStyle.color;
const backgroundColor = computedStyle.backgroundColor;
if (color.includes('color(') || backgroundColor.includes('color(')) {
// Store original
originalStyles.set(el, {
color: el.style.color,
backgroundColor: el.style.backgroundColor
});
// Replace with supported colors
if (color.includes('color(')) {
el.style.color = 'rgb(128, 128, 128)'; // Fallback
}
if (backgroundColor.includes('color(')) {
el.style.backgroundColor = 'rgb(240, 240, 240)'; // Fallback
}
}
});
return originalStyles;
}
function restoreStyles(originalStyles) {
originalStyles.forEach((styles, element) => {
if (styles.color) element.style.color = styles.color;
if (styles.backgroundColor) element.style.backgroundColor = styles.backgroundColor;
});
}
// Usage
const originalStyles = prepareForHtml2Canvas(document.getElementById('target'));
html2canvas(document.getElementById('target')).then(canvas => {
restoreStyles(originalStyles);
// Use canvas
});
This approach is more complex but gives you fine-grained control over color replacement.
Alternative #3
If you're using modern frameworks like React or Vue, you might want to consider alternative screenshot libraries that have better support for modern CSS features.
Here are some alternatives I've used:
dom-to-image (React-friendly):
import domtoimage from 'dom-to-image';
domtoimage.toPng(document.getElementById('target'))
.then(function (dataUrl) {
const img = new Image();
img.src = dataUrl;
document.body.appendChild(img);
});
html-to-image (Modern alternative):
import { toPng } from 'html-to-image';
toPng(document.getElementById('target'))
.then(function (dataUrl) {
const link = document.createElement('a');
link.download = 'screenshot.png';
link.href = dataUrl;
link.click();
});
Puppeteer (Server-side rendering):
const puppeteer = require('puppeteer');
async function captureScreenshot(html) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(html);
const screenshot = await page.screenshot();
await browser.close();
return screenshot;
}
These alternatives often have better support for modern CSS features and can be more reliable for production use.