HTML video tag - change source on viewport without media attribute
I'm trying to implement a video in HTML with react. So if the viewport is under 750px width, I would like to change the video source to a smaller resolution/ smaller file (because of high data transfer and so on).
So in a perfect HTML world, you would build this:
<video controls>
<source src="video-small.mp4" type="video/mp4" media="all and (max-width: 750px)">
<source src="video.mp4" type="video/mp4">
</video>
Since media
is not (or no more) specified in the source tag if it's inside of a video tag, I can't use this anymore. Because Chrome is displaying the first source, which is the mobile video. No matter if desktop or mobile.
Second solution was to wrap a container around and set display: none;
to the not visible video:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({theme}) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({theme}) => theme.media.mobile`
display: none;
`}
`
const VideoComponent = ({
srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
}) => (
<React.Fragment>
<MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>
<DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>
</React.Fragment>
)
In this case the correct video is displayed, but both videos are downloaded (in Chrome). Hiding doesn't prevent the browser from downloading. SAD!
Third solution was to use the second solution and remove the invisible component from the DOM:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
import {sizes} from '../../lib/ThemeProvider/media'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({ theme }) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({ theme }) => theme.media.mobile`
display: none;
`}
`
class VideoComponent extends React.Component {
state = {
showMobileSrc: true
}
componentDidMount() {
this.resize()
window.addEventListener('resize', this.resize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.resize)
}
resize = () => {
if (window.innerWidth >= sizes.mobile) {
this.setState({ showMobileSrc: false })
} else {
this.setState({ showMobileSrc: true })
}
}
render() {
const { srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
} = this.props
const {showMobileSrc} = this.state
return (
<React.Fragment>
{showMobileSrc && <MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>}
{!showMobileSrc && <DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>}
</React.Fragment>
)
}
}
But chrome is downloading both videos anyway. HTML seems to be correct. No idea what chrome is doing there..
First i really don"t understand why they removed the media attribute from the source tag inside of a video tag. Thats not consistently implemented.
Anyway: How can I change the source at a defined viewport width and prevent downloading both videos?
html reactjs video responsive viewport
add a comment |
I'm trying to implement a video in HTML with react. So if the viewport is under 750px width, I would like to change the video source to a smaller resolution/ smaller file (because of high data transfer and so on).
So in a perfect HTML world, you would build this:
<video controls>
<source src="video-small.mp4" type="video/mp4" media="all and (max-width: 750px)">
<source src="video.mp4" type="video/mp4">
</video>
Since media
is not (or no more) specified in the source tag if it's inside of a video tag, I can't use this anymore. Because Chrome is displaying the first source, which is the mobile video. No matter if desktop or mobile.
Second solution was to wrap a container around and set display: none;
to the not visible video:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({theme}) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({theme}) => theme.media.mobile`
display: none;
`}
`
const VideoComponent = ({
srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
}) => (
<React.Fragment>
<MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>
<DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>
</React.Fragment>
)
In this case the correct video is displayed, but both videos are downloaded (in Chrome). Hiding doesn't prevent the browser from downloading. SAD!
Third solution was to use the second solution and remove the invisible component from the DOM:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
import {sizes} from '../../lib/ThemeProvider/media'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({ theme }) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({ theme }) => theme.media.mobile`
display: none;
`}
`
class VideoComponent extends React.Component {
state = {
showMobileSrc: true
}
componentDidMount() {
this.resize()
window.addEventListener('resize', this.resize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.resize)
}
resize = () => {
if (window.innerWidth >= sizes.mobile) {
this.setState({ showMobileSrc: false })
} else {
this.setState({ showMobileSrc: true })
}
}
render() {
const { srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
} = this.props
const {showMobileSrc} = this.state
return (
<React.Fragment>
{showMobileSrc && <MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>}
{!showMobileSrc && <DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>}
</React.Fragment>
)
}
}
But chrome is downloading both videos anyway. HTML seems to be correct. No idea what chrome is doing there..
First i really don"t understand why they removed the media attribute from the source tag inside of a video tag. Thats not consistently implemented.
Anyway: How can I change the source at a defined viewport width and prevent downloading both videos?
html reactjs video responsive viewport
add a comment |
I'm trying to implement a video in HTML with react. So if the viewport is under 750px width, I would like to change the video source to a smaller resolution/ smaller file (because of high data transfer and so on).
So in a perfect HTML world, you would build this:
<video controls>
<source src="video-small.mp4" type="video/mp4" media="all and (max-width: 750px)">
<source src="video.mp4" type="video/mp4">
</video>
Since media
is not (or no more) specified in the source tag if it's inside of a video tag, I can't use this anymore. Because Chrome is displaying the first source, which is the mobile video. No matter if desktop or mobile.
Second solution was to wrap a container around and set display: none;
to the not visible video:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({theme}) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({theme}) => theme.media.mobile`
display: none;
`}
`
const VideoComponent = ({
srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
}) => (
<React.Fragment>
<MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>
<DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>
</React.Fragment>
)
In this case the correct video is displayed, but both videos are downloaded (in Chrome). Hiding doesn't prevent the browser from downloading. SAD!
Third solution was to use the second solution and remove the invisible component from the DOM:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
import {sizes} from '../../lib/ThemeProvider/media'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({ theme }) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({ theme }) => theme.media.mobile`
display: none;
`}
`
class VideoComponent extends React.Component {
state = {
showMobileSrc: true
}
componentDidMount() {
this.resize()
window.addEventListener('resize', this.resize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.resize)
}
resize = () => {
if (window.innerWidth >= sizes.mobile) {
this.setState({ showMobileSrc: false })
} else {
this.setState({ showMobileSrc: true })
}
}
render() {
const { srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
} = this.props
const {showMobileSrc} = this.state
return (
<React.Fragment>
{showMobileSrc && <MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>}
{!showMobileSrc && <DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>}
</React.Fragment>
)
}
}
But chrome is downloading both videos anyway. HTML seems to be correct. No idea what chrome is doing there..
First i really don"t understand why they removed the media attribute from the source tag inside of a video tag. Thats not consistently implemented.
Anyway: How can I change the source at a defined viewport width and prevent downloading both videos?
html reactjs video responsive viewport
I'm trying to implement a video in HTML with react. So if the viewport is under 750px width, I would like to change the video source to a smaller resolution/ smaller file (because of high data transfer and so on).
So in a perfect HTML world, you would build this:
<video controls>
<source src="video-small.mp4" type="video/mp4" media="all and (max-width: 750px)">
<source src="video.mp4" type="video/mp4">
</video>
Since media
is not (or no more) specified in the source tag if it's inside of a video tag, I can't use this anymore. Because Chrome is displaying the first source, which is the mobile video. No matter if desktop or mobile.
Second solution was to wrap a container around and set display: none;
to the not visible video:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({theme}) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({theme}) => theme.media.mobile`
display: none;
`}
`
const VideoComponent = ({
srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
}) => (
<React.Fragment>
<MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>
<DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>
</React.Fragment>
)
In this case the correct video is displayed, but both videos are downloaded (in Chrome). Hiding doesn't prevent the browser from downloading. SAD!
Third solution was to use the second solution and remove the invisible component from the DOM:
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import LazyLoad from 'react-lazyload'
import {sizes} from '../../lib/ThemeProvider/media'
const MobileVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: none;
${({ theme }) => theme.media.mobile`
display: block;
`}
`
const DesktopVideo = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
display: block;
${({ theme }) => theme.media.mobile`
display: none;
`}
`
class VideoComponent extends React.Component {
state = {
showMobileSrc: true
}
componentDidMount() {
this.resize()
window.addEventListener('resize', this.resize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.resize)
}
resize = () => {
if (window.innerWidth >= sizes.mobile) {
this.setState({ showMobileSrc: false })
} else {
this.setState({ showMobileSrc: true })
}
}
render() {
const { srcWebm,
srcMp4,
mobileSrcWebm,
mobileSrcMp4,
poster,
className,
forwardedRef,
...rest
} = this.props
const {showMobileSrc} = this.state
return (
<React.Fragment>
{showMobileSrc && <MobileVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{mobileSrcWebm.url !== '' && (
<source src={mobileSrcWebm.url} type="video/webm" />
)}
{mobileSrcMp4.url !== '' && (
<source src={mobileSrcMp4.url} type="video/mp4" />
)}
</video>
</MobileVideo>}
{!showMobileSrc && <DesktopVideo>
<video
playsInline
poster={poster.url}
className={className}
ref={forwardedRef}
{...rest}
>
{srcWebm.url !== '' && <source src={srcWebm.url} type="video/webm" />}
{srcMp4.url !== '' && <source src={srcMp4.url} type="video/mp4" />}
</video>
</DesktopVideo>}
</React.Fragment>
)
}
}
But chrome is downloading both videos anyway. HTML seems to be correct. No idea what chrome is doing there..
First i really don"t understand why they removed the media attribute from the source tag inside of a video tag. Thats not consistently implemented.
Anyway: How can I change the source at a defined viewport width and prevent downloading both videos?
html reactjs video responsive viewport
html reactjs video responsive viewport
edited yesterday
Tobi
asked yesterday
TobiTobi
4810
4810
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Simple JavaScript solution (not ReactJS specific, but see this component for a pure ReactJS solution)
if (matchMedia) {
var mq = window.matchMedia("(min-width: 600px)");
mq.addListener(WidthChange);
}
function WidthChange(mq) {
if (mq.matches) {
// set source to desktop
} else {
// set source to mobile
}
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54251829%2fhtml-video-tag-change-source-on-viewport-without-media-attribute%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Simple JavaScript solution (not ReactJS specific, but see this component for a pure ReactJS solution)
if (matchMedia) {
var mq = window.matchMedia("(min-width: 600px)");
mq.addListener(WidthChange);
}
function WidthChange(mq) {
if (mq.matches) {
// set source to desktop
} else {
// set source to mobile
}
}
add a comment |
Simple JavaScript solution (not ReactJS specific, but see this component for a pure ReactJS solution)
if (matchMedia) {
var mq = window.matchMedia("(min-width: 600px)");
mq.addListener(WidthChange);
}
function WidthChange(mq) {
if (mq.matches) {
// set source to desktop
} else {
// set source to mobile
}
}
add a comment |
Simple JavaScript solution (not ReactJS specific, but see this component for a pure ReactJS solution)
if (matchMedia) {
var mq = window.matchMedia("(min-width: 600px)");
mq.addListener(WidthChange);
}
function WidthChange(mq) {
if (mq.matches) {
// set source to desktop
} else {
// set source to mobile
}
}
Simple JavaScript solution (not ReactJS specific, but see this component for a pure ReactJS solution)
if (matchMedia) {
var mq = window.matchMedia("(min-width: 600px)");
mq.addListener(WidthChange);
}
function WidthChange(mq) {
if (mq.matches) {
// set source to desktop
} else {
// set source to mobile
}
}
answered yesterday
OffbeatmammalOffbeatmammal
5,55121838
5,55121838
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54251829%2fhtml-video-tag-change-source-on-viewport-without-media-attribute%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown