JSFiddle - React, Tailwind, and code Playground
HTML
<div class="demo">
</div>
<button class="toggleGrayscale">
Grayscale
</button>
<button class="toggleBlur">
Blur
</button>
CSS
.demo {
background: linear-gradient(to bottom, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%);
width: 100px;
height: 100px;;
}
JavaScript
let qs = q => document.querySelector(q);
let toggleGrayscale = qs('.toggleGrayscale');
let toggleBlur = qs('.toggleBlur');
let demo = qs('.demo');
let observerPause = false;
let observer = new MutationObserver((mutationList) => {
if (observerPause) {
observerPause = false;
return;
}
for (mutation of mutationList) {
if (mutation.attributeName === 'style') {
let filter = window.getComputedStyle(mutation.target).getPropertyValue('filter');
// If no style was there before, just allow the change
if (!mutation.oldValue) {
return;
}
if (!filter) {
// Can't know what was intended to be removed.
// Not sure what to do...
// We have to do something here so might as well go the easy way and allow the change
return;
}
// Figure out the old filter, from a DOM style string
let oldFilter = mutation.oldValue.replace(/.*?filter:[\s ]*([^;]*).*/, '$1');
let newFilterName = filter.replace(/\(.*?\)/, '');
// Remove the new filter from the old filter list
let reg = new RegExp(`${newFilterName}[\\s ]*\\([^\\)]+\\)`);
oldFilter = oldFilter.replace(reg, '');
// Pause oberserver for 1 time so we can change the filter
observerPause = true;
mutation.target.style.filter = `${oldFilter} ${filter}`;
}
}
});
observer.observe(demo, {
attributes: true,
attributeOldValue: true,
});
function setFilterUgly(filter, value) {
demo.style.filter = `${filter}(${value})`;
}
let stateGrayscale = 0;
toggleGrayscale.addEventListener('click', () => {
stateGrayscale = stateGrayscale ? 0 : '0.5';
setFilterUgly('grayscale', stateGrayscale);
});
let stateBlur = 0;
toggleBlur.addEventListener('click', () => {
stateBlur = stateBlur ? 0 : '3px';
setFilterUgly('blur', stateBlur);
});