反转颜色的自定义光标

Custom Cursor that invert colors

我有一个问题。 我怎样才能使光标恢复其背后的颜色并应用于自身。

就像"negative"效果一样。

但我需要它是自动的,无需对每种颜色进行编码,因此它可以与自身后面的任何元素交互。

这是自定义光标的开始和我的背景示例:

(function () {
  var follower, init, mouseX, mouseY, positionElement, printout, timer;

  follower = document.getElementById('follower');

  printout = document.getElementById('printout');

  mouseX = event => {
    return event.clientX;
  };

  mouseY = event => {
    return event.clientY;
  };

  positionElement = event => {
    var mouse;
    mouse = {
      x: mouseX(event),
      y: mouseY(event) };

    follower.style.top = mouse.y + 'px';
    return follower.style.left = mouse.x + 'px';
  };

  timer = false;

  window.onmousemove = init = event => {
    var _event;
    _event = event;
    return timer = setTimeout(() => {
      return positionElement(_event);
    }, 1);
  };

}).call(this);

//# sourceURL=coffeescript
* {
  cursor: none;
  margin:0;
  padding:0;
}

.img{
  width:49vw;
  height:99vh;
  position:absolute;
  background: url('https://images.pexels.com/photos/531880/pexels-photo-531880.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=1000');
}
.img2{
  width:49vw;
  height:99vh;
  left:49vw;
  position:absolute;
  background: url('https://cdn-images-1.medium.com/max/1600/0*I-sI3u34g0ydRqyA');
}

#follower {
  position: absolute;
  top: 50%;
  left: 50%;
}
#follower #circle {
  position: absolute;
  background: #fff;
  border-radius: 50%;
  opacity: 0.5;
  height: 1.5em;
  width: 1.5em;
  margin-top: -0.5em;
  margin-left: -0.5em;
  z-index:2;
}
<div id="follower">
  <div id="circle"></div>
</div>

<div class="img"></div>
<div class="img2"></div>

如何给光标一个负面效果?

这是一个使用背景的想法,其中的诀窍是使用 radial-gradient 模拟光标,这样您就可以根据需要在每个元素上定义颜色:

document.onmousemove = function(e) {
  document.body.style.setProperty('--x',(e.clientX)+'px');
  document.body.style.setProperty('--y',(e.clientY)+'px');
  
}
* {
  cursor: none;
  margin:0;
  padding:0;
}

.red{
  width:33vw;
  height:100vh;
  position:absolute;
  background:
  radial-gradient(farthest-side ,white 95%,transparent 100%)
    calc(var(--x) - .75em) calc(var(--y) - .75em)/ /*position*/
    1.5em 1.5em   /*size of circle*/
    fixed no-repeat;
  background-color:red;
}
.black{
  width:33vw;
  height:100vh;
  margin-left:33vw;
  position:absolute;
  background:radial-gradient(farthest-side ,cyan 95%,transparent 100%)
    calc(var(--x) - .75em) calc(var(--y) - .75em)/1.5em 1.5em  fixed no-repeat;
  background-color:black;
}
.green{
  width:33vw;
  height:100vh;
  margin-left:66vw;
  position:absolute;
  background:radial-gradient(farthest-side ,blue 95%,transparent 100%)
    calc(var(--x) - .75em) calc(var(--y) - .75em)/1.5em 1.5em  fixed no-repeat;
  background-color:green;
}
<div class="red"></div>
<div class="black"></div>
<div class="green"></div>

诀窍是每个渐变都是 fixed 所以它相对于视口定位然后我对所有渐变使用相同的 CSS 变量将它们放在相同的位置。每一个都只会在其部分可见。

如果你有内容并且需要将光标放在所有内容之上,你可以考虑使用伪元素在顶部创建图层:

document.onmousemove = function(e) {
  document.body.style.setProperty('--x',(e.clientX)+'px');
  document.body.style.setProperty('--y',(e.clientY)+'px');
  
}
* {
  cursor: none;
  margin:0;
  padding:0;
}
.box {
  position:relative;
  z-index:0;
  color:#fff;
}
.box:before {
  content:"";
  position:absolute;
  z-index:999;
  top:0;
  left:0;
  right:0;
  bottom:0; 
  background:
  radial-gradient(farthest-side ,var(--c) 95%,transparent 100%)
    calc(var(--x) - .75em) calc(var(--y) - .75em)/1.5em 1.5em  fixed no-repeat;
}


.red{
  width:33vw;
  height:100vh;
  position:absolute;
  background-color:red;
  --c:white;
}
.black{
  width:33vw;
  height:100vh;
  margin-left:33vw;
  position:absolute;
  background-color:black;
  --c:cyan;
}
.green{
  width:33vw;
  height:100vh;
  margin-left:66vw;
  position:absolute;
  background-color:green;
  --c:blue;
}
<div class="red box">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin molestie sem non dui tempus placerat non ut nulla. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In vel nulla commodo, dignissim sem in, viverra ipsum. Nam non libero neque.</div>
<div class="black box">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin molestie sem non dui tempus placerat non ut nulla. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In vel nulla commodo, dignissim sem in, viverra ipsum. Nam non libero neque.</div>
<div class="green box">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin molestie sem non dui tempus placerat non ut nulla. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In vel nulla commodo, dignissim sem in, viverra ipsum. Nam non libero neque.</div>


这是另一个想法,您可以使用与您的 3 个部分具有相同尺寸的 linear-gradient 为您制作的光标着色:

(function () {
  var follower, init, mouseX, mouseY, positionElement, printout, timer;

  follower = document.getElementById('follower');

  printout = document.getElementById('printout');

  mouseX = event => {
    return event.clientX;
  };

  mouseY = event => {
    return event.clientY;
  };

  positionElement = event => {
    var mouse;
    mouse = {
      x: mouseX(event),
      y: mouseY(event) };

    follower.style.top = mouse.y + 'px';
    return follower.style.left = mouse.x + 'px';
  };

  timer = false;

  window.onmousemove = init = event => {
    var _event;
    _event = event;
    return timer = setTimeout(() => {
      return positionElement(_event);
    }, 1);
  };

}).call(this);

//# sourceURL=coffeescript
* {
  cursor: none;
  margin:0;
  padding:0;
}

.red{
  width:33vw;
  height:100vh;
  position:absolute;
  background-color:red;
}
.black{
  width:33vw;
  height:100vh;
  margin-left:33vw;
  position:absolute;
  background-color:black;
}
.green{
  width:33vw;
  height:100vh;
  margin-left:66vw;
  position:absolute;
  background-color:green;
}

#follower {
  position: absolute;
  top: 50%;
  left: 50%;
}
#follower #circle {
  position: absolute;
  background:
    linear-gradient(white,white) 0  0,
    linear-gradient(cyan,cyan) 33vw 0,
    linear-gradient(blue,blue) 66vw 0;
  background-size:33vw 100vh;
  background-attachment:fixed;
  background-repeat:no-repeat;
  border-radius: 50%;
  opacity: 0.5;
  height: 1.5em;
  width: 1.5em;
  margin-top: -0.5em;
  margin-left: -0.5em;
  z-index:2;
}
<div id="follower">
  <div id="circle"></div>
</div>

<div class="red"></div>
<div class="black"></div>
<div class="green"></div>

以上代码相关部分:

 background:
    linear-gradient(white,white) 0  0,
    linear-gradient(cyan,cyan) 33vw 0,
    linear-gradient(blue,blue) 66vw 0;
 background-size:33vw 100vh;
 background-attachment:fixed;
 background-repeat:no-repeat;

更新

根据你的新需求,可以考虑mix-blend-mode实现你想要的

document.onmousemove = function(e) {
  document.body.style.setProperty('--x',(e.clientX)+'px');
  document.body.style.setProperty('--y',(e.clientY)+'px');
  
}
* {
  cursor: none;
  margin:0;
  padding:0;
}
.box {
  position:relative;
  z-index:0;
  color:#fff;
}
.box:before {
  content:"";
  position:absolute;
  z-index:999;
  top:0;
  left:0;
  right:0;
  bottom:0; 
  background:
  radial-gradient(farthest-side ,#fff 95%,transparent 100%)
    calc(var(--x) - .75em) calc(var(--y) - .75em)/1.5em 1.5em  fixed no-repeat;
  mix-blend-mode:difference;
}


.red{
  width:33vw;
  height:100vh;
  position:absolute;
  background-color:red;
}
.black{
  width:33vw;
  height:100vh;
  margin-left:33vw;
  position:absolute;
  background:url(https://picsum.photos/800/600?image=1069) center/cover;
}
.green{
  width:33vw;
  height:100vh;
  margin-left:66vw;
  position:absolute;
  background:url(https://picsum.photos/800/600?image=1039) center/cover;
}
<div class="red box"></div>
<div class="black box"></div>
<div class="green box"></div>

您只需更改光标颜色(一次)并定义所需的混合模式。

这是光标元素:

document.onmousemove = function(e) {
  document.body.style.setProperty('--x',(e.clientX)+'px');
  document.body.style.setProperty('--y',(e.clientY)+'px');
  
}
* {
  cursor: none;
  margin:0;
  padding:0;
}
body:before {
  content:"";
  position:absolute;
  z-index:999;
  top:var(--y);
  left:var(--x);
  right:0;
  bottom:0; 
  width:1.5em;
  height:1.5em;
  border-radius:50%;
  transform:translate(-50%,-50%);
  background:#fff;
  mix-blend-mode:difference;
}


.red{
  width:33vw;
  height:100vh;
  position:absolute;
  background-color:red;
}
.black{
  width:33vw;
  height:100vh;
  margin-left:33vw;
  position:absolute;
  background:url(https://picsum.photos/800/600?image=1069) center/cover;
}
.green{
  width:33vw;
  height:100vh;
  margin-left:66vw;
  position:absolute;
  background:url(https://picsum.photos/800/600?image=1039) center/cover;
}
<div class="red box"></div>
<div class="black box"></div>
<div class="green box"></div>

扩展 Temani Afif 的回答:

如果您必须滚动,他的代码就会中断,因为绘制的光标位置与实际光标位置偏离了您滚动的量。

您可以将 document.documentElement.scrollTop 添加到 y 值,但光标不会在滚动时更新。

除了 onmousemove 之外,您还可以调用函数来更新 --x--y 属性 onscroll,但是,onscroll 事件不会没有 e.clientXe.clientY,因此这些值计算为 0,光标位置偏离。

为了解决这个问题,我缓存了最新鼠标移动的 x 和 y 值,然后使用使用缓存的 x 和 y 值的函数更新鼠标移动和滚动时的属性,并添加scrollTop 到 y 值:

let x, y;

document.onmousemove = function(e) {
    x = e.clientX;
    y = e.clientY;
    updateProps();
};

document.onscroll = updateProps;

function updateProps() {
    document.body.style.setProperty('--x',(x)+'px');
    document.body.style.setProperty('--y',(y + document.documentElement.scrollTop)+'px');
}