I'm using an iframe element as a preview window for mixed video and image content. A scaled down iframe works well, as it allows our clients to view an image close to how it would appear on their TV screen.
I want to add some buttons below the iframe, however the button appears well below the iframe, conforming to the unscaled size of the iframe.
What is the best method for dealing with the original margin space?
HTML:
<iframe id="iframe" width="1920" height="1080" src="https://jsfiddle.net/" frameBorder="1"> </iframe>
<button id="previewSkip">Skip</button>
CSS:
#iframe {
-webkit-transform:scale(0.295);
-moz-transform: scale(0.295);
transform-origin: left top;
}
Fiddle:
#iframe {
-webkit-transform: scale(0.295);
-moz-transform: scale(0.295);
transform-origin: left top;
}
<iframe id="iframe" width="1920" height="1080" src="https://youtube.com/" frameBorder="1"> </iframe>
<button id="previewSkip">Skip</button>
Use a wrapper to limit the occupied space in document flow, based on same factor and the <iframe>
's dimensions:
#iframe {
transform: scale(0.295);
transform-origin: left top;
}
scale-factor {
width: calc(1920px * 0.295);
height: calc(1080px * 0.295);
overflow: hidden;
display: block;
border: 1px solid red; /* not needed, obviously */
}
<scale-factor>
<iframe id="iframe" width="1920" height="1080" src="https://jsfiddle.net/" frameBorder="1"> </iframe>
</scale-factor>
<button id="previewSkip">Skip</button>
Here's an example, in vanilla, to read the attributes from markup and apply correct scale + trimming to any <iframe>
inside a <scale-factor>
, as long as the latter has a data-scale
attribute:
/* forEach polyfill */
if (window.NodeList && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = function (callback, thisArg) {
thisArg = thisArg || window;
for (var i = 0; i < this.length; i++) {
callback.call(thisArg, this[i], i, this);
}
};
}
window.onload = handleScaleFactors;
function handleScaleFactors() {
const scaleFactor = document.querySelectorAll('scale-factor');
scaleFactor.forEach(function(e,i) {
const iframe = e.querySelector('iframe');
if (iframe) {
const w = iframe.getAttribute('width') ?
parseInt(iframe.getAttribute('width')) :
iframe.clientWidth,
h = iframe.getAttribute('height') ?
parseInt(iframe.getAttribute('height')) :
iframe.clientHeight,
s = e.getAttribute('data-scale') ?
parseFloat(e.getAttribute('data-scale')) :
1;
iframe.style.transform = 'scale(' + s + ')';
e.style.width = (w * s) + 'px';
e.style.height = (h * s) + 'px';
e.style.opacity = 1;
}
});
}
scale-factor {
display: block;
overflow: hidden;
opacity: 0;
transition: opacity .3s linear;
}
scale-factor iframe {
transform-origin: 0 0;
}
<scale-factor data-scale="0.295">
<iframe width="1920" height="1080" src="https://jsfiddle.net/" frameBorder="0"> </iframe>
</scale-factor>
<button id="previewSkip">Skip</button>
<scale-factor data-scale="0.708">
<iframe width="800" height="600" src="https://jsfiddle.net/" frameBorder="0"> </iframe>
</scale-factor>
<button id="previewSkip">Skip</button>
Its slightly more concise jQuery equivalent is:
$(window).on('load', handleScaleFactors)
function handleScaleFactors() {
$('scale-factor').each(function(i, e) {
const iframe = $('iframe', e);
if (iframe.is('iframe')) {
const w = iframe.attr('width') ? parseInt(iframe.attr('width')) : iframe.width(),
h = iframe.attr('height') ? parseInt(iframe.attr('height')) : iframe.height(),
scale = $(e).data('scale') || 0;
iframe.css({
transform: 'scale(' + scale + ')'
});
$(e).css({
width: (w * scale) + 'px',
height: (h * scale) + 'px',
opacity: 1
})
}
});
}