fix image and screen issue
This commit is contained in:
@@ -342,6 +342,65 @@ function DashboardPanel({
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* LazyVideo
|
||||
* ---------------------------------------------------------------------------
|
||||
* The workflow videos sit thousands of pixels below the fold (e.g. /miletruth
|
||||
* renders one at document y≈9978), but a plain `<video autoPlay muted loop>`
|
||||
* makes Chrome buffer the ENTIRE file at page load even while it is off-screen
|
||||
* and still paused — and `preload="none"` does not stop it, because the browser
|
||||
* keeps buffering to satisfy the pending autoplay. Measured on /miletruth that
|
||||
* was 80.7 MB of mp4 pulled before the user scrolled at all (the 40 MB
|
||||
* Doormile-quantum-video3.mp4 fetched twice over restarted byte ranges).
|
||||
* On localhost that is free; on a deployed site it saturates the connection and
|
||||
* the media pipeline exactly while the user is scrolling.
|
||||
*
|
||||
* Attaching the source only once the element nears the viewport defers all of
|
||||
* it. Playback then starts exactly as before — `.evnd__video` is sized purely
|
||||
* by CSS (width/height 100%), so an empty <video> occupies the identical box
|
||||
* and nothing shifts.
|
||||
*/
|
||||
function LazyVideo({ src, ariaLabel }: { src: string; ariaLabel: string }) {
|
||||
const ref = useRef<HTMLVideoElement>(null);
|
||||
const [shouldLoad, setShouldLoad] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el || shouldLoad) return;
|
||||
const io = new IntersectionObserver(
|
||||
(entries) => {
|
||||
if (entries.some((e) => e.isIntersecting)) {
|
||||
setShouldLoad(true);
|
||||
io.disconnect();
|
||||
}
|
||||
},
|
||||
// ~1.3 viewports of lead time: enough for the fetch to be well under way
|
||||
// before the section arrives, without paying for it at page load.
|
||||
{ rootMargin: "1200px 0px" },
|
||||
);
|
||||
io.observe(el);
|
||||
return () => io.disconnect();
|
||||
}, [shouldLoad]);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldLoad) ref.current?.load();
|
||||
}, [shouldLoad]);
|
||||
|
||||
return (
|
||||
<video
|
||||
ref={ref}
|
||||
className="evnd__video"
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
preload="none"
|
||||
aria-label={ariaLabel}
|
||||
src={shouldLoad ? src : undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default function EVSection({
|
||||
bannerImage = "/images/ev.webp",
|
||||
cardNumber = "",
|
||||
@@ -1449,23 +1508,19 @@ export default function EVSection({
|
||||
{mediaSlot ? (
|
||||
mediaSlot
|
||||
) : isVideo ? (
|
||||
<video
|
||||
className="evnd__video"
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
aria-label={imageAlt}
|
||||
>
|
||||
<source src={image} type="video/mp4" />
|
||||
</video>
|
||||
<LazyVideo src={image} ariaLabel={imageAlt} />
|
||||
) : (
|
||||
/* Same reason as LazyVideo: these stills are multi-MB raw
|
||||
PNGs (e.g. /solutions' "ev section1.png" is 2.6 MB at
|
||||
document y≈6793) and were being fetched and decoded
|
||||
eagerly while far below the fold. */
|
||||
/* eslint-disable-next-line @next/next/no-img-element */
|
||||
<img
|
||||
className="evnd__img"
|
||||
src={image}
|
||||
alt={imageAlt}
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
/>
|
||||
)}
|
||||
{badges[0] && (
|
||||
|
||||
Reference in New Issue
Block a user