【问题标题】:Invert text color on mouse hover鼠标悬停时反转文本颜色
【发布时间】:2018-04-12 09:46:27
【问题描述】:

我想在使用自定义 -black- 光标悬停黑色文本时反转黑色文本。 这个 GIF 演示了效果:

我无法用 CSS 和 JS 来完成这项工作。我猜是混合混合模式、剪切蒙版、伪元素和过滤器的一些组合。

以下代码使光标变为白色,但不允许黑色文本变为白色。听起来很抽象?这是demo

// All creds go to https://murmure.me ????

const cursor = $(".cursor"),
      body = $("body"),
      slider = $(".slider"),
      nav = $(".nav"),
      fail = $(".fail"),
      invert = $(".invert"),
      nav_open_menu = $(".navopen"),
      wwidth = $(window).width(),
      wheight = $(window).height(),
             
cursorMove = function() {
  var e, n;
  return (
    body.addClass("cursor-on"),
    cursor.css({
      transform: "matrix(1, 0, 0, 1, " + wwidth / 2 + ", " + wheight / 2 + ")"
    }),
    (e = wheight / 2),
    (n = 0.65 * wwidth / 2),
    n > e ? e : n,
    $(window).on("mousemove", function(e) {
      var n, t;
      if (
        ((window.x = e.clientX),
        (window.y = e.clientY),
        cursor.css({
          transform: "matrix(1, 0, 0, 1, " + x + ", " + y + ")"
        }),
        !nav.hasClass("overlay-visible"))
      )
        return (
          (n = Math.floor((x - 60) / 5)),
          (t = Math.floor((y - 60) / 5)),
          n < 20 && t < 20
            ? nav_open_menu.addClass("magnetize").css({
                transform: "scale(1.3) translate3d(" + n + "px, " + t + "px, 0)"
              })
            : nav_open_menu.removeClass("magnetize").attr("style", "")
        );
    })
  );
};
cursorBind = function() {
    var e, n, t;
    if (
      ((n = cursor.find("span")).removeClass("link external new"),
      (e = $(".focus")),
      (t = $(".slack")),
      $(window).on({
        mouseenter: function() {
          return n.removeClass("off");
        },
        mouseleave: function() {
          return n.addClass("off");
        }
      }),
      $("a, button, .cursor-link, .sort-listing th").on({
        mouseenter: function() {
          var e;
          return (
            (e = $(this).hasClass("external") ? "link external" : "link"),
            n.addClass(e)
          );
        },
        mouseleave: function() {
          return n.removeClass("link external");
        }
      }),
      $("h1").on({
        mouseenter: function() {
          var e;
          return (
            (e = $(this).hasClass("external") ? "invert external" : "invert"),
            n.addClass(e)
          );
        },
        mouseleave: function() {
          return n.removeClass("invert external");
        }
      }),
      e.length &&
        e.find("a").on({
          mouseenter: function() {
            return n.addClass("new");
          },
          mouseleave: function() {
            return n.removeClass("new");
          }
        }),
      slider.length &&
        slider.on({
          mouseenter: function() {
            var e;
            return (
              (e = $(this).hasClass("full") ? "click" : "drag"), n.addClass(e)
            );
          },
          mouseleave: function() {
            return n.removeClass("drag click");
          }
        }),
      t.length &&
        t.on({
          mouseenter: function() {
            return n.addClass("light");
          },
          mouseleave: function() {
            return n.removeClass("light");
          }
        }),
      fail.length)
    )
      return fail.on({
        mouseover: function() {
          return n.addClass("relol");
        },
        mouseleave: function() {
          return n.removeClass("relol");
        }
      });
  };

cursorMove();
cursorBind();
body {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

h1 {
  font-weight: 500;
  font-size: 9vw;
}
 

*, *:before, *:after {
	 box-sizing: border-box;
}
 body {
	 min-height: 100vh;
	 background-color: #fff;
	 color: #000;
	 text-rendering: optimizelegibility;
	 line-height: 1.5;
	/* System stack font-family mentioned by @wooorm */
	 font-family: Roboto, -apple-system, BlinkMacSystemFont, Helvetica Neue, Segoe UI, Oxygen, Ubuntu, Cantarell, Open Sans, sans-serif;
}
 .cursor-on {
	 cursor: none;
}
 .cursor-on * {
	 cursor: none;
}
 .cursor-on .cursor {
	 position: fixed;
	 z-index: 10;
	 pointer-events: none;
	 top: -1rem;
	 left: -1rem;
}
 .cursor-on .cursor > span {
	 display: block;
	 width: 2rem;
	 height: 2rem;
	 border-radius: 2rem;
	 background: #f8e71c;
	 transition: transform 0.2s cubic-bezier(0.165, 0.84, 0.44, 1);
	 transform: scale(1);
}
 .cursor-on .cursor > span.off {
	 transform: scale(0);
}
 .cursor-on .cursor > span.link {
	 transform: scale(1.5);
	 background-color: #0000ed;
}
 .cursor-on .cursor > span.link.external:after {
	 content: "↗";
	 display: block;
	 white-space: pre;
	 color: #fff;
	 font-weight: 100;
	 font-size: 1rem;
	 text-align: center;
	 width: 100%;
	 line-height: 1;
	 padding-top: 0.6em;
}
 .cursor-on .cursor > span.light {
	 background: #fff;
}
 .cursor-on .cursor > span.drag, .cursor-on .cursor > span.click, .cursor-on .cursor > span.relol, .cursor-on .cursor > span.new {
	 transform: scale(2.5);
}
 .cursor-on .cursor > span.drag:after, .cursor-on .cursor > span.click:after, .cursor-on .cursor > span.relol:after, .cursor-on .cursor > span.new:after {
	 display: block;
	 content: "";
	 white-space: pre;
	 color: #fff;
	 font-size: 5px;
	 text-align: center;
	 width: 100%;
	 line-height: 1;
	 padding-top: calc((2rem / 2) - 2.5px);
	 color: #000;
}
 .cursor-on .cursor > span.drag:after {
	 content: "play";
}
 .cursor-on .cursor > span.click:after {
	 content: "click\A click";
}
 .cursor-on .cursor > span.relol:after {
	 content: "click\A me";
	 padding-top: calc((2rem / 2) - 5px);
}
 .cursor-on .cursor > span.new:after {
	 content: "new\A new";
}
 .cursor-on:active .cursor > span {
	 transform: scale(0.75);
}
 .cursor-on:active .cursor > span.link {
	 transform: scale(1);
}
 .cursor-on:active .cursor > span.drag, .cursor-on:active .cursor > span.click, .cursor-on:active .cursor > span.relol, .cursor-on:active .cursor > span.new {
	 transform: scale(2);
}
 .grid {
	 background-color: #fff;
}
 .grid--column--item {
	 background-color: #000;
}
 .grid--column.sticky .grid--column--item {
	 border-color: #000;
}


.cursor-on .cursor > span {
	 background: black;
}
 .cursor-on .cursor > span.invert {
	 transform: scale(2.5);
	 mix-blend-mode: difference;
	 filter: invert(1) grayscale(1) contrast(2);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 class="invert">Work</h1>


<div class="cursor" >
  <span class="off"></span>
 </div>
mix-blend-mode: difference;
filter: invert(1) grayscale(1) contrast(2);

我设置了一个playground on Codepen 来解决问题,但还没有找到解决方案。

如何使用 CSS 和 Javascript 重新创建这种悬停效果?

【问题讨论】:

    标签: javascript html css


    【解决方案1】:

    这是一个使用clip-path 的想法。诀窍是复制文本以使两层相互叠加,并使用不同的文本颜色,然后我使用clip-path 显示最上面的一层,并通过鼠标移动进行调整。

    var h =document.querySelector('h1');
    var p= h.getBoundingClientRect();
    var c= document.querySelector('.cursor');
    
    document.body.onmousemove = function(e) {
      /*Adjust the cursor position*/
      c.style.left=e.clientX+'px';
      c.style.top=e.clientY+'px';
      /*Adjust the clip-path*/
      h.style.setProperty('--x',(e.clientX-p.top)+'px');
      h.style.setProperty('--y',(e.clientY-p.left)+'px');
    }
    body {
      cursor:none;
    }
    h1 {
      color: #000;
      display:inline-block;
      margin:50px;
      text-align: center;
      position:relative;
    }
    h1:before {
      position:absolute;
      content:attr(data-text);
      color:#fff;
      background:#000;
      clip-path: circle(20px at var(--x,-100%) var(--y,-100%));
    }
    .cursor {
      position:fixed;
      width:40px;
      height:40px;
      background:#000;
      border-radius:50%;
      top:0;
      left:0;
      transform:translate(-50%,-50%);
      z-index:-2;
    }
    <h1 data-text="WORK">WORK</h1>
    
    <span class="cursor"></span>

    这是另一个使用radial-gradient 且无需复制可同时处理多个元素的文本的想法:

    document.body.onmousemove = function(e) {
      document.documentElement.style.setProperty('--x',(e.clientX)+'px');
      document.documentElement.style.setProperty('--y',(e.clientY)+'px');
    }
    body {
      cursor:none;
    }
    
    .mask {
      background: 
        radial-gradient(circle 20px 
                        at var(--x,0) var(--y,0), 
                        #fff 99%,black 100%) 
                        fixed;
      background-clip: text;
      -webkit-background-clip: text;
      color:transparent;
      -webkit-text-fill-color: transparent;
    }
    html::before {
      content:"";
      position:fixed;
      width:40px;
      height:40px;
      background:#000;
      border-radius:50%;
      top:var(--y,0);
      left:var(--x,0);
      transform:translate(-50%,-50%);
      z-index:-2;
    }
    <h1 class="mask">WORK</h1>
    <p class="mask">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis risus sapien. Maecenas dui orci, blandit et commodo eget, egestas quis odio. Donec eu tortor turpis. Aliquam convallis et nisi ut varius. Proin sapien erat, auctor in efficitur vel, efficitur sit amet justo. In pretium iaculis tempus. Vivamus congue</p>
    
    <p class="mask">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis risus sapien. Maecenas dui orci, blandit et commodo eget, egestas quis odio. Donec eu tortor turpis. Aliquam convallis et nisi ut varius. Proin sapien erat, auctor in efficitur vel, efficitur sit amet justo. In pretium iaculis tempus. Vivamus congue</p>

    类似想法的相关问题:Stacking circles produces a black bar on border radius

    【讨论】:

    • 非常感谢!当光标在原始 JS 代码中通过 transform: matrix 进行缩放和移动时,这怎么会起作用? codepen.io/danoszz/pen/GxreBV
    • @danoszz 正如您在我的代码中看到的那样,光标和与剪辑路径或径向渐变一起使用的圆圈具有相同的尺寸......所以如果您缩放圆圈,您需要更改尺寸使它们匹配
    【解决方案2】:

    使用mix-blend-mode: difference;.cursor 制定了解决方案。

    优点是 - 我们不需要为我们用圆形鼠标悬停的所有元素添加任何类或 javascript。

    缺点是 - 由于mix-blend-mode,这个解决方案不太稳定,有点原始技术。需要在bodyhtml中设置height,对body设置严格的background-color

    .cursor CSS 和 JavaScript 的部分——我部分借鉴了@Temani Afif 的解决方案。谢谢你,希望你不要介意,因为试图写得更好是没有意义的。但我添加了+window.scrollX+window.scrollY,以便在滚动时正确.cursor 工作。

    更多关于mix-blend-mode你可以在这里阅读https://caniuse.com/#search=mix-blend-modehttps://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode

    document.body.onmousemove = function(e) {
      document.documentElement.style.setProperty('--x', (e.clientX+window.scrollX) + 'px');
      document.documentElement.style.setProperty('--y', (e.clientY+window.scrollY) + 'px');
    }
    html {
      height: 100%; /* requires for stable body height */
    }
    
    body {
      min-height: 100%; /* requires for 'mix-blend-mode' */
      cursor: none;
      color: #000;
      background-color: #fff; /* requires for 'mix-blend-mode' */
    }
    
    .cursor {
      position: absolute;
      width: 40px;
      height: 40px;
      background: #fff;
      border-radius: 50%;
      top: var(--y, 0);
      left: var(--x, 0);
      transform: translate(-50%, -50%);
      z-index: 2;
      mix-blend-mode: difference;
    }
    <h1>WORK</h1>
    <span class="cursor"></span>

    【讨论】:

      猜你喜欢
      • 2017-05-22
      • 1970-01-01
      • 2014-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-30
      • 1970-01-01
      相关资源
      最近更新 更多