Pastel Paper, Hard Numbers: A Sweet-Shop Gradient Library That Survives Dark Mode
Photo: Sweet Caporal Little Cigars., Public domain, via Wikimedia Commons
Vintage sweet wrappers are a terrible design system and a brilliant colour archive. A pear-drop packet is not a brand guideline; it is a small, crinkled argument about acid green, powder blue and the exact pink of a floral cream. The trouble starts when makers lift those colours straight into a gradient and call it nostalgia. On a bright screen the result can look like a birthday card from 1978 — and read like one too. This is how to turn the sweet-shop counter into a reusable CSS gradient library with tokens, contrast checks and a demo that keeps the charm but loses the kitsch.
Start with the paper, not the sweet
Old wrappers were printed on cheap stock with inks that were never asked to survive a retina display. The paper has yellowed, the cyan has drifted, the magenta has gone shy. That is part of the appeal. But it means you cannot eyedrop a faded wrapper and declare the job done. Treat the wrapper as a mood board, not a colour picker.
Sort your samples into three piles: the shouty colours, the paper colours and the ink colours. Pear drops give you the shouty green and yellow. Aniseed balls give you near-black with a violet lean. Sherbet fountains give you a chalky white and a dusty raspberry. Floral creams give you rose, cream and a green that looks like it has been left in a drawer. The paper colours are the ones that stop the gradients from vibrating: sugar-paper cream, faded newsprint, the inside of a paper bag.
Sampling without stealing
A wrapper palette has too many hues to be a token set. Pick six to eight anchors, then name them by role rather than by sweet. That sounds dull, but it saves you later. A token called --pear-drop is a novelty; a token called --accent-fruit is a decision.
Here is a small starting set in OKLCH. The lightness values are deliberately spread out so the gradients have somewhere to go:
:root {
--sweet-paper: oklch(96% 0.02 85);
--sweet-cream: oklch(91% 0.04 78);
--sweet-rose: oklch(72% 0.12 15);
--sweet-raspberry: oklch(55% 0.16 5);
--sweet-pear: oklch(82% 0.15 125);
--sweet-aniseed: oklch(28% 0.04 285);
--sweet-sherbet: oklch(94% 0.03 200);
--sweet-liquorice: oklch(22% 0.02 60);
}
Notice there is no pure black and no pure white. That is on purpose. The sweet-shop look depends on slight dirt: cream instead of white, liquorice instead of black. It keeps the gradients from looking like a default UI kit in fancy dress.
Tokens that know about dark mode
The mistake is to build one gradient and flip the whole page to dark mode by inverting it. Inversion turns pear green into an unpleasant fluorescent mint and makes the paper cream look like old nicotine. Instead, define the gradient recipes once and swap the anchors.
Use a light-dark() pair or a media query if you need broader support. In 2026 the former is comfortable in modern browsers, but the principle matters more than the syntax: the light version should feel like paper, the dark version like the inside of a sweet jar at night.
:root {
--gradient-pear: linear-gradient(
135deg,
var(--sweet-pear) 0%,
var(--sweet-sherbet) 55%,
var(--sweet-paper) 100%
);
--gradient-aniseed: linear-gradient(
160deg,
var(--sweet-aniseed) 0%,
var(--sweet-raspberry) 70%,
var(--sweet-rose) 100%
);
}
@media (prefers-color-scheme: dark) {
:root {
--sweet-paper: oklch(24% 0.02 80);
--sweet-cream: oklch(32% 0.03 70);
--sweet-pear: oklch(70% 0.13 125);
--sweet-sherbet: oklch(64% 0.04 200);
--sweet-rose: oklch(60% 0.11 15);
}
}
The gradients keep their names and their direction. The colours just step back. That is the whole trick.
The gradient recipes
Three recipes will cover most of the sweet-shop language without turning your site into a pick'n'mix aisle.
The first is the paper gradient: cream to sherbet, very low contrast, used for panels and cards. It is the calm one. The second is the fruit gradient: pear to sherbet to paper, bright but not neon, good for hero strips and call-to-action blocks. The third is the liquorice gradient: aniseed to raspberry to rose, dark enough to carry white text if you check it.
Do not use all three on one screen. A sweet shop works because the jars are separated by shelves. Your layout needs the same shelves: borders, spacing, cards, plain backgrounds. A gradient is a sweet, not a meal.
A small demo that generates cards
The demo below makes a row of gradient cards from a small data array. It is deliberately plain: no candy-stripe animation, no faux handwritten font, no drop shadow that looks like a 2010 WordPress theme. The charm comes from the colours and the names.
<div id='sweet-grid' class='sweet-grid'></div>
<script>
const sweets = [
{ name: 'Pear Drop', c1: 'oklch(82% 0.15 125)', c2: 'oklch(96% 0.02 85)', ink: 'oklch(24% 0.02 80)' },
{ name: 'Aniseed Ball', c1: 'oklch(28% 0.04 285)', c2: 'oklch(55% 0.16 5)', ink: 'oklch(96% 0.02 85)' },
{ name: 'Sherbet Fountain', c1: 'oklch(94% 0.03 200)', c2: 'oklch(91% 0.04 78)', ink: 'oklch(24% 0.02 80)' },
{ name: 'Floral Cream', c1: 'oklch(72% 0.12 15)', c2: 'oklch(91% 0.04 78)', ink: 'oklch(24% 0.02 80)' }
];
const grid = document.querySelector('#sweet-grid');
sweets.forEach((sweet) => {
const card = document.createElement('article');
card.className = 'sweet-card';
card.style.setProperty('--c1', sweet.c1);
card.style.setProperty('--c2', sweet.c2);
card.style.setProperty('--ink', sweet.ink);
card.innerHTML = `
<h2>${sweet.name}</h2>
<p>Gradient token sample</p>
`;
grid.appendChild(card);
});
</script>
.sweet-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
gap: 1rem;
}
.sweet-card {
min-height: 9rem;
padding: 1rem;
border-radius: 0.75rem;
border: 1px solid color-mix(in oklch, var(--ink) 18%, transparent);
background: linear-gradient(135deg, var(--c1), var(--c2));
color: var(--ink);
}
.sweet-card h2 {
margin: 0 0 0.5rem;
font-size: 1rem;
}
.sweet-card p {
margin: 0;
font-size: 0.875rem;
}
The ink value is the part people skip. It is not decorative. It is the text colour you have tested against the gradient. In the real library, every gradient recipe should ship with a matching ink token and a note about where it is safe to place copy.
Testing contrast before you ship
Gradients are not a single background colour, so contrast testing is a range, not a tick box. Check the lightest and darkest points under the text. If the copy sits over the middle of a gradient, check that too. A pear-to-sherbet gradient can pass at the pale end and fail at the green end; a liquorice gradient can pass at the rose end and lose the plot near the aniseed.
The practical answer is to stop putting small text directly on gradients. Use the gradient as a decorative panel and place text on a solid token, or add a solid inner panel with enough contrast. That is not a cop-out. It is how you keep the sweet-shop feeling without making people squint.
For UK public-sector work, aim for WCAG 2.2 AA at minimum. For everything else, aim for the same and then test with a real screen in daylight. A gradient that looks rich on a calibrated monitor can turn to mush on a phone in a bus shelter.
Keep the kitsch in the jar
The final rule is restraint. A sweet-shop palette is a lovely thing, but it is not a licence to use six gradients, a script font and a striped border on the same card. Pick one gradient per section. Let the paper tokens do the quiet work. Name the tokens after roles, not sweets. Test the ink. Then the library will feel like a memory of the counter, not a fancy-dress version of it.
The full CodeChroma version of this library will live as a small CSS file and a JSON manifest: gradients, ink pairs and contrast notes. Build your own first. Start with a pear drop, an aniseed ball and a sheet of sugar paper. You will be surprised how far three colours and a bit of discipline will go.