Page Previews
Published on .
As of today, if you hover over an internal blog post link on my site on a wide screen, a page preview will appear in the right margin as demonstrated below, in order to help you decide whether or not to click.
Caching and simplicity already make page loads on my site pretty fast (50-200ms,) but I always liked the way that Wikipedia designed page previews. Still, I thought the implementation was too complicated to warrant. Then today I saw an alternative implementation on jefftk.com that used iframes, which is both simple and fairly fast.
The implementation does a few interesting things:
- Setting
sandbox="allow-same-origin"
restricts the iframe from loading any potentially slow scripts (although I control this anyway) yet still allows the embedding page to modify thecontentDocument
- The site header within the iframe is hidden by
iframe.contentDocument.querySelector("foo").style.display="none"
- The iframe slides in from the right, thanks to a bit of CSS
animation: slide 0.5s forwards;
and the associated keyframe@keyframes slide { to { right: 0; } }
- The
mouseoever
event is bound only to certain links thanks to a attribute prefix selectordocument.querySelectorAll("a[href^='https://nattaylor.com/blog']")
- The previews are delayed by 250ms in case you are sliding your most down a list of links, and linger for 3s so you can move your mouse over to keep the preview in place and click if, if you wish.
Love it? Hate it? Let me know with an email to nattaylor@gmail.com
Here is the code.
<script type="text/javascript">
window.onload = previewSetup(250, 3000, 1000, 'https://nattaylor.com/blog');
function previewSetup(delay, timeout, minwidth, pattern) {
/**
* Show a iframe preview of a link on hover (a la Wikipedia)
*
* Usage: window.onload = previewSetup(500, 3000, 1000);
* @param Number delay time to wait to show preview
* @param Number timeout time in ms for preview to linger
* @param Number minwidth minimum screen width to display the preview
* @return {[type]} [description]
*/
// For blog links, show a preview
document.querySelectorAll("a[href*='"+pattern+"']").forEach(function(e) {
e.addEventListener('mouseover', function(e) {
window.clearTimeout(window.previewDelay);
window.previewDelay = setTimeout(preview, delay, e);
});
}
)
// Create & append the elements, plus configure event listeners
function preview(e) {
if (window.outerWidth < minwidth) {
return
}
window.clearTimeout(window.previewTimeout);
href = e.target.href;
iwrap = document.createElement("iwrap")
iwrap.id = "preview-wrapper";
iwrap.addEventListener("click", function() {document.location = href});
iframe = document.createElement("iframe");
iframe.id = "preview";
iframe.setAttribute("sandbox", "allow-same-origin");
iframe.src=href;
iframe.scrolling="no";
// Hide the header within the preview
iframe.addEventListener( "load", function(e) {
document
.querySelector("#preview")
.contentDocument
.querySelector("body > header")
.style.display="none";
})
iwrap.addEventListener( "mouseover", function (e) {
window.clearTimeout(previewTimeout);
e.target.addEventListener("mouseout", function(e) {
window.previewTimeout = window.setTimeout(function() {
if (document.querySelector("#preview-wrapper")) {
document.querySelector("#preview-wrapper").remove();
}
}, timeout);
})
});
e.target.addEventListener( "mouseout", function(e) {
window.clearTimeout(window.previewTimeout);
window.previewTimeout = window.setTimeout(function() {
if (document.querySelector("#preview-wrapper")) {
document.querySelector("#preview-wrapper").remove();
}
}, timeout);
})
if (document.querySelector("#preview-wrapper")) {
document.querySelector("#preview-wrapper").remove();
}
iwrap.appendChild(iframe);
document.body.appendChild(iwrap);
return true;
}
}
</script>
<style type="text/css">
iframe#preview {
position: absolute;
right: -400px;
bottom: 0;
height: 400px;
width:400px;
border:1px solid gray;
background-color:white;
filter: drop-shadow(0 0 0.75rem gray);
animation: slide 0.5s forwards;
pointer-events: none;
}
#preview-wrapper {
position: absolute;
height: 400px;
width:400px;
bottom: 0;
right:0;
}
@keyframes slide {
to { right: 0; }
}
</style>