Cirkel die de tekst omkeert New
A round cursor with mix-blend-mode: difference floating over a large heading and inverting everything beneath it: black turns white and vice versa. Over a link the circle grows, on keyboard focus it jumps to the link and on a phone it follows your finger; without input it drifts slowly across the text. Works best in black and white (orange would turn blue). For the hero of an interior designer, furniture maker or photographer with a calm, typographic homepage.
Keukens die twintig jaar meegaan, gebouwd in onze werkplaats in Zwolle.
How to use it
- Paste the HTML where the components should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- Cirkel die de tekst omkeert · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="tok">
<p class="tok__kop">Keukens die twintig jaar meegaan, gebouwd in onze werkplaats in Zwolle.</p>
<p class="tok__links"><a class="tok__a" href="#">Bekijk de keukens</a><a class="tok__a" href="#">Plan een bezoek</a></p>
<span class="tok__bol" aria-hidden="true"></span>
</div>
</div>/* Cirkel die de tekst omkeert · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.tok{position:relative;width:100%;height:100%;overflow:hidden;isolation:isolate;background:#fff;color:#0a0a0a;padding:20px 24px;box-sizing:border-box;display:flex;flex-direction:column;justify-content:center;font-family:Switzer,sans-serif;touch-action:pan-y}
.tok__kop{margin:0;font-size:28px;line-height:1.08;font-weight:600;letter-spacing:-.01em;max-width:15em}
.tok__links{margin:16px 0 0;display:flex;gap:18px;flex-wrap:wrap}
.tok__a{font-size:14px;color:#0a0a0a;text-decoration:underline;text-underline-offset:4px;min-height:28px;display:inline-flex;align-items:center}
.tok__a:focus-visible{outline:2px solid #0a0a0a;outline-offset:3px}
.tok__bol{position:absolute;left:0;top:0;width:76px;height:76px;margin:-38px 0 0 -38px;border-radius:50%;background:#fff;mix-blend-mode:difference;pointer-events:none;will-change:transform;z-index:2}
@media (hover:hover) and (pointer:fine){.tok,.tok__a{cursor:none}}
@media (max-width:500px){.tok{padding:16px 18px}.tok__kop{font-size:22px}.tok__links{margin-top:12px}}// Cirkel die de tekst omkeert · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie
// root = het element waarin de HTML staat
function init(root){
const w = root.querySelector('.tok'); if (!w) return;
const bol = w.querySelector('.tok__bol'), links = w.querySelectorAll('.tok__a');
const rm = matchMedia('(prefers-reduced-motion: reduce)').matches;
let doel = { x: 60, y: 60, s: 1 }, nu = { x: 60, y: 60, s: 1 }, zelf = !rm, raf = 0, zichtbaar = true;
function tik(t){
raf = 0; if (!zichtbaar) return;
if (zelf){ const r = w.getBoundingClientRect(); doel.x = r.width * (0.45 + 0.3 * Math.sin(t / 2100)); doel.y = r.height * (0.42 + 0.16 * Math.sin(t / 1400)); doel.s = 1; }
const k = rm ? 1 : 0.18;
nu.x += (doel.x - nu.x) * k; nu.y += (doel.y - nu.y) * k; nu.s += (doel.s - nu.s) * k;
bol.style.transform = 'translate(' + nu.x.toFixed(1) + 'px,' + nu.y.toFixed(1) + 'px) scale(' + nu.s.toFixed(3) + ')';
if (zelf || Math.abs(doel.x - nu.x) + Math.abs(doel.y - nu.y) + Math.abs(doel.s - nu.s) > 0.05) raf = requestAnimationFrame(tik);
}
const start = () => { if (!raf) raf = requestAnimationFrame(tik); };
function naar(e){
const r = w.getBoundingClientRect(); zelf = false;
doel.x = e.clientX - r.left; doel.y = e.clientY - r.top;
doel.s = e.target.closest && e.target.closest('.tok__a') ? 1.7 : 1; start();
}
w.addEventListener('pointermove', naar); w.addEventListener('pointerdown', naar);
links.forEach(a => {
a.addEventListener('click', e => e.preventDefault());
a.addEventListener('focus', () => {
const r = w.getBoundingClientRect(), l = a.getBoundingClientRect(); zelf = false;
doel.x = l.left - r.left + l.width / 2; doel.y = l.top - r.top + l.height / 2; doel.s = 1.5; start();
});
});
if ('IntersectionObserver' in window) new IntersectionObserver(es => { zichtbaar = es[0].isIntersecting; if (zichtbaar) start(); }).observe(w);
start();
}
init(document.querySelector('.jouw-container'));
More components
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →