A video playing in the background spanning the entire browser window creates a captivating visual effect when text overlays it, a unique feature not commonly encountered. This is primarily due to the limitation in CSS where a video file cannot be directly set as the background image. Overcoming this challenge will necessitate employing some clever layout techniques.
Of course, a background film taking up the entire page would be a bit much. It is possible to do it tastefully, I would say. I am more interested in the how-to of finishing it, if necessary, and various potential patterns it may take than in debating design philosophy here (maybe later).
The fundamentals of tastefulness are still important to note here:
- No sound. By default, at least. Opt-in audio is appropriate.
- Be mindful of your bandwidth. Video content is the heaviest item you can put on a website. Please take note that this is a video that was not specifically requested.
- Make it available. Since you will most likely be overlaying text on top of the video, ensure the contrast is sufficient for legibility.
In celebration of the upcoming journey with Media Temple and ZaneRay, let's tackle this Montana-style.
The How-To of Full-Page Background Video
Fortunately, we are in a favorable position. Dudley Story has conducted numerous investigations on this subject in the past and has shared a helpful configuration with us. Additionally, he has a sample webpage available for reference.
Sure thing, we need to embed the video onto the webpage, so here it is: ```
<video playsinline autoplay muted loop poster="mixkit-white-sand-beach-background-1564-medium" id="bg">
<source src="https://placehold.co/300x300/1abc9c/ffffff?text=Sample+Image" type="video/webm">
<source src="https://placehold.co/400x300/1abc9c/ffffff?text=Sample+Image" type="video/mp4">
</video>
<video playsinline autoplay muted loop poster="mixkit-white-sand-beach-background-1564-medium" id="bg">
<source src="https://placehold.co/300x300/1abc9c/ffffff?text=Sample+Image" type="video/webm">
<source src="https://placehold.co/400x300/1abc9c/ffffff?text=Sample+Image" type="video/mp4">
</video>
When a video loads at a slow pace or fails to load entirely, the poster attribute offers an image for visual representation. It may also be beneficial to incorporate a background using CSS.
The autoplay attribute is present to initiate video playback automatically. It is a thoughtful feature that eliminates the need for manual intervention from the user. In scenarios where playback controls are absent, the user's ability to start or stop the video is restricted. To enable autoplay on iOS devices, the playsinline attribute should be utilized. Furthermore, the muted attribute is vital for iOS to support autoplay, which is a prudent decision especially when the video content does not require audio. Once these attributes are set, the loop attribute ensures continuous playback of the video content.
You can achieve this by maximizing the video to occupy the entire screen.
video {
object-fit: cover;
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
}
You will be provided with a comprehensive video tutorial for that! Excellent!
Now, let's explore some patterns. A full-page video can be managed using a single approach, whereas there are multiple alternative methods available.
### Just One Viewport
We have arranged the video in its position. We can now overlay any elements on top of it.
Take some text like this:
<header class="viewport-header">
<h1>
Explore
beach</h1>
</header>
It can be situated in relation to the video and positioned above it. Then, apply a slight centering adjustment:
.viewport-header {
align-items: centre;
justify-content: centre;
text-align: centre;
display: flex;
position: relative;
height: 100vh;
}
We have the simplest possible effect:
Html:
<video src="https://placehold.co/800x200/1abc9c/ffffff?text=Banner" autoplay loop playsinline muted></video>
<header class="viewport-header">
<h1>
Explore
beach</h1>
</header>
<main>
[[[https://mixkit.co/free-stock-video/white-sand-beach-background-1564/]]]
</main>
video {
object-fit: cover;
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
}
html, body {
height: 100%;
}
html {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 150%;
line-height: 1.4;
}
body {
margin: 0;
}
.viewport-header {
position: relative;
height: 100vh;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
h1 {
font-family: 'Syncopate', sans-serif;
color: #4a3a27;
text-transform: uppercase;
letter-spacing: 3vw;
line-height: 1.2;
font-size: 3vw;
text-align: center;
span {
display: block;
font-size: 10vw;
letter-spacing: -1.3vw;
}
}
main {
display: none;
width: 80vw;
left: 10%;
height: 40vh;
overflow: auto;
background: rgba(black, 0.66);
color: white;
position: relative;
padding: 1rem;
}
Other elements that we prefer could potentially be located anywhere within the webpage. While it may not be considered trendy, there is also the option to eliminate a scrolling text segment to maintain the overall impression of a complete page.
HTML:
<video src="https://placehold.co/800x200/1abc9c/ffffff?text=Banner" autoplay loop playsinline muted></video>
<header class="viewport-header">
<h1>
Explore
beach</h1>
</header>
<main>
[[[https://mixkit.co/free-stock-video/white-sand-beach-background-1564/]]]
</main>
video {
object-fit: cover;
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
}
html, body {
height: 100%;
}
html {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 150%;
line-height: 1.4;
}
body {
margin: 0;
}
.viewport-header {
position: relative;
height: 50vh;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
h1 {
font-family: 'Syncopate', sans-serif;
color: #4a3a27;
text-transform: uppercase;
letter-spacing: 3vw;
line-height: 1.2;
font-size: 3vw;
text-align: center;
span {
display: block;
font-size: 10vw;
letter-spacing: -1.3vw;
}
}
main {
width: 80vw;
left: 10%;
height: 40vh;
overflow: auto;
background: rgba(black, 0.66);
color: white;
position: relative;
padding: 1rem;
}
JS:
/*
- Fallback bokuh
- webm?
- poster=""
- Full page always
- Full page, then scroll
- Just header
- Browser compat
*/
### One Viewport Header, Scrolls Away
Other elements may disappear from view while the video is playing in full-screen mode. The main content remains unchanged, while the header, which remains fully visible within the screen, smoothly moves out of sight. Moreover, it maintains a semi-transparent quality, enabling the video content to remain visible through it.
HTML:
<video src="https://placehold.co/800x200/1abc9c/ffffff?text=Banner" autoplay loop playsinline muted></video>
<header class="viewport-header">
<h1>
Explore
Montana</h1>
</header>
<main>
[[[https://mixkit.co/free-stock-video/white-sand-beach-background-1564/]]]
</main>
video {
object-fit: cover;
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
}
html, body {
height: 100%;
}
html {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 150%;
line-height: 1.4;
}
body {
margin: 0;
}
.viewport-header {
position: relative;
height: 100%;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
h1 {
font-family: 'Syncopate', sans-serif;
color: white;
text-transform: uppercase;
letter-spacing: 3vw;
line-height: 1.2;
font-size: 3vw;
text-align: center;
span {
display: block;
font-size: 10vw;
letter-spacing: -1.3vw;
}
}
main {
background: rgba(black, 0.66);
color: white;
position: relative;
padding: 1rem;
p {
max-width: 600px;
margin: 1rem auto;
}
}
/*
- Fallback bokuh
- webm?
- poster=""
- Full page always
- Full page, then scroll
- Just header
- Browser compat
*/
### One Viewport Header, Content Scrolls Over Header
The text may scroll past the heading located above the video or remain stationary. Employing margin-top: 100vh to anchor the video and heading in place while guaranteeing that the main content is shifted out of view is a method to achieve this effect.
HTML:
<header class="video-header">
<video src="https://placehold.co/800x200/1abc9c/ffffff?text=Banner" autoplay loop playsinline muted></video>
</header>
<main>
[[[https://mixkit.co/free-stock-video/white-sand-beach-background-1564/]]]
</main>
@mixin coverer {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
}
.video-header {
position: absolute;
text-align: center;
width: 100vw;
height: 100vh;
&, video, .viewport-header {
@include coverer;
}
video {
background: brown;
object-fit: cover;
}
.viewport-header {
display: flex;
align-items: center;
justify-content: center;
}
}
html, body {
height: 100%;
overflow-x: hidden;
}
html {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 150%;
line-height: 1.4;
}
body {
margin: 0;
}
h1 {
font-family: 'Syncopate', sans-serif;
color: white;
text-transform: uppercase;
letter-spacing: 3vw;
line-height: 1.2;
font-size: 3vw;
text-align: center;
span {
display: block;
font-size: 10vw;
letter-spacing: -0.6rem;
}
}
main {
background: white;
position: relative;
padding: 1rem;
margin-top: 100vh;
&::before {
content: "";
@include coverer;
top: -100vh;
}
p {
max-width: 600px;
margin: 1rem auto;
}
}
Enhancing the user experience, we can implement a feature where the header text gradually fades into the background as the user scrolls. This effect can be achieved by incorporating opacity and scale modifications based on the scroll position. Leveraging CSS custom attributes simplifies the implementation of this functionality. Feel free to explore this concept in action by checking out the provided demo.
HTML:
<header class="video-header">
<video src="https://placehold.co/800x200/1abc9c/ffffff?text=Banner" autoplay loop playsinline muted></video>
</header>
<main>
[[[https://mixkit.co/free-stock-video/white-sand-beach-background-1564/]]]
</main>
:root {
--headerOpacity: 1;
--headerScale: 1;
}
@mixin coverer {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
}
.video-header {
position: absolute;
text-align: center;
width: 100vw;
height: 100vh;
&, video, .viewport-header {
@include coverer;
}
video {
background: brown;
object-fit: cover;
}
.viewport-header {
display: flex;
align-items: center;
justify-content: center;
opacity: 1;
opacity: var(--headerOpacity);
transform: scale(var(--headerScale));
}
}
html, body {
height: 100vh;
overflow-x: hidden;
}
html {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 150%;
line-height: 1.4;
}
body {
margin: 0;
}
h1 {
font-family: 'Syncopate', sans-serif;
color: white;
text-transform: uppercase;
letter-spacing: 3vw;
line-height: 1.2;
font-size: 3vw;
text-align: center;
span {
display: block;
font-size: 10vw;
letter-spacing: -1.3vw;
}
}
main {
background: white;
position: relative;
padding: 1rem;
margin-top: 100vh;
&::before {
content: "";
@include coverer;
top: -100vh;
}
p {
max-width: 600px;
margin: 1rem auto;
}
}
var viewportHeader = document.querySelector(".viewport-header");
document.body.addEventListener("scroll", function(event) {
var opacity = (document.body.offsetHeight - document.body.scrollTop) / document.body.offsetHeight;
var scale = (document.body.offsetHeight - document.body.scrollTop) / document.body.offsetHeight;
document.documentElement.style.setProperty('--headerOpacity', opacity);
document.documentElement.style.setProperty('--headerScale', scale);
});