Link Previews on Hover

Add live mini webpage previews to links on hover.

This demo shows how to add live mini-previews to links on hover in your Ghost site.

Check out this link to Culture Solutions Group, one of my client's websites. Hover over it to see a small preview of what it points to.

And here is what the Wikipedia website mini-preview looks like... Wikipedia.

And here is the Elizabeth II page on Wikipedia.

Those previews were fetched as soon as this page loaded. This is great for having the previews ready ahead of time, but can eat up extra bandwidth.

As an alternative, check out these same links to Culture Solutions Group and Wikipedia and Elizabeth II. This time the previews aren't fetched until you hover over this paragraph.

Finally, check out these links again to Culture Solutions Group and Wikipedia and Elizabeth II. These previews are only fetched when needed (when you hover over the specific link.) This saves the most bandwidth on page load, but there will be a delay before the previews can be shown.

Put this in an HTML Card...

<p id="p1">    
Check out this link to
    <a href="https://culturesolutionsgroup.com">Culture Solutions Group</a>, one of my client's websites. Hover over it to see a small preview of what it points to.<br><br>
And here is what the Wikipedia website mini-preview looks like...
    <a href="https://wikipedia.org">Wikipedia</a>.
    <br><br>
And here is the
    <a href="https://en.wikipedia.org/wiki/Elizabeth_II">Elizabeth II</a> page on Wikipedia.<br><br>
Those previews were fetched as soon as this page loaded. This is great for having the previews ready ahead of time, but can eat up extra bandwidth.
</p>

<p id="p2">
As an alternative, check out these same links to 
    <a href="https://culturesolutionsgroup.com">Culture Solutions Group</a> and 
    <a href="https://wikipedia.org">Wikipedia</a>
and 
    <a href="https://en.wikipedia.org/wiki/Elizabeth_II">Elizabeth II</a>. This time the previews aren't fetched until you hover over this paragraph.
</p>

<p id="p3">Finally, check out these links again to 
     <a href="https://culturesolutionsgroup.com">Culture Solutions Group</a> and 
    <a href="https://wikipedia.org">Wikipedia</a>
and 
    <a href="https://en.wikipedia.org/wiki/Elizabeth_II">Elizabeth II</a>. These previews are only fetched when needed (when you hover over the specific link.) This saves the most bandwidth on page load, but there will be a delay before the previews can be shown.
</p>

This goes in the Site (or Post) Header Injection...

<style>
.mini-preview-anchor {
    display: inline-block;
    position: relative;
    white-space: nowrap;
}

.mini-preview-wrapper {
    -moz-box-sizing: content-box;
    box-sizing: content-box;
    position: absolute;
    overflow: hidden;
    z-index: -1;
    opacity: 0;
    margin-top: -4px;
    border: solid 1px #000;
    box-shadow: 4px 4px 6px rgba(0, 0, 0, .3);
    transition: z-index steps(1) .3s, opacity .3s, margin-top .3s;
}

.mini-preview-anchor:hover .mini-preview-wrapper {
    z-index: 2;
    opacity: 1;
    margin-top: 6px;
    transition: opacity .3s, margin-top .3s;
}

.mini-preview-loading, .mini-preview-cover {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    left: 0;    
}

.mini-preview-loading {
    display: table;
    height: 100%;
    width: 100%;
    font-size: 1.25rem;
    text-align: center;
    color: #f5ead4;
    background-color: #59513f;
}

.mini-preview-loading::before {
    content: 'Loading...';
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}

.mini-preview-cover {
    background-color: rgba(0, 0, 0, 0); /* IE fix */
}

.mini-preview-frame {
    border: none;
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
}
</style>

This goes in the Site (or Post) Footer Injection...

<script>
(function($) {
    var PREFIX = 'mini-preview';
    
    // implemented as a jQuery plugin
    $.fn.miniPreview = function(options) {
        return this.each(function() {
            var $this = $(this);
            var miniPreview = $this.data(PREFIX);
            if (miniPreview) {
                miniPreview.destroy();
            }

            miniPreview = new MiniPreview($this, options);
            miniPreview.generate();
            $this.data(PREFIX, miniPreview);
        });
    };
    
    var MiniPreview = function($el, options) {
        this.$el = $el;
        this.$el.addClass(PREFIX + '-anchor');
        this.options = $.extend({}, this.defaultOptions, options);
        this.counter = MiniPreview.prototype.sharedCounter++;
    };
    
    MiniPreview.prototype = {
        sharedCounter: 0,
        
        defaultOptions: {
            width: 256,
            height: 144,
            scale: .25,
            prefetch: 'pageload'
        },
                
        generate: function() {
            this.createElements();
            this.setPrefetch();
        },

        createElements: function() {
            var $wrapper = $('<div>', { class: PREFIX + '-wrapper' });
            var $loading = $('<div>', { class: PREFIX + '-loading' });
            var $frame = $('<iframe>', { class: PREFIX + '-frame' });
            var $cover = $('<div>', { class: PREFIX + '-cover' });
            $wrapper.appendTo(this.$el).append($loading, $frame, $cover);
            
            // sizing
            $wrapper.css({
                width: this.options.width + 'px',
                height: this.options.height + 'px'
            });
            
            // scaling
            var inversePercent = 100 / this.options.scale;
            $frame.css({
                width: inversePercent + '%',
                height: inversePercent + '%',
                transform: 'scale(' + this.options.scale + ')'
            });

            // positioning
            var fontSize = parseInt(this.$el.css('font-size').replace('px', ''), 10)
            var top = (this.$el.height() + fontSize) / 2;
            var left = (this.$el.width() - $wrapper.outerWidth()) / 2;
            $wrapper.css({
                top: top + 'px',
                left: left + 'px'
            });
        },
        
        setPrefetch: function() {
            switch (this.options.prefetch) {
                case 'pageload':
                    this.loadPreview();
                    break;
                case 'parenthover':
                    this.$el.parent().one(this.getNamespacedEvent('mouseenter'),
                        this.loadPreview.bind(this));
                    break;
                case 'none':
                    this.$el.one(this.getNamespacedEvent('mouseenter'),
                        this.loadPreview.bind(this));
                    break;
                default:
                    throw 'Prefetch setting not recognized: ' + this.options.prefetch;
                    break;
            }
        },
        
        loadPreview: function() {
            this.$el.find('.' + PREFIX + '-frame')
                .attr('src', this.$el.attr('href'))
                .on('load', function() {
                    // some sites don't set their background color
                    $(this).css('background-color', '#fff');
                });
        },
        
        getNamespacedEvent: function(event) {
            return event + '.' + PREFIX + '_' + this.counter;
        },

        destroy: function() {
            this.$el.removeClass(PREFIX + '-anchor');
            this.$el.parent().off(this.getNamespacedEvent('mouseenter'));
            this.$el.off(this.getNamespacedEvent('mouseenter'));
            this.$el.find('.' + PREFIX + '-wrapper').remove();
        }
    };
})(jQuery);
</script>

<script>
            $(function() {
                $('#p1 a').miniPreview({ prefetch: 'pageload' });
                $('#p2 a').miniPreview({ prefetch: 'parenthover' });
                $('#p3 a').miniPreview({ prefetch: 'none' });
            });
</script>

From:

GitHub - lonekorean/mini-preview: jQuery plugin for adding live mini-previews to links on hover.
jQuery plugin for adding live mini-previews to links on hover. - GitHub - lonekorean/mini-preview: jQuery plugin for adding live mini-previews to links on hover.

If you have a lot of mini-previews on one page, and that page is loading too slowly, here is a modification you can make... https://github.com/lonekorean/mini-preview/issues/5

You can also find the source code and docs at... https://codegena.com/image-link-preview-on-hover/

And a supplementary modification... https://stackoverflow.com/questions/66701233/minipreview-jquery-link-preview-contents-of-parent-p-or-div-only