How to make ReactPlayer scale with height and width
Asked Answered
V

11

13

I am using reactplayer for a youtube video which uses iframe. I am trying to scale the video to my div and I want it to be responsive.

I put a width and height at 100% on the ReactPlayer, and I have a wrapper div that I put height and width on, but the reactplayer does not fit the div. It is stuck at a height of 150px no matter how I resize the screen.

<div className="video-wrapper>
  <ReactPlayer
            width="100%"
            height="100%"
            url="https://youtu.be/BGhqlJnFIXU"
            controls
            muted
            config={{
              youtube: {
                playerVars: { showinfo: 1 }
              }
            }}
          />
</div>

.css

.video-wrapper {
 height: 100%;
 width: 100%;
 min-height: 225px;
}
Volkman answered 20/3, 2018 at 20:48 Comment(1)
For a more comprehensive solution, see github.com/CookPete/react-player/issues/145Homemaker
Q
24

This can be easily achieved by further-extending your CSS. Since most videos are shot in 16:9, following this guide by Chris Coyier will make the process easily achievable.

Since you're utilizing React-Player, I am working with the content located on their demo page.

.player-wrapper {
  width: auto; // Reset width
  height: auto; // Reset height
}
.react-player {
  padding-top: 56.25%; // Percentage ratio for 16:9
  position: relative; // Set to relative
}

.react-player > div {
  position: absolute; // Scaling will occur since parent is relative now
}

Why it works?

TL;DR - Padding in percentages is based on width. By setting an element's height to 0, we can utilize a percentage for 'padding-top' to scale content perfectly.

Generate 16:9's Percentage

(9 / 16) * 100 = 56.25

Quent answered 20/3, 2018 at 21:58 Comment(5)
there is a issue where the parent of .player-wrapper is having 0 width in some cases... my case i set the with of the parent of .player-wrapper to 100% and it was good.Flesh
I'd like to point out this hack is now redundant with the advent of the css "aspect-ratio: 16/9;" on a wrapper div your woes will disappear.Dolly
@Dolly Not completely redundant due to browser support, unfortunately. Aspect-ratio works fine for most browsers, but you'll still want to leverage CSS supports as a fallback if you're looking to achieve a universal experience. @supports not (aspect-ratio: 1 / 1) { // add CSS hack here }Quent
Working perfectly but I also had to add top: 0; to the .react-player > div selector for my case.Jeer
But it does not work for light prop to show thumbnailFlatting
A
13

To force react-player be fully responsive I did the following:

CSS

.player-wrapper {
  position: relative;
  padding-top: 56.25%; /* 720 / 1280 = 0.5625 */
}

.react-player {
  position: absolute;
  top: 0;
  left: 0;
}

JSX

import React from "react";
import ReactPlayer from "react-player";
import "./Player.css";

const Player = () => (
  <div className="player-wrapper">
    <ReactPlayer
      url="https://youtu.be/3eLrINg3O2Q"
      className="react-player"
      playing
      width="100%"
      height="100%"
      controls={false}
    />
  </div>
);

export default Player;
Acquiescent answered 9/1, 2021 at 8:38 Comment(3)
Followed your advice (using CSS modules) - the wrapper takes up the space but the player does not appear..Briefless
I tried it again - working great. Check you code. Check example jsfiddle.net/e6w3rtj1Acquiescent
Great answer, thanks!Skuld
H
7

The Easiest way to make the it responsive is adding the widht as 100%

<ReactPlayer
  controls
  pip
  width="100%"
  url={_post.videolink}
 /> 
Hasidism answered 5/11, 2021 at 13:11 Comment(0)
A
5

For a more modern approach, just add a class to the react player component and set it to:

height: auto !important;
aspect-ratio: 16/9;

https://caniuse.com/mdn-css_properties_aspect-ratio

Ario answered 8/3, 2022 at 9:29 Comment(1)
Yep. Why it is not the best answer ? 😇Danicadanice
K
2

you can fill with:

 .react-player > video {
   position: absolute;
   object-fit: fill;
 }
Krasner answered 10/12, 2021 at 22:31 Comment(0)
C
1

If you are using Tailwindcss and Swiper you can use this code

This code implements the last aspect-video class to ensure the aspect ratio always be correct

And also ensure that if the user scroll to the next page, the previous player gets paused

You can also set Max width of videos , here its "max-w-6xl"

import React, { useEffect, useState } from 'react'
import ReactPlayer from 'react-player'
import { Swiper, SwiperSlide } from 'swiper/react';
import { Pagination } from "swiper";
const videos = [
  {
    id: 1,
    url: "https://www.youtube.com/watch?v=1234"
  },
  {
    id: 2,
    url: "https://www.youtube.com/watch?v=1234"
  },
  {
    id: 3,
    url: "https://www.youtube.com/watch?v=1234"
  }
];

const IndexHero = () => {
  const [domLoaded, setDomLoaded] = useState(false);
  const [isPlaying, setIsPlaying] = useState(null);
  useEffect(() => {
    setDomLoaded(true);
  }, []);

  return (
    <>
    <div className='h-auto'>
      {!domLoaded && (
        <div className="flex items-start justify-center">
          <div className="flex-1 max-w-6xl">
            <div className="aspect-video">
            {/** For CLS */}
            </div>
          </div>
        </div>
      )}
      {domLoaded && (
      <Swiper
          modules={[Pagination]} 
          pagination={true} 
          className="h-full "
          onSlideChange={() => {
            setIsPlaying(null);
          }}
          autoplay={false}
          watchSlidesProgress={true}
        >
          {videos.map((data) => (
            <SwiperSlide key={data.id}>

              <div className="flex items-start justify-center">
                <div className="flex-1 max-w-6xl"> 
                  <div className="aspect-video">
                  <ReactPlayer
                      key={data.id}
                      url={data.url}
                      width="100%"
                      height="100%"
                      controls={true}
                      onPlay={() => {
                        setIsPlaying(data.id);
                      }}
                      playing={isPlaying === data.id}
                    />
                  </div>
                </div>
              </div>              
            </SwiperSlide>
            ))}
        </Swiper> )}
      </div>
    </>
  );
};

export default IndexHero;
Crag answered 17/1, 2023 at 20:19 Comment(0)
Q
0

you can keep the width fixed and then allow the height to adjust according to the video height as different video has its own size like 100*200. .video-wrapper > video { width: 55vw; height: min-content; }

Quillan answered 30/3, 2021 at 7:35 Comment(0)
H
0

Here is a easy fix that works for me, I hope it do it for you too

  const videoRef = useRef<ReactPlayer>(null!)

  const beginningHandler = () => {
    const videoTag = videoRef.current.getInternalPlayer() as HTMLVideoElement;
    videoTag.style.objectFit = 'cover';
  }

  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <ReactPlayer
        ref={videoRef}
        volume={1}
        onEnded={() => console.log('finish')}
        url={'./videos/time-travel.mp4'}
        width={'100%'}
        height={'100%'}
        playing
        onStart={beginningHandler}
      />
    </div>
  )
Hassle answered 23/5, 2023 at 6:30 Comment(0)
A
0

I think it can help someone.

.react-player video {
  object-fit: fill !important;
}
Animosity answered 14/5 at 9:32 Comment(0)
K
0

Something like this can fill the parent with a specific ratio. You just put the video player inside and choose the ratio.

// your-file.tsx
<KeepAspect aspect={16 / 9} className='h-full' objectFit={'cover'}>
  <div className='flex h-full w-full items-center justify-center'>
    <ReactPlayer
      url={...}
      playing
      muted
      width='100%'
      height='100%'
      controls={false}
      loop
      className='object-cover'
    />
  </div>
</KeepAspect>

// keep-aspect.tsx
import { useEffect, useRef, useState } from 'react'

import { cn } from '@/lib/utils'

export const KeepAspect = (p: {
  className?: string
  aspect: number
  objectFit: 'cover' | 'contain'
  children: React.ReactNode
}) => {
  const [outerSize, setOuterSize] = useState({ width: 0, height: 0 })
  const ref = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const handleResize = () => {
      if (ref.current) {
        setOuterSize({
          width: ref.current.offsetWidth,
          height: ref.current.offsetHeight,
        })
      }
    }

    handleResize()
    window.addEventListener('resize', handleResize)
    return () => window.removeEventListener('resize', handleResize)
  }, [])

  const innerWidthWidth = outerSize.width
  const innerHeightWidth = outerSize.width / p.aspect

  const innerWidthHeight = outerSize.height * p.aspect
  const innerHeightHeight = outerSize.height

  const baseOnWidth =
    p.objectFit === 'cover'
      ? innerHeightWidth > outerSize.height
      : innerHeightWidth < outerSize.height

  const innerWidth = baseOnWidth ? innerWidthWidth : innerWidthHeight
  const innerHeight = baseOnWidth ? innerHeightWidth : innerHeightHeight

  return (
    <div ref={ref} className={cn(p.className, 'relative')}>
      <div className='absolute inset-0 flex items-center justify-center'>
        <div
          className='h-full w-full'
          style={{
            minWidth: innerWidth,
            minHeight: innerHeight,
          }}
        >
          {p.children}
        </div>
      </div>
    </div>
  )
}
Kinsler answered 11/6 at 12:38 Comment(0)
M
-2

Here's how I did it.

video { object-fit: cover; }

Now, the size of the video can be adjusted by sizing the wrapper.

Muttonchops answered 28/10, 2022 at 7:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.