Quick start (HTML/CSS)
- Unzip the set. Copy the
hero,footerandpostersfolders, pluscode/html-css/matteflux.cssandmatteflux.js, into your site. - Open
code/html-css/example.htmlthrough a local server to see it working (see Common mistakes if nothing plays). - Add the stylesheet in
<head>and the script before</body>, then paste the section markup where you want it.
<head>
<link rel="stylesheet" href="/matteflux/matteflux.css">
</head>
<body>
<section class="mf-section mf-section--hero">
<div class="mf-bg" style="--mf-overlay: 0.2">
<picture class="mf-bg__poster">
<source media="(max-width: 767px)" srcset="/posters/ember-aurora-hero-mobile.webp" type="image/webp">
<source srcset="/posters/ember-aurora-hero-desktop.webp" type="image/webp">
<img src="/posters/ember-aurora-hero-desktop.jpg" alt="" fetchpriority="high">
</picture>
<video class="mf-bg__video" muted loop playsinline preload="none" aria-hidden="true"
data-mf-load="eager"
data-mf-desktop="/hero/ember-aurora-hero-desktop"
data-mf-mobile="/hero/ember-aurora-hero-mobile"></video>
<div class="mf-bg__overlay"></div>
</div>
<!-- your content -->
</section>
<script src="/matteflux/matteflux.js" defer></script>
</body>
The video paths have no file extension on purpose: the script adds .webm first and .mp4 as the fallback.
For the footer, use mf-section--footer, the footer files and data-mf-load="lazy" so it only downloads when a visitor scrolls near it.
Framer
- In Framer, open Assets → Code, create a new code component and name it
MattefluxBackground. - Replace its contents with
code/framer/MattefluxBackground.tsxand save. - Drag the component into your hero or footer frame. Set its position to absolute with all edges at 0, and send it to the back.
- In the properties panel, upload the desktop and mobile WebM and MP4 files and the posters.
- Set Overlay to the value from the README, and turn on Lazy load for footers.
Webflow
- Paste
code/webflow/1-head-code.htmlinto Site settings → Custom code → Head code, and2-footer-code.htmlinto Footer code. You can use Page settings instead to limit it to one page. - Upload the videos and posters to a public host (see Hosting the files).
- Give your hero Section position: relative, overflow: hidden and a minimum height.
- Add a Code Embed as the first child of the Section, paste
3-hero-embed.htmland replacehttps://YOUR-FILE-HOST/…with your file URL. - Repeat with
4-footer-embed.htmlfor the footer.
Custom code needs a Webflow plan that allows it. The native Background Video element also works, but you lose the separate mobile composition and the reduced-motion handling.
Overlay and legibility
The overlay is a dark layer between the video and your text, set with --mf-overlay (0 to 1). For every set we measure each pixel of the text area across the whole loop, and find the lowest overlay at which white text reaches a 4.5:1 contrast ratio (WCAG AA) on 99.5% of pixels.
The recommended value adds headroom on top of that minimum: at least 20% for heroes and 25% for footers, or the measured minimum plus 5% if that is higher. Both numbers are in each set's README and on its page.
/* Darker for small text or busy layouts */
.mf-bg { --mf-overlay: 0.35; }
/* Dark text instead of white: use a light overlay and check contrast */
.mf-bg__overlay { background: rgb(243 239 231 / 0.6); }
Performance
- Preload the hero poster. It is your largest image on first paint; add a
<link rel="preload" as="image">for the desktop and mobile posters, as inexample.html. - Hero loads right away, footer loads late.
data-mf-load="eager"for heroes,"lazy"for everything below the fold. - Videos pause off screen. No CPU is spent on a video nobody is looking at.
- Reduced motion and Data Saver get the poster only. No video is downloaded at all.
- WebM first. It is usually a third of the MP4 size; MP4 is the fallback for any browser that can't play WebM.
Hosting the files
Any host that serves static files works. For busy sites, serve the videos from a CDN or object storage and set a long cache lifetime. Keep the folder names from the ZIP (hero/, footer/, posters/) so the paths in the code stay valid.
Common mistakes
- The video doesn't autoplay on iPhone.
- Keep
mutedandplaysinlineon the<video>tag. Low Power Mode can also block autoplay; the poster stays visible in that case. - The video covers my text.
- The section needs
position: relativeandisolation: isolate(the.mf-sectionclass does both), or give your contentposition: relative; z-index: 1. - Mobile shows the desktop video.
- Check the
data-mf-mobilepath. The default breakpoint is 767 px; change it withdata-mf-breakpoint="900"on a parent element. - Nothing plays when I open the file directly.
- Some browsers block video from
file://. Run a local server in the set folder, for examplepython -m http.server. - The video jumps once per loop.
- Make sure the files weren't re-encoded or trimmed by a site builder. The original files loop exactly.
Reference
| Attribute or variable | Where | What it does |
|---|---|---|
data-mf-desktop | video | Path to the desktop file, without extension |
data-mf-mobile | video | Path to the mobile file, without extension |
data-mf-load | video | eager (hero) or lazy (default) |
data-mf-breakpoint | any parent | Max width in px that counts as mobile (default 767) |
--mf-overlay | .mf-bg | Overlay strength, 0 to 1 |
--mf-position | .mf-bg | Focus point, e.g. 50% 30% |
Matteflux.refresh() | JavaScript | Starts videos added to the page after load |