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;
}