From bcc3bc4fd75663bafd3657565e4f6d2e7de4b266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:47:58 +0900 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20MkLightbox=E3=81=AE=E5=8B=95?= =?UTF-8?q?=E7=94=BB=E3=81=AE=E7=B8=A6=E6=A8=AA=E6=AF=94=E3=82=92=E4=BA=8B?= =?UTF-8?q?=E5=89=8D=E3=81=AB=E7=A2=BA=E5=AE=9A=E3=81=95=E3=81=9B=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=20(#17822)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(frontend): MkLightboxの動画の縦横比を事前に確定させるように * fix * fix --- .../src/components/MkLightbox.item.vue | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/components/MkLightbox.item.vue b/packages/frontend/src/components/MkLightbox.item.vue index 91751f16b5..d358f20767 100644 --- a/packages/frontend/src/components/MkLightbox.item.vue +++ b/packages/frontend/src/components/MkLightbox.item.vue @@ -83,16 +83,16 @@ SPDX-License-Identifier: AGPL-3.0-only v-else-if="content.type === 'video'" ref="videoEl" data-gallery-click-action="video" - :class="$style.content" + :class="[$style.video, { [$style.videoSized]: videoAspectRatio != null }]" :src="content.url" :alt="content.file?.comment ?? undefined" draggable="false" :controls="prefer.s.useNativeUiForVideoAudioPlayer" playsinline - @loadedmetadata="originalContentLoaded = true" + @loadedmetadata="onVideoLoadedMetadata" @click.stop="onVideoClick" > -
+
@@ -224,6 +224,21 @@ const isVideoPlaying = computed(() => videoControl.value?.isPlaying ?? false); const isVideoActuallyPlaying = computed(() => videoControl.value?.isActuallyPlaying ?? false); let canOpenAnimation = false; +const videoAspectRatio = ref( + props.content.width != null && props.content.height != null && props.content.width > 0 && props.content.height > 0 + ? props.content.width / props.content.height + : null +); + +function onVideoLoadedMetadata() { + originalContentLoaded.value = true; + + // ドライブ上のメタデータが無い場合に限り、動画自体の初期サイズから縦横比を確定させる + if (videoAspectRatio.value != null) return; + if (videoEl.value == null || videoEl.value.videoWidth === 0 || videoEl.value.videoHeight === 0) return; + videoAspectRatio.value = videoEl.value.videoWidth / videoEl.value.videoHeight; +} + const headerSize = 30; const footerSize = props.content.type === 'video' && !prefer.s.useNativeUiForVideoAudioPlayer ? 80 : 0; @@ -941,6 +956,25 @@ defineExpose({ object-fit: contain; } +.video { + display: block; + user-select: none; + position: absolute; + top: 50%; + left: 50%; + translate: -50% -50%; + width: 100%; + height: 100%; + object-fit: contain; +} + +.videoSized { + width: min(100cqw, calc(100cqh * v-bind("videoAspectRatio ?? 16 / 9"))); + height: auto; + background-color: #000; + aspect-ratio: v-bind("videoAspectRatio ?? 16 / 9"); +} + .loading { position: absolute; top: 0; @@ -969,6 +1003,8 @@ defineExpose({ position: relative; width: 100%; height: 100%; + // .videoSizedが使う100cqw / 100cqhの基準 (= paddingを除いた実際の表示領域) + container-type: size; transition: scale 200ms ease, opacity 200ms ease !important; } @@ -985,6 +1021,7 @@ defineExpose({ height: 100%; display: grid; place-items: center; + pointer-events: none; } .playIcon { @@ -1000,8 +1037,8 @@ defineExpose({ transition: scale 100ms ease; } -.playIconWrapper:hover .playIcon, -.playIcon:hover { +// アイコン自体はクリックを受け取らないので、hoverは下のvideo要素を経由して拾う +.video:hover ~ .playIconWrapper .playIcon { scale: 1.2; }