How to make ReactPlayer scale with height and width - css

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

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

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;

The Easiest way to make the it responsive is adding the widht as 100%
<ReactPlayer
controls
pip
width="100%"
url={_post.videolink}
/>

you can fill with:
.react-player > video {
position: absolute;
object-fit: fill;
}

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

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

Here's how I did it.
video { object-fit: cover; }
Now, the size of the video can be adjusted by sizing the wrapper.

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;

Related

iFrame not detecting touch or scroll on mobile with 3D scene - Threejs - React Three

I have created a iFrame on my 3D website in which renders a path from my portfolio. I have been attempting to scroll or touch (mobile) this iFrame for a while now, the desktop version works fine, you can scroll, access pages, etc although on mobile, the touch event does not seem to happens.
I have searched several posts and fixes, but none of them made the touch event, or touch scroll from this iframe to work.
You can access my website through https://niltonsf.dev and on the top right select viewWebpage to focus on the html screen.
Here is the component in which renders the iframe:
import { Html } from "#react-three/drei";
import { Dispatch, SetStateAction } from "react";
import { isMobile } from "react-device-detect";
import * as THREE from "three";
interface MonitorProps {
geometry: THREE.BufferGeometry;
screen: THREE.Mesh;
bakedTexture: THREE.Texture;
setIsPointerOnHtml: Dispatch<SetStateAction<boolean>>;
isFocusOnHtml: boolean;
}
export default function Monitor({
geometry,
screen,
bakedTexture,
setIsPointerOnHtml,
isFocusOnHtml,
}: MonitorProps) {
return (
<>
<primitive object={screen}>
<group position={[-2.57, 1.8, -0.01]} rotation-y={1.565}>
<Html
transform
prepend
wrapperClass="htmlScreen"
scale={0.35}
distanceFactor={1.17}
zIndexRange={[0, 0]}
>
<div
onClick={(e) => {
if (!isFocusOnHtml) e.preventDefault();
}}
onPointerEnter={(e) => {
if (isFocusOnHtml) setIsPointerOnHtml(true);
}}
onPointerLeave={(e) => {
if (isFocusOnHtml) setIsPointerOnHtml(false);
}}
>
<iframe
id="iframe"
src="https://niltonsf.dev/static"
// src="http://192.168.1.13:3000/static"
title="myStaticWebsite"
style={{
width: isMobile ? 1200 : 1500,
}}
/>
</div>
</Html>
<mesh>
<planeGeometry args={[1.535, 0.69]} />
<meshPhysicalMaterial
blending={THREE.NoBlending}
opacity={0}
color={"black"}
side={THREE.DoubleSide}
/>
</mesh>
</group>
</primitive>
<mesh geometry={geometry}>
<meshBasicMaterial map={bakedTexture} />
</mesh>
</>
);
}
This is the main css file:
#root {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: white;
-webkit-overflow-scrolling: touch;
}
.htmlScreen iframe {
height: 700px;
border: none;
background: #000;
overflow-y: scroll;
touch-action: touch;
}
canvas {
touch-action: touch;
}
EDIT: It seems to be something with iPhones, Android devices work correctly

Get image height in React grid

I am making masonry grid gallery in React and I have trouble getting image height after load and before resizing it with grid. I have onLoad handler on img but there I get only already resized image height where it should be original, to use it to calculate number of row spans. I am aware it could be pure css problem, but I don't know how to solve it.
Here is my useEffect:
useEffect(() => {
if (imageRef.current && !loading) {
const height = imageRef.current.clientHeight;
console.log('height', height);
const spansCount = Math.ceil(height / 10 + 1);
setSpansCount(spansCount);
}
}, [imageRef.current, loading]);
And here is my render:
return (
<div
{...rest}
className={styles.gallery__item}
style={{ gridRowEnd: `span ${spansCount}` }}
>
<img
src={image.previewURL}
ref={imageRef}
className={styles.gallery__img}
alt={image.tags}
onLoad={handleLoad}
/>
<Placeholder
ref={loaderRef}
style={loading ? { display: 'block' } : { display: 'none' }}
/>
</div>
Here is my non working Codesandbox.
And here is working Codesandbox with react-load-image package, but I am not sure why this is working and the first one isn't.
I just needed to change this css on image:
.gallery__img {
width: 100%;
height: auto; // not 100%
}

Have a "sticky" button right underneath another "sticky" navbar

I have an app file which contains my own custom appbar and different page components:
const styles = theme => ({
appBar: {
width:'100%',
},
});
class App extends Component {
render() {
const {classes} = this.props;
return (
<React.Fragment>
<CssBaseline />
<AppBar position="sticky" className={classes.appBar} />
<Page1 show={someCondition} />
<Page2 show={someCondition} />
.
.
<Page99 show={someCondition} />
</React.Fragment>
);
}
}
The Appbar is sticky so it always shows on the top.
Each page component has a button which is always on the top of that page:
const styles = theme => ({
button: {
width:'100%',
},
});
class Page99 extends Component {
render() {
const {classes} = this.props;
return (
<React.Fragment>
<div>
<Button variant="contained" className= {classes.button}>
Action Button
</Button>
</div>
{/* Some other stuff */>
</React.Fragment>
);
}
}
I know want this button to always be right under the appbar. So when the user scrolls down this button should remain sticky just like the appbar does. I tried to set the positioning to sticky hoping it would stack underneath it but it wouldn't. The appbar is dynamic so I don't know the exact height it will be since on different resolutions it will look different so I couldn't use something like fixed positioning.
You can set position of page container as relative and set button as absolute.
the you can align it to top right of the page or wherever you want.
Check this fiddle is this is what you need
.componentparent {
position: relative;
height:100px;
max-height: 50px;
overflow: auto;
}
.button {
position: fixed;
top: 30px;
}
.otherelements{
top: 70px;
position: relative;
}
<div id="parent-container">
<div> your app bar </div>
<div class='componentparent'>
<button class='button'>my button</button>
<div class='otherelements'>your component</div>
</div>
</div>
Place your button inside your appbar and set your button to position to absolute and add top: 100% to move it exactly at the bottom of appbar.

Can't get buttons to wrap to new line instead of overflowing container

I couldn't get a JSFiddle to work properly with React and some other dependencies, so I hope the link to this Github repo is sufficient for demonstrating the issue:
https://github.com/ishraqiyun77/button-issues/
Basically, a group of buttons is rendered and they should be auto-widened to fill white space and take up the whole row. This works in Chrome, Edge, Safari, and Firefox. It looks like this:
This isn't happening in IE. I've been messing with it for hours and haven't made much progress:
Here is the code, although could clone the repo I posted above:
// component.jsx
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import {
Button,
Col,
Modal,
ModalBody,
ModalHeader,
Row
} from 'reactstrap';
import styles from '../assets/scss/app.scss';
class TestPrint extends Component {
constructor(props) {
super(props);
this.state = {
modal: false,
}
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
modal: !this.state.modal
})
}
renderContent() {
let buttons = [];
for (let i = 1; i < 50; i++) {
buttons.push(
<Col key={i}>
<Button
key={i}
className='cuts-btn'
>
{i} - Test
</Button>
</Col>
);
};
return buttons;
}
render() {
return (
<div>
<Button
style={
{
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}
}
onClick={this.toggle}
>
Open Modal for Buttons
</Button>
<Modal
size='lg'
isOpen={this.state.modal}
toggle={this.toggle}
className='results-modal'
>
<ModalHeader toggle={this.toggle}>
Button Issues
</ModalHeader>
<ModalBody>
<div className='results-bq-cuts'>
<Row>
{this.renderContent()}
</Row>
</div>
</ModalBody>
</Modal>
</div>
)
}
}
ReactDOM.render(<TestPrint />, document.getElementById('app'));
.results-modal {
max-width: 1200px;
.modal-content {
.modal-body {
margin-left: 13px;
margin-right: 13px;
.results-bq-cuts {
width: 100%;
.col {
padding:2px;
}
.cuts-btn {
font-size: 11px;
padding: 3px;
width: 100%;
box-shadow: none;
}
// .col {
// padding: 2px;
// display: table-cell;
// flex-basis: 100%;
// flex: 1;
// }
// .cuts-btn {
// font-size: 11px;
// padding: 3px;
// width: 100%;
// box-shadow: none;
// }
}
}
}
}
I have all of the <Button> wrapped in <Col> because that should be what is filling the white space by increasing the size of the button.
Thanks for the help!
IE11 doesn't like working out the width of flex items. If you add flex-basis: calc( 100% / 24 ); to .col it works :) Obviously use any width you want, but what I've given replicates the 21 boxes on one line. But essentially flex-basis needs a defined width to work.
​
Or add an extra class to each element (such as col-1 ) This'll also achieve the same thing.

How to make a sticky footer in react?

I've made a sticky footer higher-level component that wraps other components inside itself:
Footer.js
//this is a higher-order component that wraps other components placing them in footer
var style = {
backgroundColor: "#F8F8F8",
borderTop: "1px solid #E7E7E7",
textAlign: "center",
padding: "20px",
position: "fixed",
left: "0",
bottom: "0",
height: "60px",
width: "100%",
};
const Footer = React.createClass({
render: function() {
return (
<div style={style}>
{this.props.children}
</div>
);
}
});
export default Footer;
Usage:
<Footer><Button>test</Button></Footer>
But it is hiding the contents of the page:
This looks like a common problem, so I searched a bit and found this issue, where is FlexBox is recommended for the sticky footer. But at this demo the footer is at the very bottom of the page, while I need the footer to be always displayed on the page and the content being scrolled inside the above area (like in SO chat). In addition to that, there is an advice to change all the other components with custom stylesheet rules. Is it possible to achieve what I need using styling only the footer component so the code will remain modular?
Here's an idea (sandbox example link).
Include a phantom div in your footer component that represents the footer's position that other dom elements will respect (i.e. affecting page flow by not being position: 'fixed';).
var style = {
backgroundColor: "#F8F8F8",
borderTop: "1px solid #E7E7E7",
textAlign: "center",
padding: "20px",
position: "fixed",
left: "0",
bottom: "0",
height: "60px",
width: "100%",
}
var phantom = {
display: 'block',
padding: '20px',
height: '60px',
width: '100%',
}
function Footer({ children }) {
return (
<div>
<div style={phantom} />
<div style={style}>
{ children }
</div>
</div>
)
}
export default Footer
Much easier idea (following the trend), i imported both bootstrap and reactstrap, used the bootstrap fixed bottom class and workaround with that like this.
class AppFooter extends Component{
render() {
return(
<div className="fixed-bottom">
<Navbar color="dark" dark>
<Container>
<NavbarBrand>Footer</NavbarBrand>
</Container>
</Navbar>
</div>
)
}
There is a much simpler way. I am creating a portfolio site with React, and some of my pages are not very long, so in some devices, like kindle fire hd for example, the footer would not stick to the bottom. And of course to set this up in the traditional fashion with would not work, because the would be wrapped in there. And we don't want that. So this is what I did:
In App.js:
import React, { Component } from 'react';
import {Header} from './components/Header';
import {Main} from './components/Main';
import {Footer} from './components/Footer';
class App extends Component {
render() {
return (
<div className="App Site">
<div className="Site-content">
<div className="App-header">
<Header />
</div>
<div className="main">
<Main />
</div>
</div>
<Footer />
</div>
);
}
}
export default App;
And then in _sticky-footer.css (I use POSTCSS):
:root {
--space: 1.5em 0;
--space: 2em 0;
}
.Site {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.Site-content {
flex: 1 0 auto;
padding: var(--space) var(--space) 0;
width: 100%;
}
.Site-content:after {
content: '\00a0';
display: block;
margin-top: var(--space);
height: 0;
visibility: hidden;
}
The original solution for this was created by Philip Walton: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/
You can fix this by adding margin-bottom: 60px; to the body of your website. With the 60px being the height of your footer.
.footer{
width: 100%;
position: fixed;
bottom: 0;
}
This should do the trick! Cheers! (:
.App will be the main component you load to your Root.
Assume that the footer is the last child of .App in the document flow
.App {
height: 100vh;
display: flex;
flex-direction: column;
}
footer {
margin-top: auto;
}
I found that if you wrap your 'footer' component in a standard html
<footer>
tag, it pretty much sorts out all of the positioning for you
I wanted to share this solution that worked. I cribbed this from https://react.semantic-ui.com/modules/sticky. Scroll to the bottom of this page and inspect the text 'This is the bottom' to see where I stole it. Its a site built on react so it should work for your situation.
Here it is:
{
padding-top: 50vh;
}
Conceptually, this solution is creating negative space like jacoballenwood's phantom div to push the footer down to the bottom and stick it there. Just add it to your css style class for the footer and adjust the value to taste.
Very late answer, but someone can find this useful. You can, instead of phantom style, set Toolbar. I have build some standard layout for the components, where {children} is component from the parent component - App.js. This is example:
import React from "react";
import { Route } from "react-router-dom";
import { makeStyles } from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import CssBaseline from "#material-ui/core/CssBaseline";
import Toolbar from "#material-ui/core/Toolbar";
import Header from "../components/header";
import Footer from "../components/footer";
import SideBar from "../components/sidebar";
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
},
content: {
flexGrow: 5,
padding: theme.spacing(3),
},
}));
const StandardLayout = ({ children }) => {
const classes = useStyles();
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="fixed" className={classes.appBar}>
<Route path="/" component={Header} />
</AppBar>
<SideBar />
<main className={classes.content}>
<Toolbar />
<br />
{children}
<Toolbar/>
</main>
<AppBar className={classes.appBar}>
<Route path="/" component={Footer} />
</AppBar>
</div>
);
};
export default StandardLayout;
Its rule for me
<footer style={{position:"fixed",bottom:"0"}}>
Try this html code:
/public/index.html
<html lang="en" class="h-100">
<body class="h-100">
<div id="root" class="d-flex flex-column h-100"></div>
...
/src/App.js
<main role='main' className='flex-shrink-0'>
You can follow this template:
react-bootstrap-sticky-footer/public/index.html
react-bootstrap-sticky-footer/src/App.js

Resources