ipfs-hls-player
Version:
Video.js-based HLS player optimized for IPFS content-addressed storage
293 lines (250 loc) • 6.48 kB
CSS
/**
* IPFS HLS Player Styles
* Video.js customizations and fixes for IPFS HLS content
*
* @author Mark Giles
* @license MIT
*/
/* Fix black bar issue - remove margins from video element */
.ipfs-hls-player .vjs-tech {
margin: 0 ;
top: 0 ;
left: 0 ;
position: absolute ;
width: 100% ;
height: 100% ;
}
/* Ensure video expands properly in fullscreen regardless of inline styles */
.vjs-fullscreen .vjs-tech,
.ipfs-hls-player.vjs-fullscreen .vjs-tech {
max-width: none ;
max-height: none ;
width: 100% ;
height: 100% ;
}
/* Ensure video container fills space properly and contains absolutely positioned elements */
.ipfs-hls-player {
position: relative;
width: 100%;
aspect-ratio: 16/9; /* Provide proper aspect ratio for height reference */
height: auto;
}
.ipfs-hls-player .video-js {
background-color: #000;
width: 100% ;
height: 100% ;
position: absolute;
top: 0;
left: 0;
}
/* Fix poster and text track positioning */
.ipfs-hls-player .vjs-poster,
.ipfs-hls-player .vjs-text-track-display {
top: 0 ;
bottom: 0 ;
margin: 0 ;
}
/* Dark Theme Customizations */
.ipfs-hls-player .vjs-control-bar {
background: linear-gradient(to top, rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.7));
height: 3em;
}
.ipfs-hls-player .vjs-button > .vjs-icon-placeholder:before {
font-size: 1.8em;
line-height: 1.67;
}
/* Quality Selector Menu Styles */
.vjs-menu-button-popup .vjs-menu ul {
padding: 0 ;
margin: 0 ;
list-style: none ;
}
.vjs-menu-button-popup .vjs-menu ul li {
margin: 0 ;
}
.vjs-quality-selector .vjs-menu-item {
color: #adb5bd;
padding: 0.5em 1em;
}
.vjs-quality-selector .vjs-menu-item:hover {
background-color: rgba(255, 255, 255, 0.1);
color: #fff;
}
.vjs-quality-selector .vjs-menu-item.vjs-selected {
background-color: #007bff;
color: #fff;
}
/* Big Play Button */
.vjs-big-play-button {
background-color: rgba(17, 18, 34, 0.8) ;
border: 2px solid #007bff ;
border-radius: 50% ;
width: 80px ;
height: 80px ;
line-height: 80px ;
margin: -40px 0 0 -40px ;
}
.vjs-big-play-button:hover {
background-color: #007bff ;
border-color: #007bff ;
}
/* Loading Spinner */
.vjs-loading-spinner {
border-color: #007bff ;
}
/* Progress Bar */
.vjs-play-progress {
background-color: #007bff ;
}
.vjs-load-progress {
background-color: rgba(255, 255, 255, 0.3) ;
}
.vjs-progress-control:hover .vjs-progress-holder {
font-size: 1.2em;
}
/* Volume Bar */
.vjs-volume-level {
background-color: #007bff;
}
/* Time Display */
.vjs-current-time,
.vjs-duration,
.vjs-time-divider {
display: block;
padding: 0 0.5em;
}
/* Fullscreen Button */
.vjs-fullscreen-control {
position: absolute;
right: 0;
}
/* Mobile Responsive */
@media (max-width: 768px) {
.vjs-control-bar {
height: 2.5em;
}
.vjs-button > .vjs-icon-placeholder:before {
font-size: 1.5em;
}
.vjs-big-play-button {
width: 60px ;
height: 60px ;
line-height: 60px ;
margin: -30px 0 0 -30px ;
}
/* Hide some controls on mobile */
.vjs-playback-rate,
.vjs-chapters-button {
display: none;
}
}
/* Ensure proper aspect ratio */
.ipfs-hls-player.vjs-fluid,
.ipfs-hls-player.vjs-16-9,
.ipfs-hls-player.vjs-4-3 {
padding-top: 0 ;
}
/* Fix for IPFS videos - ensure proper object-fit */
.ipfs-hls-player video[src*="ipfs"],
.ipfs-hls-player video[src*="gateway"] {
object-fit: contain;
}
/* Preemptive video initialization - prevent flash of unstyled video */
/* Target all videos that aren't enhanced yet or Video.js tech elements */
video:not([data-ipfs-enhanced="true"]):not([id$="_html5_api"]) {
/* Establish proper size immediately */
width: 100%;
aspect-ratio: 16/9;
background-color: #000;
object-fit: contain;
/* Hide initially to prevent flash */
opacity: 0;
visibility: hidden;
/* Display block ensures consistent rendering */
display: block;
}
/* Container wrapper styles */
.ipfs-video-container {
width: 100%;
aspect-ratio: 16/9;
background-color: #000;
position: relative;
overflow: hidden;
}
/* Enhanced player container - base styles inherited from .ipfs-video-container */
/* Native player sizing - proper letterboxing with object-fit */
.ipfs-native-player {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
object-fit: contain; /* Maintains aspect ratio with letterboxing */
background-color: #000;
}
/* Modal video styles */
.modal .ipfs-hls-player .video-js {
max-height: 80vh;
}
/* Modal native player styles - prevent clipping */
.modal .ipfs-video-container.ipfs-hls-player {
max-height: 80vh;
aspect-ratio: 16/9;
}
.modal .ipfs-native-player {
max-height: 100%;
max-width: 100%;
}
/* Loading State Styles */
.ipfs-video-container.ipfs-video-loading video {
visibility: hidden;
opacity: 0;
}
/* Loading spinner */
.ipfs-video-container.ipfs-video-loading::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border: 4px solid rgba(255, 255, 255, 0.2);
border-top-color: #007bff;
border-radius: 50%;
animation: ipfs-spinner 0.8s linear infinite;
z-index: 10;
}
/* Spinner animation */
@keyframes ipfs-spinner {
to {
transform: translate(-50%, -50%) rotate(360deg);
}
}
/* Ready state - smooth reveal */
.ipfs-video-container.ipfs-video-ready video {
visibility: visible;
opacity: 1;
transition: opacity 0.3s ease-in-out;
}
/* Enhanced videos are always visible (unless in loading state) */
video[data-ipfs-enhanced="true"]:not(.ipfs-video-container.ipfs-video-loading video) {
visibility: visible;
opacity: 1;
}
/* Error state - show video anyway for fallback */
.ipfs-video-container.ipfs-video-error video {
visibility: visible;
opacity: 1;
}
/* Ensure Video.js players also respect loading states */
.ipfs-video-container.ipfs-video-loading .video-js {
visibility: hidden;
opacity: 0;
}
.ipfs-video-container.ipfs-video-ready .video-js {
visibility: visible;
opacity: 1;
transition: opacity 0.3s ease-in-out;
}