mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
fix: eliminate black bars in video modal player
Enforce full-width/height video display and dynamic object-fit logic to prevent letterboxing and layout gaps. - Add robust CSS overrides to 'css/tailwind.source.css' to ensure video fills the stage. - Update 'VideoModal.js' to dynamically switch between 'cover' and 'contain' based on aspect ratio match. - Handle ambient canvas positioning to prevent layout shifts.
This commit is contained in:
1 parent
1a86b82fea
commit
b9f7ffd95e
2 files changed
+132
-25
No files matched your search
+57
-25
@@ -6102,43 +6102,75 @@
|
||||
|
||||
/* Embed & Video Modal Fixes */
|
||||
@layer components {
|
||||
/* ensure the video fills the stage and doesn't show a black strip */
|
||||
#embedVideo,
|
||||
/* Force the video stage to let the video fully fill it and prevent 80vh constraints */
|
||||
.video-modal__stage,
|
||||
.video-modal__video,
|
||||
.video-modal__video > .video-modal__media,
|
||||
.video-modal__video video#modalVideo,
|
||||
.video-modal__video .video-modal__media {
|
||||
display: block;
|
||||
.video-modal__panel {
|
||||
/* allow child to fill: do not let other rules limit height */
|
||||
max-height: none !important;
|
||||
height: 100% !important;
|
||||
min-height: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
display: flex !important;
|
||||
align-items: stretch !important; /* allows the video to stretch vertically */
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
/* Prevent any earlier max-height on modal container from clashing */
|
||||
.bv-modal__panel[role="dialog"],
|
||||
.bv-modal__panel {
|
||||
max-height: none !important;
|
||||
}
|
||||
|
||||
/* Definitive video rules */
|
||||
#modalVideo,
|
||||
.video-modal__media {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center center;
|
||||
max-width: 100% !important;
|
||||
max-height: 100% !important; /* ensure no earlier max-height causes clipping */
|
||||
object-fit: cover !important; /* or contain if you prefer letterbox */
|
||||
object-position: center center !important;
|
||||
background: transparent !important;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
/* make sure the stage wrapper doesn’t add bottom padding/space */
|
||||
.video-modal__stage,
|
||||
.video-modal__video {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
/* permanent class to force fill */
|
||||
.video-modal__media--fill {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
max-width: 100% !important;
|
||||
max-height: 100% !important;
|
||||
object-position: center center !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.video-modal__stage {
|
||||
position: relative; /* ensure ambient is absolutely positioned relative to stage */
|
||||
overflow: hidden; /* clip any bleed visually; prevents layout expansion */
|
||||
}
|
||||
|
||||
.video-modal__ambient {
|
||||
position: absolute;
|
||||
inset: calc(var(--video-modal-ambient-bleed) * -1);
|
||||
pointer-events: none; /* ensure it never captures pointer events */
|
||||
z-index: 0; /* behind content */
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
/* ensure video is above ambient */
|
||||
.video-modal__video { position: relative; z-index: 1; }
|
||||
|
||||
/* if there is an ambient canvas or overlay, ensure it doesn't change layout */
|
||||
.video-modal__ambient,
|
||||
.video-modal__ambient-canvas {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Logo accent wiring */
|
||||
|
||||
@@ -390,6 +390,81 @@ export class VideoModal {
|
||||
) {
|
||||
this.modalVideo = videoElement;
|
||||
this.bindVideoEvents();
|
||||
|
||||
try {
|
||||
if (this.modalVideo) {
|
||||
// give the element the fill class so CSS can control layout
|
||||
this.modalVideo.classList.add("video-modal__media--fill");
|
||||
|
||||
// ensure the stage/wrapper allow stretching (safety)
|
||||
const videoWrap =
|
||||
this.playerModal?.querySelector(".video-modal__video") ||
|
||||
this.document.querySelector(".video-modal__video");
|
||||
|
||||
if (videoWrap) {
|
||||
videoWrap.style.display = "flex";
|
||||
videoWrap.style.alignItems = "stretch";
|
||||
videoWrap.style.justifyContent = "center";
|
||||
videoWrap.style.padding = "0";
|
||||
}
|
||||
|
||||
// choose object-fit dynamically after metadata loads so we can inspect intrinsic size:
|
||||
const decideObjectFit = () => {
|
||||
try {
|
||||
const vw =
|
||||
this.modalVideo.videoWidth ||
|
||||
this.modalVideo.naturalWidth ||
|
||||
this.modalVideo.clientWidth;
|
||||
const vh =
|
||||
this.modalVideo.videoHeight ||
|
||||
this.modalVideo.naturalHeight ||
|
||||
this.modalVideo.clientHeight;
|
||||
const wrap = this.modalVideo.parentElement;
|
||||
const cw = wrap ? wrap.clientWidth : this.modalVideo.clientWidth;
|
||||
const ch = wrap ? wrap.clientHeight : this.modalVideo.clientHeight;
|
||||
|
||||
// If we can't compute, default to cover
|
||||
if (!vw || !vh || !cw || !ch) {
|
||||
this.modalVideo.style.objectFit = "cover";
|
||||
return;
|
||||
}
|
||||
|
||||
const videoRatio = vw / vh;
|
||||
const containerRatio = cw / ch;
|
||||
const diff = Math.abs(containerRatio - videoRatio);
|
||||
|
||||
// if aspect ratios are close, prefer contain to avoid cropping small edges,
|
||||
// otherwise use cover to avoid large letterbox bars
|
||||
const THRESHOLD = 0.12; // tweakable
|
||||
this.modalVideo.style.objectFit =
|
||||
diff > THRESHOLD ? "cover" : "contain";
|
||||
} catch (e) {
|
||||
this.modalVideo.style.objectFit = "cover";
|
||||
}
|
||||
};
|
||||
|
||||
if (this.modalVideo.readyState >= 1) {
|
||||
// metadata already available
|
||||
decideObjectFit();
|
||||
} else {
|
||||
const onMeta = () => {
|
||||
decideObjectFit();
|
||||
this.modalVideo.removeEventListener("loadedmetadata", onMeta);
|
||||
};
|
||||
this.modalVideo.addEventListener("loadedmetadata", onMeta);
|
||||
}
|
||||
|
||||
// always ensure background transparent
|
||||
this.modalVideo.style.background = "transparent";
|
||||
this.modalVideo.style.objectPosition = "center center";
|
||||
}
|
||||
} catch (err) {
|
||||
// swallow, but log for diagnostics
|
||||
this.logger?.log?.(
|
||||
"[VideoModal] setVideoElement style enforcement failed",
|
||||
err
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.modalVideo = null;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user