I have been experimenting with creating a transition effect using SVG masks and CSS. Initially, everything was working as intended, but after a few repetitions (usually 1 or 2, unpredictably), the transition effect would suddenly stop and become instantaneous. Upon thorough examination of my code and monitoring for any issues with the generated SVG, I found that everything appeared to be correct and consistent with the initial executions where the effect worked smoothly.
This anomaly occurs in both Firefox and Chrome browsers.
To demonstrate this issue, I have prepared a JSFiddle: https://jsfiddle.net/nrm4fwg0/1/
function lerp(start, end, t) {
return start * (1 - t) + end * t;
}
const noise = (visible, wasVisible, durationSeconds = 1, seed = 44, liminal = 0.1) => {
const startOp = lerp(liminal * 2, 1 + liminal * 2, wasVisible?1:0);
const endOp = lerp(liminal * 2, 1 + liminal * 2, visible?1:0);
const slope = -1 / (liminal * 2);
const startIntercept = (startOp - liminal) * -slope;
const endIntercept = (endOp - liminal) * -slope;
return `
<svg xmlns="http://www.w3.org/2000/svg" viewport="0 0 100 100" width="100" height="100">
<defs>
<filter id="alpha-effect">
<feFlood x="0" y="0"
width="100" height="100"/>
<feGaussianBlur stdDeviation="3"/>
<feComponentTransfer result="SMOOTH">
<feFuncA type="table" tableValues="1 0.7 0.3 0"/>
</feComponentTransfer>
<feTurbulence seed="${seed}" result="NOISE" type="fractalNoise" baseFrequency="0.05" numOctaves="5"/>
<feMerge>
<feMergeNode in="NOISE"></feMergeNode>
<feMergeNode in="SMOOTH"></feMergeNode>
</feMerge>
<feComponentTransfer>
<feFuncA type="linear" slope="${slope}" intercept="${endIntercept}">
<animate
attributeName="intercept"
from="${startIntercept}"
to="${endIntercept}"
dur="${durationSeconds}s" />
</feFuncA>
</feComponentTransfer>
</filter>
</defs>
<rect x="0" y="0" width="100" height="100"
fill="blue" filter="url(#alpha-effect)"/>
</svg>
`;
};
let isCardVisible = true;
function toggleCard(){
const card = document.querySelector('#card');
const mask = noise(!isCardVisible, isCardVisible);
isCardVisible = !isCardVisible;
card.style['mask-image'] = `url(data:image/svg+xml;base64,${btoa(mask)})`;
card.style['-webkit-mask-image'] = `url(data:image/svg+xml;base64,${btoa(mask)})`;
card.style['mask-size'] = 'cover';
card.style['-webkit-mask-size'] = 'cover';
card.style['mask-repeat'] = 'no-repeat';
}
document.querySelector('#button').addEventListener('click', toggleCard);