Cirkel die de tekst omkeert Nieuw
Een ronde cursor met mix-blend-mode: difference die over een grote kop zweeft en alles eronder omkeert: zwart wordt wit en andersom. Boven een link groeit de cirkel, bij toetsenbordfocus springt hij naar de link en op een telefoon volgt hij je vinger; zonder invoer drijft hij langzaam over de tekst. Werkt het best in zwart-wit (oranje zou blauw worden). Voor de hero van een interieurontwerper, meubelmaker of fotograaf met een rustige, typografische homepage.
Keukens die twintig jaar meegaan, gebouwd in onze werkplaats in Zwolle.
Zo gebruik je het
- Plak de HTML op de plek waar het onderdeel moet komen.
- Zet de CSS in je stylesheet. Alle klassen hebben een eigen voorvoegsel, dus niets botst met je eigen opmaak.
- Voeg de JavaScript toe en roep init() aan met het element waar de HTML in staat.
<!-- 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'));
Meer uit componenten
Iets gezien dat je mooi vindt?
Zet het in je selectie en stuur hem op. Dan bouwen we je site eromheen, in jouw huisstijl.
Neem contact op →