CSS scintillation with radius-background transition

Viewed 102

I'm building a script that focuses HTML elements. One problem was to match the focused element border-radius, which I resolved using radial-gradient (see Inner border-radius on a table cell).

However, when transitioning between two elements, a kind of white border appears on the focus element (between the "hello" element and its shadow in my example [transitions are triggered automatically]).

const hello = document.getElementById('hello');
var target = 'blue';
var radius = '';
var left = '';
var width = '';
var y = '';

focus();
setInterval(() => focus(), 3000);

function focus() {
 if (target === 'blue') {
   radius = '5px';
    left = '50px';
    width = '100px';
    y = '50px';
  } else {
   radius = '25px';
    left = '300px';
    width = '200px';
    y = '100px';
  }
  hello.style.top = y;
  hello.style.left = left;
  hello.style.width = width;
hello.style.background =
           `radial-gradient(farthest-side at bottom left, transparent 98%, #000000bb 100%) top right,
            radial-gradient(farthest-side at bottom right,transparent 98%, #000000bb 100%) top left,
            radial-gradient(farthest-side at top    left, transparent 98%, #000000bb 100%) bottom right,
            radial-gradient(farthest-side at top    right,transparent 98%, #000000bb 100%) bottom left`;
            hello.style.backgroundSize = `${radius} ${radius}`;
                hello.style.backgroundRepeat = 'no-repeat';
                
                target = (target === 'blue') ? 'red' : 'blue';
}
#uno {
  position: absolute;
  width: 100px;
  height: 100px;
  border-radius: 5px;
  background-color: blue;
  left: 50px;
  top: 50px;
}

#dos {
  position: absolute;
  width: 200px;
  height: 100px;
  border-radius: 25px;
  background-color: red;
  left: 300px;
  top: 100px;
}

#hello {
  position: fixed;
  width: 200px;
  height: 100px;
  left: 60px;
  top: 50px;
  box-shadow: 0px 0px 0px 2050px #000000bb;
  
  transition: all 2s ease;
}
<div id="uno"></div>
<div id="dos"></div>
<div id="hello"></div>

Here's the style for the "hello" focuser element:

/* shadow that hides rest of the page */
box-shadow: 0px 0px 0px 2050px #000000bb;
/* having a smooth transition on width, height and background */
transition: all 2s ease;

The glittering effect seems not to appear on Firefox, so maybe it's a chromium-related issue.

In case you only have Firefox, here's a screenshot of the fiddle: enter image description here

Any idea where the issue might come from?

1 Answers

This is due to the transition of background-size combined with background-position where you are using percentage values (yes the keywords right,bottom,etc are equivalent to percentage). You may also notice that it doesn't happen for the top/left corner because the position isn't changing there.

One way to avoid this is to consider pixel value to position the background instead of percentage values.

Here is an example where I will simplify your code using CSS varible and toggling classes:

const hello = document.getElementById('hello');

focus();
setInterval(() => focus(), 3000);

function focus() {
  hello.classList.toggle('red');
  hello.classList.toggle('blue');
}
#uno {
  position: absolute;
  width: 100px;
  height: 100px;
  border-radius: 5px;
  background-color: blue;
  left: 50px;
  top: 50px;
}

#dos {
  position: absolute;
  width: 200px;
  height: 100px;
  border-radius: 25px;
  background-color: red;
  left: 300px;
  top: 100px;
}

#hello {
  position: fixed;
  height: 100px;
  box-shadow: 0px 0px 0px 2050px #000000bb;
  background:
     radial-gradient(farthest-side at bottom left, transparent 98%, #000000bb 100%) var(--l) 0,
     radial-gradient(farthest-side at bottom right,transparent 98%, #000000bb 100%) 0 0,
     radial-gradient(farthest-side at top    left, transparent 98%, #000000bb 100%) var(--l) var(--t),
     radial-gradient(farthest-side at top    right,transparent 98%, #000000bb 100%) 0 var(--t);
  background-size:var(--s) var(--s);
  border-radius:var(--s);
  background-repeat:no-repeat;
  transition: all 2s ease;
}

.blue {
  left:50px;
  top:50px;
  width: 100px;
  --s:5px;
  --t:95px; /* height - border-radius */
  --l:95px; /* width  - border-radius */
}
.red {
  left:300px;
  top:100px;
  width: 200px;
  --s:25px;
  --t:75px;  /* height - border-radius */
  --l:175px; /* width  - border-radius */
}
<div id="uno"></div>
<div id="dos"></div>
<div id="hello" class="red"></div>

Related