I am integrating multiple video players (Plyr, Video.js, and a proprietary player) into my React application and am facing issues with maintaining consistent sizes and aspect ratios across all players. Despite setting the width and aspect ratio through CSS and player options, Plyr does not adhere to the specified dimensions. The rest of the other 2 players are working fine and as expected.
Here’s the relevant part of my CSS and JavaScript setup:
index.js
useEffect(() => {
if (videoRef.current) {
if (isCustomPlayer) {
// Custom player initialization
if (playerRef.current) {
playerRef.current.dispose();
playerRef.current = null;
}
videoRef.current.addEventListener('timeupdate', handleTimeUpdate);
videoRef.current.src = videoData?.video_link || '';
const currentTime = videoRef.current.currentTime;
setCurrentTime(currentTime);
} else if (isPlyrPlayer) {
// Initialize Plyr
if (!playerRef.current) {
playerRef.current = new Plyr(videoRef.current, {
controls: [
'play-large', 'restart', 'rewind', 'play', 'fast-forward', 'progress', 'current-time', 'duration', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', 'fullscreen'
],
});
playerRef.current.source = {
type: 'video',
sources: [
{
src: videoData?.video_link,
type: 'video/mp4',
},
],
};
playerRef.current.on('timeupdate', () => {
const currentTime = playerRef.current.currentTime;
setCurrentTime(currentTime);
});
}
} else {
// Video.js player initialization
if (!playerRef.current) {
playerRef.current = videojs(videoRef.current, {
controls: true,
autoplay: false,
preload: 'auto',
sources: [
{
src: videoData?.video_link,
type: 'video/mp4',
},
],
});
playerRef.current.on('timeupdate', () => {
const currentTime = playerRef.current.currentTime();
setCurrentTime(currentTime);
});
}
}
}
return () => {
if (videoRef.current) {
videoRef.current.removeEventListener('timeupdate', handleTimeUpdate);
}
if (playerRef.current) {
playerRef.current.destroy ? playerRef.current.destroy() : playerRef.current.dispose();
playerRef.current = null;
}
};
}, [isCustomPlayer, isPlyrPlayer, videoData]);
{isCustomPlayer ? (
<div key="custom-player">
<video
id="video-player"
className={isShortVideo ? 'short-video-container' : 'video-container'}
ref={videoRef}
controls
controlslist="nodownload"
disablePictureInPicture
></video>
</div>
) : isPlyrPlayer ? (
<div key="plyr-player">
<video
id="video-player"
ref={videoRef}
className={`plyr-container ${isShortVideo ? 'short-video-container' : 'video-container'}`}
controls
></video>
</div>
) : (
<div key="video-js-player">
<video
id="video-player"
ref={videoRef}
className={`video-js vjs-default-skin vjs-big-play-centered ${isShortVideo ? 'short-video-container' : 'video-container'}`}
controls
></video>
</div>
)}
styles.css
aspect-ratio: 16 / 9;
width: 100%;
height: auto;
}
.video-js .vjs-tech {
object-fit: contain;
/* Preserves aspect ratio, but might keep black bars */
}
.plyr-container {
position: relative;
width: 100%;
padding-top: 56.25%;
}
.plyr-container video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
Problems Encountered:
- The Plyr player does not respect the aspect ratio settings defined in CSS.
- Plyr player sizing behaves inconsistently when compared to Video.js and the proprietary player.
Questions:
- How can I ensure that the Plyr player respects the same sizing and aspect ratio as other players in the application?
- Is there a more effective method to enforce CSS rules on Plyr without interfering with its native handling of video scaling?
Any insights or recommendations on achieving consistent player sizing in a React environment would be highly appreciated.
Plyr might be overriding some CSS properties, which is why your settings aren’t working as expected.
-
Fixing Aspect ratio for Plyr
plyr creates additional wrapper elements that can interfere with direct CSS control over the video element. To ensure the aspect ratio works as expected, you need to control both the wrapper element and the video element inside.I will give you the updated CSS for Playr
<code> /* Wrapper for the Plyr player */.plyr-container {position: relative;width: 100%; /* Ensures it fills the parent container */padding-top: 56.25%; /* Aspect ratio: 16:9 (9 / 16 = 0.5625) */height: 0; /* Important for aspect ratio handling */overflow: hidden; /* Prevents content overflow */}/* Ensures the video element respects the parent container's dimensions */.plyr-container video {position: absolute;top: 0;left: 0;width: 100%;height: 100%;object-fit: contain; /* This will maintain aspect ratio and fit within the bounds */}</code><code> /* Wrapper for the Plyr player */ .plyr-container { position: relative; width: 100%; /* Ensures it fills the parent container */ padding-top: 56.25%; /* Aspect ratio: 16:9 (9 / 16 = 0.5625) */ height: 0; /* Important for aspect ratio handling */ overflow: hidden; /* Prevents content overflow */ } /* Ensures the video element respects the parent container's dimensions */ .plyr-container video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: contain; /* This will maintain aspect ratio and fit within the bounds */ } </code>/* Wrapper for the Plyr player */ .plyr-container { position: relative; width: 100%; /* Ensures it fills the parent container */ padding-top: 56.25%; /* Aspect ratio: 16:9 (9 / 16 = 0.5625) */ height: 0; /* Important for aspect ratio handling */ overflow: hidden; /* Prevents content overflow */ } /* Ensures the video element respects the parent container's dimensions */ .plyr-container video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: contain; /* This will maintain aspect ratio and fit within the bounds */ }
-
Enforcing consistency across all players
So you want to ensure that Plyr, Video.js, and your proprietary player behave consistently.<code> /* Shared styling for all video containers */.video-container, .short-video-container, .plyr-container {position: relative;width: 100%;padding-top: 56.25%; /* For 16:9 aspect ratio */height: 0;overflow: hidden;}/* Apply to video.js player */.video-js {position: absolute;top: 0;left: 0;width: 100%;height: 100%;object-fit: contain;}/* Apply to the custom player video and Plyr */.video-container video,.plyr-container video,.short-video-container video {position: absolute;top: 0;left: 0;width: 100%;height: 100%;object-fit: contain;}</code><code> /* Shared styling for all video containers */ .video-container, .short-video-container, .plyr-container { position: relative; width: 100%; padding-top: 56.25%; /* For 16:9 aspect ratio */ height: 0; overflow: hidden; } /* Apply to video.js player */ .video-js { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: contain; } /* Apply to the custom player video and Plyr */ .video-container video, .plyr-container video, .short-video-container video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: contain; } </code>/* Shared styling for all video containers */ .video-container, .short-video-container, .plyr-container { position: relative; width: 100%; padding-top: 56.25%; /* For 16:9 aspect ratio */ height: 0; overflow: hidden; } /* Apply to video.js player */ .video-js { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: contain; } /* Apply to the custom player video and Plyr */ .video-container video, .plyr-container video, .short-video-container video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: contain; }
Adjusting JavaScript for Plyr Player
In some cases, Plyr might interfere with CSS sizing due to its own settings. You can disable certian native behaviors or set the aspect ratio in the Plyr options when initializing the player.
So change index.js like this
if (!playerRef.current) {
playerRef.current = new Plyr(videoRef.current, {
controls: [
'play-large', 'restart', 'rewind', 'play', 'fast-forward', 'progress', 'current-time',
'duration', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', 'fullscreen'
],
ratio: '16:9', // Enforces the 16:9 aspect ratio in Plyr settings
fullscreen: {
enabled: true, // Ensures proper scaling in fullscreen mode
fallback: true,
iosNative: true
}
});
playerRef.current.source = {
type: 'video',
sources: [
{
src: videoData?.video_link,
type: 'video/mp4',
}
]
};
playerRef.current.on('timeupdate', () => {
const currentTime = playerRef.current.currentTime;
setCurrentTime(currentTime);
});
}