diff --git a/package.json b/package.json
index 7cf82a92..074f26e1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "impro",
- "version": "0.19.9",
+ "version": "0.19.10",
"type": "module",
"scripts": {
"start": "rm -rf \"${BUILD_DIR:-build}\" && NODE_ENV=development eleventy --serve",
diff --git a/src/css/style.css b/src/css/style.css
index d56d80b0..984c7676 100644
--- a/src/css/style.css
+++ b/src/css/style.css
@@ -2675,7 +2675,14 @@ animated-button {
border: var(--hair) solid var(--post-border-color);
border-radius: var(--video-border-radius);
overflow: hidden;
- transform: translateZ(0); /* Prevents video jiggle on iPadOS scroll */
+}
+
+/* Reserve the media height without CSS aspect-ratio, which can flicker while
+ * scrolling video elements in WebKit. Percentage padding is based on width. */
+.post-video::before {
+ content: "";
+ display: block;
+ padding-top: var(--post-video-height, 100%);
}
.post-video > .alt-indicator {
@@ -2731,7 +2738,8 @@ animated-button {
}
.post-video streaming-video {
- display: block;
+ position: absolute;
+ inset: 0;
width: 100%;
height: 100%;
}
@@ -2741,11 +2749,11 @@ animated-button {
width: 100%;
height: 100%;
object-fit: cover;
- transform: translateZ(0); /* Prevents video jiggle on iPadOS scroll */
}
.post-video img {
- display: block;
+ position: absolute;
+ inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
diff --git a/src/js/templates/postEmbed.template.js b/src/js/templates/postEmbed.template.js
index dab254f0..7a9f3777 100644
--- a/src/js/templates/postEmbed.template.js
+++ b/src/js/templates/postEmbed.template.js
@@ -276,6 +276,12 @@ function getPostMediaAspectRatio(media) {
return Math.max(ratio, MIN_POST_MEDIA_ASPECT_RATIO);
}
+function postVideoSizingStyle(aspectRatio) {
+ const ratio =
+ Number.isFinite(aspectRatio) && aspectRatio > 0 ? aspectRatio : 1;
+ return `--post-video-height: ${100 / ratio}%;`;
+}
+
function imageContainerTemplate({ image, lazyLoad, doCalculateAspectRatio }) {
return html`
![]()
{
e.stopPropagation();
e.preventDefault();
@@ -401,7 +407,7 @@ function openAltTextDialog(altText) {
function gifPlayerTemplate({ type = "video", uri, alt, aspectRatio = null }) {
return html`
${type === "video"
? html` {
return container.querySelector(".post-video");
}
- it("renders the aspect ratio inline on .post-video", () => {
+ it("reserves height from the video aspect ratio", () => {
const el = renderVideo({ width: 16, height: 9 });
assert(el !== null);
- assert.deepEqual(el.style.aspectRatio, String(16 / 9));
+ assert.deepEqual(
+ el.style.getPropertyValue("--post-video-height"),
+ "56.25%",
+ );
+ assert.deepEqual(el.style.aspectRatio, "");
});
it("caps tall videos at a 1:2 ratio", () => {
const el = renderVideo({ width: 1, height: 4 });
- assert.deepEqual(el.style.aspectRatio, String(1 / 2));
+ assert.deepEqual(el.style.getPropertyValue("--post-video-height"), "200%");
});
it("passes through wide videos without clamping", () => {
const el = renderVideo({ width: 5, height: 1 });
- assert.deepEqual(el.style.aspectRatio, "5");
+ assert.deepEqual(el.style.getPropertyValue("--post-video-height"), "20%");
});
- it("omits aspect-ratio when missing", () => {
+ it("reserves a square when the aspect ratio is missing", () => {
const el = renderVideo(undefined);
- assert.deepEqual(el.style.aspectRatio, "");
+ assert.deepEqual(el.style.getPropertyValue("--post-video-height"), "100%");
});
- it("omits aspect-ratio when invalid", () => {
+ it("reserves a square when the aspect ratio is invalid", () => {
const el = renderVideo({ width: 0, height: 0 });
- assert.deepEqual(el.style.aspectRatio, "");
+ assert.deepEqual(el.style.getPropertyValue("--post-video-height"), "100%");
});
it("renders a video with controls and no looping by default", () => {
@@ -304,9 +308,13 @@ describe("postEmbedTemplate - gif presentation video", () => {
);
});
- it("renders the aspect ratio inline on .post-video", () => {
+ it("reserves height from the gif aspect ratio", () => {
const el = renderGifVideo({ aspectRatio: { width: 16, height: 9 } });
- assert.deepEqual(el.style.aspectRatio, String(16 / 9));
+ assert.deepEqual(
+ el.style.getPropertyValue("--post-video-height"),
+ "56.25%",
+ );
+ assert.deepEqual(el.style.aspectRatio, "");
});
it("shows the ALT badge when alt text is present", () => {