I'm updating DOM element's brightness/contrast from JavaScript:
let style = `brightness(${brightness}%) contrast(${contrast}%)`;
element.style.filter = style;
This happens when the user holds left mouse button and moves cursor. However, the brightness/contrast does NOT change in Safari (on Mac) unless the scroll bars are visible. However, the brightness does change in other browsers (Chrome, Firefox, Edge). Is it a bug in Safari? How do I make it work in Safari?
Demo: https://l36vng.csb.app/
Code: https://codesandbox.io/s/charming-vaughan-l36vng?file=/main.js:2207-2306
PS. This also does not work in Safari on iOS (if I include touch event handlers to the code above). My Mac Safari version is 16.1.
This seems to be fixed in the latest Technology Preview (Release 160 (Safari 16.4, WebKit 18615.1.14.3)).
For the time being, you can workaround the issue by adding a super fast transition on the filter property, this will make current stable happy and update the filter as expected.
// Change brightness/contrast of the image by holding
// left mouse button on the image and moving cursor.
// Moving horizontally changes brightness,
// moving vertically changes contrast.
class Brightness {
constructor(element) {
this.element = element;
// x and y mouse coordinates of the cursor
// when the brightness change was started
this.startPosition = null;
this.brightnessPercent = 100;
// Current brightness/contrast percentage.
this.currentAmount = {
brightness: 100,
contrast: 100
};
// True if the user holds left mouse bottom, which
// indicates that brightness is being changed.
// False by default or when the left mouse button is released.
this.active = false;
this.addEventListeners();
}
addEventListeners() {
let element = this.element;
// Start changing brightness
// -----------------
element.addEventListener("mousedown", (e) => {
if (e.button !== 0) return; // Not a left mouse button
this.active = true;
e.preventDefault();
this.startChange(e);
});
// End changing brightness
// -----------------
document.addEventListener("mouseup", () => {
this.active = false;
});
// Drag the pointer over the bar
// -----------------
document.addEventListener("mousemove", (e) => {
if (!this.active) return;
this.change(e);
});
}
startChange(e) {
this.startPosition = this.positionFromCursor(e);
}
change(e) {
let position = this.positionFromCursor(e);
let xChange = position.x - this.startPosition.x;
this.changeCurrentAmount(xChange, "brightness");
let yChange = position.y - this.startPosition.y;
this.changeCurrentAmount(yChange, "contrast");
this.changeImageStyle();
}
changeCurrentAmount(change, type) {
change /= 2; // Decrease rate of change
change = Math.round(change);
let amount = 100 + change;
if (type === "contrast") amount = 100 - change;
if (amount < 0) amount = 0;
this.currentAmount[type] = amount;
}
changeImageStyle() {
let brightness = this.currentAmount.brightness;
let contrast = this.currentAmount.contrast;
let css = `brightness(${brightness}%) contrast(${contrast}%)`;
this.element.style.filter = css;
}
positionFromCursor(e) {
let pointerX = e.pageX;
let pointerY = e.pageY;
if (e.touches && e.touches.length > 0) {
pointerX = e.touches[0].pageX;
pointerY = e.touches[0].pageY;
}
return { x: pointerX, y: pointerY };
}
}
document.addEventListener("DOMContentLoaded", function () {
const imageElement = document.querySelector(".Image");
new Brightness(imageElement);
});
.Image {
/* Safari bug workaround */
transition: filter 1e-6s linear;
}
<img
class="Image"
width="512"
height="512"
src="https://64.media.tumblr.com/df185589006321d70d37d1a59040d7c3/df57f19b4b4b783a-cb/s250x400/e76347d6b1cb4aa08839036fb0407a9f6108a0ab.jpg"
/>