Fix the animation of dialogs in Safari
authorAlexander Ebert <ebert@woltlab.com>
Sat, 20 May 2023 16:53:52 +0000 (18:53 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 20 May 2023 16:53:52 +0000 (18:53 +0200)
Safari executes the resize observer asynchronously, causing the offset to be not calculated when the dialog was just added to the DOM.

In addition the `contentBoxSize` was observed to report the width of the element without any borders. We are able to simplify the code by querying the client rect instead which reports the proper width.

Fixes #5519

ts/WoltLabSuite/Core/Ui/Dialog.ts
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Dialog.js
wcfsetup/install/files/style/ui/dialog.scss

index f8e1473727ba98758ce6d43b77c0df5489160c18..fbb338dc4958592ba6662caf70d858186db499e4 100644 (file)
@@ -403,23 +403,10 @@ const UiDialog = {
     // elements to be squished together. The actual value for
     // `transform` must not use percent values, because this
     // causes blurry text rendering in Chromium.
-    const resizeObserver = new ResizeObserver((entries) => {
+    const resizeObserver = new ResizeObserver(() => {
       if (dialog.getAttribute("aria-hidden") === "false") {
-        for (const entry of entries) {
-          let width: number;
-          if (entry.contentBoxSize) {
-            const contentBoxSize: ResizeObserverSize = Array.isArray(entry.contentBoxSize)
-              ? entry.contentBoxSize[0]
-              : entry.contentBoxSize;
-            width = contentBoxSize.inlineSize;
-          } else {
-            // Safari < 15.4 supports only the older spec.
-            width = entry.contentRect.width;
-          }
-
-          const offset = Math.floor(width / 2);
-          dialog.style.setProperty("--translate-x", `-${offset}px`);
-        }
+        const offset = Math.floor(dialog.getBoundingClientRect().width / 2);
+        dialog.style.setProperty("--translate-x", `-${offset}px`);
       }
     });
     resizeObserver.observe(dialog);
@@ -637,6 +624,9 @@ const UiDialog = {
     const maximumHeight = window.innerHeight * (_dialogFullHeight ? 1 : 0.8) - unavailableHeight;
     contentContainer.style.setProperty("max-height", `${~~maximumHeight}px`, "");
 
+    const offset = Math.floor(data.dialog.getBoundingClientRect().width / 2);
+    data.dialog.style.setProperty("--translate-x", `-${offset}px`);
+
     const callbackObject = _dialogToObject.get(id);
     //noinspection JSUnresolvedVariable
     if (callbackObject !== undefined && typeof callbackObject._dialogSubmit === "function") {
index 2b71adca3f5339d4476fe27f2b94d99de8342c97..33fc124653edeeb6072b190c934c9770b96b9335 100644 (file)
@@ -331,23 +331,10 @@ define(["require", "exports", "tslib", "../Core", "../Dom/Change/Listener", "./S
             // elements to be squished together. The actual value for
             // `transform` must not use percent values, because this
             // causes blurry text rendering in Chromium.
-            const resizeObserver = new ResizeObserver((entries) => {
+            const resizeObserver = new ResizeObserver(() => {
                 if (dialog.getAttribute("aria-hidden") === "false") {
-                    for (const entry of entries) {
-                        let width;
-                        if (entry.contentBoxSize) {
-                            const contentBoxSize = Array.isArray(entry.contentBoxSize)
-                                ? entry.contentBoxSize[0]
-                                : entry.contentBoxSize;
-                            width = contentBoxSize.inlineSize;
-                        }
-                        else {
-                            // Safari < 15.4 supports only the older spec.
-                            width = entry.contentRect.width;
-                        }
-                        const offset = Math.floor(width / 2);
-                        dialog.style.setProperty("--translate-x", `-${offset}px`);
-                    }
+                    const offset = Math.floor(dialog.getBoundingClientRect().width / 2);
+                    dialog.style.setProperty("--translate-x", `-${offset}px`);
                 }
             });
             resizeObserver.observe(dialog);
@@ -528,6 +515,8 @@ define(["require", "exports", "tslib", "../Core", "../Dom/Change/Listener", "./S
             unavailableHeight += Util_1.default.outerHeight(data.header);
             const maximumHeight = window.innerHeight * (_dialogFullHeight ? 1 : 0.8) - unavailableHeight;
             contentContainer.style.setProperty("max-height", `${~~maximumHeight}px`, "");
+            const offset = Math.floor(data.dialog.getBoundingClientRect().width / 2);
+            data.dialog.style.setProperty("--translate-x", `-${offset}px`);
             const callbackObject = _dialogToObject.get(id);
             //noinspection JSUnresolvedVariable
             if (callbackObject !== undefined && typeof callbackObject._dialogSubmit === "function") {
index 993fd7ee1f7534c7c2229fbd5a2168ddf6e6f1b5..8e0a99afff9506559d05131bcc7bc0dbbb65e1f0 100644 (file)
 @keyframes wcfDialog {
        0% {
                visibility: visible;
-               transform: translateX(var(--translate-x, 0)) translateY(calc(-50% - 20px));
-               //top: 8%;
+               transform: translateX(var(--translate-x)) translateY(calc(-50% - 20px));
        }
        100% {
                visibility: visible;
-               //top: 10%;
+               transform: translateX(var(--translate-x)) translateY(-50%);
        }
 }
 
@@ -71,7 +70,7 @@
                // this causes a blurry text rendering in Chromium.
                // The offset is calculated using a `ResizeObserver`.
                left: 50%;
-               transform: translateX(var(--translate-x, 0)) translateY(-50%);
+               transform: translateX(var(--translate-x)) translateY(-50%);
 
                &[aria-hidden="false"] {
                        animation: wcfDialog 0.24s;