difference 블렌드 커서

mix-blend-mode: difference cursor

mix-blend-mode: difference 를 건 흰색 점을 배경 위에 올리면, 무슨 색 위에 있든 항상 또렷하게 반전돼 보이는 커서를 만들 수 있습니다.

다른 이름: 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 는 위·아래 두 레이어의 채널별 값을 빼서(절댓값) 합치는 블렌드 모드입니다. 흰색(255,255,255) 위에 놓으면 255 - 배경값이 되어 배경이 정확히 반전됩니다. 검은 배경 위에서는 255 - 0 = 255, 즉 그대로 흰색이라 아무 변화가 없다는 점도 기억해 둘 만합니다.

이 성질 때문에 배경이 무슨 색이든 항상 보이는 커서·포커스 링을 만들 때 즐겨 씁니다. 데모의 원을 가만히 두면 자동으로 움직이고, 포인터를 올리면 따라옵니다 — 지나가는 자리마다 색이 반전되는 걸 보세요.

블렌드는 "같은 스태킹 컨텍스트 안에서 아래에 그려진 모든 것"과 섞입니다. 원하는 배경하고만 섞이게 하려면 그 배경과 커서를 isolation: isolate 로 감싼 별도 컨텍스트에 넣어 다른 레이어가 끼어들지 않게 해야 합니다. mix-blend-mode 도 filter·transform 처럼 자기 페인트 레이어를 만듭니다.

언제 쓰나

커스텀 커서, 선택된 상태를 배경색과 무관하게 강조하는 하이라이트에 씁니다. isolation: isolate 로 블렌드 범위를 반드시 좁히세요.