This guide explains how to create a responsive iframe that maintains aspect ratio and covers the entire viewport without borders, shadows, or rounded corners. This is the core technology behind Picito.
<div class="container">
<div class="iframe-wrapper">
<iframe
src="your-content-url"
class="responsive-iframe"
frameborder="0"
scrolling="no"
allowfullscreen
></iframe>
</div>
</div>
/* Reset default styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Container takes full viewport */
.container {
position: fixed;
inset: 0;
overflow: hidden;
background: #000; /* Or any desired background */
}
/* Wrapper for positioning and scaling */
.iframe-wrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
overflow: hidden;
}
/* iframe styling */
.responsive-iframe {
position: absolute;
top: 50%;
left: 50%;
border: none;
margin: 0;
padding: 0;
overflow: hidden;
transform-origin: center center;
}
class ResponsiveIframe {
constructor(iframeElement, originalWidth, originalHeight) {
this.iframe = iframeElement;
this.originalWidth = originalWidth;
this.originalHeight = originalHeight;
// Bind methods
this.updateScale = this.updateScale.bind(this);
// Initial setup
this.setup();
}
setup() {
// Set initial dimensions
this.iframe.width = this.originalWidth;
this.iframe.height = this.originalHeight;
// Add resize listener
window.addEventListener('resize', this.updateScale);
// Initial scale
this.updateScale();
}
updateScale() {
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Calculate scale factors
const scaleX = viewportWidth / this.originalWidth;
const scaleY = viewportHeight / this.originalHeight;
// Use the smaller scale to maintain aspect ratio
const scale = Math.min(scaleX, scaleY);
// Apply transform
this.iframe.style.transform = `translate(-50%, -50%) scale(${scale})`;
}
cleanup() {
window.removeEventListener('resize', this.updateScale);
}
}
// Initialize with your iframe's original dimensions
const iframe = document.querySelector('.responsive-iframe');
const responsiveIframe = new ResponsiveIframe(iframe, 1920, 1080);
Here's how to implement this in a React component:
import React, { useEffect, useRef } from 'react';
import styled from 'styled-components';
const Container = styled.div`
position: fixed;
inset: 0;
margin: 0;
padding: 0;
overflow: hidden;
background: #000;
`;
const IframeWrapper = styled.div`
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
overflow: hidden;
`;
const StyledIframe = styled.iframe`
position: absolute;
top: 50%;
left: 50%;
border: none;
margin: 0;
padding: 0;
transform-origin: center center;
`;
interface ResponsiveIframeProps {
src: string;
originalWidth: number;
originalHeight: number;
}
const ResponsiveIframe: React.FC<ResponsiveIframeProps> = ({
src,
originalWidth,
originalHeight
}) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
const updateScale = () => {
if (!iframeRef.current) return;
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const scaleX = viewportWidth / originalWidth;
const scaleY = viewportHeight / originalHeight;
const scale = Math.min(scaleX, scaleY);
iframeRef.current.style.transform = `translate(-50%, -50%) scale(${scale})`;
};
useEffect(() => {
// Set initial dimensions
if (iframeRef.current) {
iframeRef.current.width = originalWidth.toString();
iframeRef.current.height = originalHeight.toString();
}
// Initial scale
updateScale();
// Add resize listener
window.addEventListener('resize', updateScale);
// Cleanup
return () => window.removeEventListener('resize', updateScale);
}, [originalWidth, originalHeight]);
return (
<Container>
<IframeWrapper>
<StyledIframe
ref={iframeRef}
src={src}
frameBorder="0"
scrolling="no"
allowFullScreen
/>
</IframeWrapper>
</Container>
);
};
export default ResponsiveIframe;
Flickering During Resize
transform-style: preserve-3d
to force hardware accelerationWhite Borders
margin: 0; padding: 0; border: none;
Scroll Bars Appearing
overflow: hidden
to all containing elementsContent Not Centered
Mobile Safari Issues
-webkit-overflow-scrolling: touch
to containerfunction debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Usage
const debouncedUpdateScale = debounce(updateScale, 16); // ~1 frame at 60fps
window.addEventListener('resize', debouncedUpdateScale);
function updateScale() {
requestAnimationFrame(() => {
// scaling logic here
});
}
This implementation works in all modern browsers. For older browsers, consider these polyfills:
position: fixed
fallback for older mobile browserstransform
prefixes for older browsersrequestAnimationFrame
polyfill for smoother animationsKey scenarios to test:
Use browser dev tools to test different viewport sizes and device emulation.