Skip to content

Instantly share code, notes, and snippets.

@XOP
Created April 14, 2016 11:22
Show Gist options
  • Save XOP/d5171ab47526e251cf68cbc667836bfa to your computer and use it in GitHub Desktop.
Save XOP/d5171ab47526e251cf68cbc667836bfa to your computer and use it in GitHub Desktop.
Fake media queries with Iframe trick
(function (global) {
var metaViewport = document.querySelector('meta[name="viewport"]');
var metaViewportStr = metaViewport && metaViewport.outerHTML || '';
var metaCharset = document.querySelector('meta[charset]');
var metaCharsetStr = metaCharset && metaCharset.outerHTML || '';
var queryCache = {};
/**
* Get the styling nodes to inject in the head of the embedded document
*
* @param {String} selector
* @return {String}
*/
function getStylingNodes (selector) {
if (typeof queryCache[selector] === 'undefined') {
queryCache[selector] = Array.prototype.map.call(
document.querySelectorAll(selector),
function (stylesheet) {
return stylesheet.outerHTML;
}
).join('');
}
return queryCache[selector];
}
/**
* Get the content for the iframified version of a node.
*
* @param {HTMLElement} node
* @param {Object} options
* @return {String}
*/
function getIframeContentForNode (node, options) {
return '<!doctype html>' +
'<html ' + options.htmlAttr + '>' +
'<head>' +
options.metaCharset +
options.metaViewport +
options.stylesheets +
options.styles +
'</head>' +
'<body ' + options.bodyAttr + '>' +
node.innerHTML +
'</body>' +
'</html>';
}
/**
* Format an object of attributes into a HTML string
*
* @param {Object} attrObj
* @return {String}
*/
function formatAttributes (attrObj) {
var attributes = [];
for (var attribute in attrObj) {
attributes.push(attribute + '="' + attrObj[attribute] + '"');
}
return attributes.join(' ');
}
/**
* Get document height (stackoverflow.com/questions/1145850/)
*
* @param {Document} doc
* @return {Number}
*/
function getDocumentHeight (doc) {
doc = doc || document;
var body = doc.body;
var html = doc.documentElement;
return Math.max(
body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight
);
}
function getOptions (options) {
var opts = options || {};
opts.htmlAttr = formatAttributes(opts.htmlAttr || {});
opts.bodyAttr = formatAttributes(opts.bodyAttr || {});
opts.sizingTimeout = opts.sizingTimeout || 500;
opts.styles = (opts.styles ? '<style>' + opts.styles + '</style>' : '');
opts.stylesheets = getStylingNodes(opts.stylesSelector || 'link[rel*=stylesheet], style');
opts.metaCharset = opts.metaCharset || metaCharsetStr;
opts.metaViewport = opts.metaViewport || metaViewportStr;
return opts;
}
/**
* Transform a collection of nodes into an iframe version of themselves
* including all the styles they need to perform correctly.
*
* @param {HTMLElement} nodes
* @param {Object} options
* @return undefined
*/
function iframify (node, options) {
options = getOptions(options);
var iframe = document.createElement('iframe');
var html = getIframeContentForNode(node, options);
iframe.srcdoc = html;
if (!('srcdoc' in iframe)) {
console.log(
'Your browser does not support the `srcdoc` attribute on elements.' +
'Therefore, it is not possible to wrap this node with an iframe due' +
'to CORS policy.'
);
return null;
}
node.parentNode.replaceChild(iframe, node);
setTimeout(function () {
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
iframe.height = getDocumentHeight(iframeDocument);
}, options.sizingTimeout);
return iframe;
}
global.iframify = iframify;
}(window));
document.addEventListener('DOMContentLoaded', function () {
var components = document.querySelectorAll('.iframify');
Array.prototype.forEach.call(components, iframify);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment