mix-blend-mode: difference cursor

difference 블렌드 커서

Put mix-blend-mode: difference on a white dot and it inverts whatever colour sits beneath it — a cursor that stays legible over any background.

Also known as: Inverting cursorExclusion cursor
···
html
<div class="wrap" id="wrap"><div class="bg"><i></i><i></i><i></i><i></i></div><div class="cursor" id="cur"></div></div>
css
.wrap{position:relative;width:100%;height:100%;isolation:isolate;overflow:hidden}
.bg{position:absolute;inset:0;display:flex}
.bg i{flex:1;height:100%}
.bg i:nth-child(1){background:#ff5c8a}
.bg i:nth-child(2){background:#5b5bf7}
.bg i:nth-child(3){background:#ffb648}
.bg i:nth-child(4){background:#18c29c}
.cursor{position:absolute;left:50%;top:50%;width:70px;height:70px;border-radius:50%;background:#fff;
  mix-blend-mode:difference;pointer-events:none;transform:translate(-50%,-50%)}
js
const wrap = document.getElementById('wrap');
const cur = document.getElementById('cur');
let auto = true, t = 0;
function place(x, y){ cur.style.left = x + 'px'; cur.style.top = y + 'px'; }
function loop(){
  if (auto) { t += 0.02; place(innerWidth / 2 + Math.sin(t) * innerWidth * 0.3, innerHeight / 2 + Math.sin(t * 1.7) * innerHeight * 0.28); }
  requestAnimationFrame(loop);
}
loop();
wrap.addEventListener('pointermove', (e) => { auto = false; place(e.clientX, e.clientY); });
wrap.addEventListener('pointerleave', () => { auto = true; });

difference subtracts the two layers' channel values (and takes the absolute value) to combine them. Placed over white (255,255,255), the result is 255 minus the background — an exact colour inversion. Worth remembering: over black, 255 − 0 = 255, so a white shape stays plain white and nothing visibly changes there.

That's exactly why it's popular for a cursor or focus ring that needs to stay visible no matter what colour is underneath. Leave the circle in the demo alone and it drifts on its own; move your pointer over it and it follows — watch the colours invert wherever it passes.

A blend mixes with everything painted beneath it inside the same stacking context — not just the background you intended. To scope it to a specific background, wrap both in a separate context with isolation: isolate so no other layer sneaks in underneath. Like filter and transform, mix-blend-mode also forces its own paint layer.

When to use

For custom cursors or a selection highlight that needs to read regardless of background colour. Always scope the blend with isolation: isolate.