堆叠圆圈在边界半径上产生一个黑条

Posted

技术标签:

【中文标题】堆叠圆圈在边界半径上产生一个黑条【英文标题】:Stacking circles produces a black bar on border radius 【发布时间】:2019-07-07 13:07:22 【问题描述】:

我这里有一个相当令人费解的企业。

我正在制作一个用作“手电筒/探照灯”的鼠标。如果发生悬停,所有文本(内联元素、按钮,你明白了)都会从通常的白色反转为黑色,正常的背景是黄色的氛围。

我目前有以下设置:

const _$shadow = $('.b-cursor__shadow');
const _$front = $('.b-cursor__front');
const _$back = $('.b-cursor__back');

$(document).on('mousemove', (e) => 
  _$back.css(
    left: e.pageX,
    top: e.pageY
  );
  _$front.css(
    left: e.pageX,
    top: e.pageY
  );
  _$shadow.css(
    left: e.pageX,
    top: e.pageY
  );
);
html,
body 
  padding: 0;
  margin: 0;
  cursor: none;
  background: red;


.test 
  background: darkblue;


p 
  color: white;
  font-family: sans-serif;
  font-size: 20px;
  max-width: 30rem;
  padding: 1rem;
  margin: 1rem;
  border: 1px solid white;


p,
span,
a 
  position: relative;
  z-index: 105;


.b-cursor__back,
.b-cursor__front,
.b-cursor__shadow 
  position: fixed;
  width: 8rem;
  height: 8rem;
  margin-left: -4rem;
  margin-top: -4rem;
  border-radius: 50%;


.b-cursor__shadow 
  box-shadow: 0px 0px 10px 10px rgba(231, 232, 192, 1);


/* background changes */
.b-cursor__back 
  z-index: 104;
  background: #18173e;
  clip-path: circle(50% at 50% 50%);


.b-cursor__front 
  z-index: 106;
  background: white;
  clip-path: circle(50% at 50% 50%);
  mix-blend-mode: difference;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pretium pharetra ipsum, at placerat ante maximus vitae. Duis lacus urna, posuere id dapibus in, semper vitae massa. Quisque at egestas nisl. In ex elit, imperdiet eu interdum a, auctor vitae ante. Pellentesque efficitur imperdiet elementum. Integer at nibh gravida nisl sodales ornare ut quis est. Suspendisse sem odio, congue vitae felis at, tincidunt interdum purus. Morbi vitae efficitur est, non congue ante. Proin vel odio et metus sodales lobortis quis ut justo. Phasellus rhoncus eu urna vitae tristique. Suspendisse potenti. Curabitur quis quam lobortis mi laoreet lacinia. Cras non ultrices eros. Nam sed leo et tortor vestibulum cursus nec eu massa. Suspendisse potenti.</p>

<section class="b-cursor">
  <div class="b-cursor__shadow"></div>
  <div class="b-cursor__back"></div>
  <div class="b-cursor__front"></div>
</section>
<div class="test">
  <p>ja uh misschien werkt dit wel niet
    <p>
</div>

(codepen)

这几乎产生了预期的结果,除了 border-radius: 50% 不能正确处理半好的堆叠 div。像素剧!图片澄清:

问题:如何在保留当前对文本的效果的同时,删除由相同大小的这两个元素堆叠产生的黑色边框?

【问题讨论】:

我认为您可以通过使用具有径向渐变的单个 SVG 作为光标更轻松地逃脱,然后在 SVG 上应用 mix-blend-mode 以将其与背景上的差异进行合成... 与您的问题无关,但滚动确实会脱离聚光灯定位。 @AKX 嘿 AKX,我尝试在单个 SVG 中应用此效果,但我使用 z-index 堆栈让内容出现在元素“之间”,因此差异效果正在发挥作用白色文字。 看起来与 this question 相关,但不重复 codepen.io/anon/pen/OdwoWY 可能只使用插入框阴影(我知道结果不完全相同,但没有黑条) 【参考方案1】:

这可能满足您的需求。

const _$shadow = $('.b-cursor__shadow');
const _$front = $('.b-cursor__front');
const _$back = $('.b-cursor__back');

$(document).on('mousemove', (e) => 
  _$back.css(
    left: e.pageX,
    top: e.pageY
  );
  _$front.css(
    left: e.pageX,
    top: e.pageY
  );
  _$shadow.css(
    left: e.pageX,
    top: e.pageY
  );
);
html, body 
    padding: 0;
    margin: 0;
    cursor: none;
    background: red;

.test 
    background: darkblue;

p 
    color: white;
    font-family: sans-serif;
    font-size: 20px;
    max-width: 30rem;
    padding: 1rem;
    margin: 1rem;
    border: 1px solid white;

p, span, a 
    position: relative;
    z-index: 105;

.b-cursor__shadow2, .b-cursor__back, .b-cursor__front, .b-cursor__shadow 
    position: fixed;
    width: 8rem;
    height: 8rem;
    margin-left: -4rem;
    margin-top: -4rem;
    border-radius: 50%;

.b-cursor__shadow 
    box-shadow: 0px 0px 10px 20px rgba(231, 232, 192, 1);
    z-index: 107;
    height: 8rem;
    width: 8rem;

.b-cursor__shadow2 
    background: radial-gradient(circle at center, #18173e 100%, #18173e 25%);
    z-index: 109;
    height: 8rem;
    width: 8rem;
    background-color: transparent;

/* background changes */
.b-cursor__back 
    z-index: 104;
    height: 8rem;
    width: 8rem;
    background: radial-gradient(circle at center, #18173e 100%, #18173e 25%);
    background-size: 100% 100%;
    background-position: 50% 50%;

.b-cursor__back:after 
    width: 7rem;
    height: 7rem;
    content: '';
    border-radius: 50%;
    background: transparent;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0px 0px 0px 1rem #18173e;
    transition: all 0.3s linear;
    mix-blend-mode: normal;

.b-cursor__front 
    z-index: 106;
    height: 8rem;
    width: 8rem;
    background: white;
    background: radial-gradient(circle at center, #ffffff 100%, #ffffff 25%);
    background-position: 50% 50%;
    mix-blend-mode: difference;

.b-cursor__front:after 
    width: 7rem;
    height: 7rem;
    content: '';
    border-radius: 50%;
    background: transparent;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0px 0px 0px 1rem #ffffff;
    transition: all 0.3s linear;
    mix-blend-mode: normal;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pretium pharetra ipsum, at placerat ante maximus vitae. Duis lacus urna, posuere id dapibus in, semper vitae massa. Quisque at egestas nisl. In ex elit, imperdiet eu interdum a, auctor vitae
  ante. Pellentesque efficitur imperdiet elementum. Integer at nibh gravida nisl sodales ornare ut quis est. Suspendisse sem odio, congue vitae felis at, tincidunt interdum purus. Morbi vitae efficitur est, non congue ante. Proin vel odio et metus sodales
  lobortis quis ut justo. Phasellus rhoncus eu urna vitae tristique. Suspendisse potenti. Curabitur quis quam lobortis mi laoreet lacinia. Cras non ultrices eros. Nam sed leo et tortor vestibulum cursus nec eu massa. Suspendisse potenti.</p>

<section class="b-cursor">
  <div class="b-cursor__shadow"></div>
  <div class="b-cursor__back"></div>
  <div class="b-cursor__front"></div>
  <div class="cursor_now"></div>
</section>
<div class="test">
  <p>ja uh misschien werkt dit wel niet
    <p>
</div>

【讨论】:

【参考方案2】:

尝试添加

filter:blur(1.4px); /* or anywhere between 0.7px to 1.9px */

到外圈或内圈。在你的 CSS 中

【讨论】:

嗨 Ryan,这是不可能的,因为它改变了 z-index 创建的堆叠上下文 我认为 SVG 建议是您的最佳选择,因为它们与像素无关并且可以解决您的问题。【参考方案3】:

我会简单地在上面添加另一个元素,使用伪元素来隐藏那个小边框,并通过移动容器而不是每个元素来简化代码。也不需要clip-path

const _$cursor = $('.b-cursor');

$(document).on('mousemove', (e) => 
  _$cursor.css(
    left: e.pageX,
    top: e.pageY
  );
);
html,
body 
  padding: 0;
  margin: 0;
  cursor: none;
  background: red;


.test 
  background: darkblue;


p 
  color: white;
  font-family: sans-serif;
  font-size: 20px;
  max-width: 30rem;
  padding: 1rem;
  margin: 1rem;
  border: 1px solid white;


p,
span,
a 
  position: relative;
  z-index: 105;


.b-cursor  /*no z-index here !!!*/
  position: absolute;
  width: 8rem;
  height: 8rem;
  margin-left: -4rem;
  margin-top: -4rem;

/*the magic element*/
.b-cursor:before 
  content:"";
  position:absolute;
  top:-1px;
  left:-1px;
  right:-1px;
  bottom:-1px;
  border:2px solid rgba(231, 232, 192, 1);
  border-radius:50%;
  z-index:999;

/**/

.b-cursor__back,
.b-cursor__front,
.b-cursor__shadow 
  position:absolute;
  top:0;
  left:0;
  width:100%;
  height:100%;
  border-radius: 50%;


.b-cursor__shadow 
  box-shadow: 0px 0px 10px 10px rgba(231, 232, 192, 1);


/* background changes */
.b-cursor__back 
  z-index: 104;
  background: #18173e;


.b-cursor__front 
  z-index: 106;
  background: white;
  mix-blend-mode: difference;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pretium pharetra ipsum, at placerat ante maximus vitae. Duis lacus urna, posuere id dapibus in, semper vitae massa. Quisque at egestas nisl. In ex elit, imperdiet eu interdum a, auctor vitae ante. Pellentesque efficitur imperdiet elementum. Integer at nibh gravida nisl sodales ornare ut quis est. Suspendisse sem odio, congue vitae felis at, tincidunt interdum purus. Morbi vitae efficitur est, non congue ante. Proin vel odio et metus sodales lobortis quis ut justo. Phasellus rhoncus eu urna vitae tristique. Suspendisse potenti. Curabitur quis quam lobortis mi laoreet lacinia. Cras non ultrices eros. Nam sed leo et tortor vestibulum cursus nec eu massa. Suspendisse potenti.</p>

<section class="b-cursor">
  <div class="b-cursor__back"></div>
  <div class="b-cursor__front"></div>
  <div class="b-cursor__shadow"></div>
</section>
<div class="test">
  <p>ja uh misschien werkt dit wel niet</p>
</div>

这是另一个想法,代码更少,纯 JS 没有 jQuery:

document.onmousemove = function(e) 
  document.body.style.setProperty('--mx',(e.pageX)+'px');
  document.body.style.setProperty('--my',(e.pageY)+'px');
  
  document.body.style.setProperty('--x',(e.clientX)+'px');
  document.body.style.setProperty('--y',(e.clientY)+'px');
  

html 
  background:red;

body
  padding: 1px;
  margin: 0;
  min-height:100vh;
  cursor: none;
  background:
    radial-gradient(circle at var(--x) var(--y),#18173e 4rem,transparent 4rem) fixed;


.test 
  background:
    radial-gradient(circle at var(--x) var(--y),#18173e 4rem,transparent 4rem) fixed,
    darkblue;


p 
  color: white;
  font-family: sans-serif;
  font-size: 20px;
  max-width: 30rem;
  padding: 1rem;
  margin: 1rem;
  border: 1px solid white;


.b-cursor  /*no z-index here !!!*/
  position: absolute;
  width: 8rem;
  height: 8rem;
  top:var(--my);
  left:var(--mx);
  margin-left: -4rem;
  margin-top: -4rem;

/*the magic element*/
.b-cursor:before
  content:"";
  position:absolute;
  top:-1px;
  left:-1px;
  right:-1px;
  bottom:-1px;
  border:2px solid rgba(231, 232, 192, 1);
  border-radius:50%;
  z-index:999;

.b-cursor:after 
  content:"";
  position:absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  box-shadow: 0px 0px 10px 10px rgba(231, 232, 192, 1);
  border-radius:50%;
  z-index:998;

/**/
.b-cursor > div 
  position:absolute;
  top:0;
  left:0;
  width:100%;
  height:100%;
  border-radius: 50%;
  z-index: 997;
  background: white;
  mix-blend-mode: difference;
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pretium pharetra ipsum, at placerat ante maximus vitae. Duis lacus urna, posuere id dapibus in, semper vitae massa. Quisque at egestas nisl. In ex elit, imperdiet eu interdum a, auctor vitae ante. Pellentesque efficitur imperdiet elementum. Integer at nibh gravida nisl sodales ornare ut quis est. Suspendisse sem odio, congue vitae felis at, tincidunt interdum purus. Morbi vitae efficitur est, non congue ante. Proin vel odio et metus sodales lobortis quis ut justo. Phasellus rhoncus eu urna vitae tristique. Suspendisse potenti. Curabitur quis quam lobortis mi laoreet lacinia. Cras non ultrices eros. Nam sed leo et tortor vestibulum cursus nec eu massa. Suspendisse potenti.</p>

<section class="b-cursor">
  <div></div>
</section>
<div class="test">
  <p>ja uh misschien werkt dit wel niet</p>
</div>

如果我们考虑另一种渐变来替换我们用来修复黑色渐变的阴影和边框,您仍然可以进行更多优化:

document.onmousemove = function(e) 
  document.body.style.setProperty('--mx',(e.pageX)+'px');
  document.body.style.setProperty('--my',(e.pageY)+'px');
  
  document.body.style.setProperty('--x',(e.clientX)+'px');
  document.body.style.setProperty('--y',(e.clientY)+'px');
  

html 
  background:red;

body
  padding: 1px;
  margin: 0;
  min-height:100vh;
  cursor: none;
  background:
    radial-gradient(circle at var(--x) var(--y),#18173e 4rem,transparent 4rem) fixed;


.test 
  background:
    radial-gradient(circle at var(--x) var(--y),#18173e 4rem,transparent 4rem) fixed,
    darkblue;


p 
  color: white;
  font-family: sans-serif;
  font-size: 20px;
  max-width: 30rem;
  padding: 1rem;
  margin: 1rem;
  border: 1px solid white;


.b-cursor  /*no z-index here !!!*/
  position: absolute;
  width: 8rem;
  height: 8rem;
  top:var(--my);
  left:var(--mx);
  margin-left: -4rem;
  margin-top: -4rem;


.b-cursor:before
  content:"";
  position:absolute;
  top:-10px;
  left:-10px;
  right:-10px;
  bottom:-10px;
  background:
    radial-gradient(farthest-side, 
      transparent calc(100% - 18px),rgba(231, 232, 192, 1) calc(100% - 15px),
      rgba(231, 232, 192, 1) calc(100% - 10px),transparent 100%);
  border-radius:50%;
  z-index:999;


.b-cursor:after 
  content:"";
  position:absolute;
  top:0;
  left:0;
  width:100%;
  height:100%;
  border-radius: 50%;
  z-index: 998;
  background: white;
  mix-blend-mode: difference;
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pretium pharetra ipsum, at placerat ante maximus vitae. Duis lacus urna, posuere id dapibus in, semper vitae massa. Quisque at egestas nisl. In ex elit, imperdiet eu interdum a, auctor vitae ante. Pellentesque efficitur imperdiet elementum. Integer at nibh gravida nisl sodales ornare ut quis est. Suspendisse sem odio, congue vitae felis at, tincidunt interdum purus. Morbi vitae efficitur est, non congue ante. Proin vel odio et metus sodales lobortis quis ut justo. Phasellus rhoncus eu urna vitae tristique. Suspendisse potenti. Curabitur quis quam lobortis mi laoreet lacinia. Cras non ultrices eros. Nam sed leo et tortor vestibulum cursus nec eu massa. Suspendisse potenti.</p>

<section class="b-cursor">
</section>
<div class="test">
  <p>ja uh misschien werkt dit wel niet</p>
</div>

Safari 不支持at 的渐变语法,详见this question,所以这里有另一种选择:

document.onmousemove = function(e) 
  document.body.style.setProperty('--mx',(e.pageX)+'px');
  document.body.style.setProperty('--my',(e.pageY)+'px');
  
  document.body.style.setProperty('--x',(e.clientX)+'px');
  document.body.style.setProperty('--y',(e.clientY)+'px');
  

html 
  background:red;

body
  padding: 1px;
  margin: 0;
  min-height:100vh;
  cursor: none;
  background:
    radial-gradient(farthest-side ,#18173e 100%,transparent 100%)
    calc(var(--x) - 4rem) calc(var(--y) - 4rem)/8rem 8rem  fixed no-repeat;


.test 
  background:
    radial-gradient(farthest-side ,#18173e 100%,transparent 100%)
    calc(var(--x) - 4rem) calc(var(--y) - 4rem)/8rem 8rem  fixed no-repeat,
    darkblue;


p 
  color: white;
  font-family: sans-serif;
  font-size: 20px;
  max-width: 30rem;
  padding: 1rem;
  margin: 1rem;
  border: 1px solid white;


.b-cursor  /*no z-index here !!!*/
  position: absolute;
  width: 8rem;
  height: 8rem;
  top:var(--my);
  left:var(--mx);
  margin-left: -4rem;
  margin-top: -4rem;


.b-cursor:before
  content:"";
  position:absolute;
  top:-10px;
  left:-10px;
  right:-10px;
  bottom:-10px;
  background:
    radial-gradient(farthest-side, 
      transparent calc(100% - 18px),rgba(231, 232, 192, 1) calc(100% - 15px),
      rgba(231, 232, 192, 1) calc(100% - 10px),transparent 100%);
  border-radius:50%;
  z-index:999;


.b-cursor:after 
  content:"";
  position:absolute;
  top:0;
  left:0;
  width:100%;
  height:100%;
  border-radius: 50%;
  z-index: 998;
  background: white;
  mix-blend-mode: difference;
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pretium pharetra ipsum, at placerat ante maximus vitae. Duis lacus urna, posuere id dapibus in, semper vitae massa. Quisque at egestas nisl. In ex elit, imperdiet eu interdum a, auctor vitae ante. Pellentesque efficitur imperdiet elementum. Integer at nibh gravida nisl sodales ornare ut quis est. Suspendisse sem odio, congue vitae felis at, tincidunt interdum purus. Morbi vitae efficitur est, non congue ante. Proin vel odio et metus sodales lobortis quis ut justo. Phasellus rhoncus eu urna vitae tristique. Suspendisse potenti. Curabitur quis quam lobortis mi laoreet lacinia. Cras non ultrices eros. Nam sed leo et tortor vestibulum cursus nec eu massa. Suspendisse potenti.</p>

<section class="b-cursor">
</section>
<div class="test">
  <p>ja uh misschien werkt dit wel niet</p>
</div>

【讨论】:

哇,这太酷了——在元帖子上找到了。如果您在不移动鼠标的情况下滚动滚轮,您会得到一个蓝色圆圈,并且逆变器效果会保持在原来的位置,但是一旦您将鼠标移动 1 个像素,它们就会重新组合

以上是关于堆叠圆圈在边界半径上产生一个黑条的主要内容,如果未能解决你的问题,请参考以下文章

这个 CSS 是如何产生一个圆圈的?

CSS ONLY 动画绘制圆与边框半径和透明背景

绘制半径等于手指路径的圆

在gis Map上画一个圆圈

如何仅在地图上的半径(圆圈)内显示标记?

我如何知道一个 Lat,Lng 点是不是包含在一个圆圈内?