Vue 2 image and video loader supporting lazy loading, background videos, fixed aspect ratios, low rez poster images, transitions, loaders, slotted content and more.

Last update: Jul 10, 2022

Vue Visual npm

Vue 2 image and video loader supporting lazy loading. Visual 2.x is a simplification of Version 1.x with a greater reliance on modern browser features (IntersectionObserver, object-fit, srcset, sizes, etc).

Examples at https://bkwld.github.io/vue-visual.

Installation

  1. Install the package: npm install --save vue-visual or yarn add vue-visual
  2. Register the component:
    import Vue from 'vue'
    import Visual from 'vue-visual'
    Vue.component('visual', Visual)
    import 'vue-visual/index.css'
  3. These polyfills are recommended for older browsers:

Usage

See the Storybook.

Props

A list of the component properties that may be set on the Visual component.

Assets

  • image (string) : The URL of an image to load.

  • srcset (string) : An img srcset, used in addition to the image. Both are recommended.

  • webp-srcset (string) : A srcset that will be added to a source inside of a picture element with a type of image/webp.

  • video (string|array) : A video that is loaded after the image is loaded if the device supports video. If a string, should be the URL to a source video. If an array, a list of video URLs that will be added as difference <source>s.

Size

  • width (number|string) : This width will be applied to the asset element. If a number, it's assumed to be a px value.

  • height (number|string) : See width

  • max-width (number|string) : This value will be applied to the asset element as the css max-width. If a number, it's assumed to be a px value.

  • sizes (string) : Specify the img sizes attribute.

  • aspect (number) : Force the Visual to a specific aspect ratio. This works by making the asset position:absolute and then using an inner div with a padding-top set to a percentage.

  • expand (boolean) : Make the Visual fill it's container via CSS using absolute positioning.

Style

  • object-fit (string) - Default cover. Like the CSS property.

  • object-position (string) - Default center center. Like the CSS property.

  • align (string) - Default center middle.. Used in conjunction with slots to position the slot content. May be any combination of one horizontal (left, center, right) and one vertical (top, middle, bottom) choice, space-delimited.

Loading

  • autoload (boolean) - Default: true. If true, assets are loaded immediately unless lazyload.

  • lazyload (boolean) - Waits until the Visual enters the viewport to trigger loading. Overrides, autoload.

  • intersection-options (object) - IntersectionObserver options. Used with lazyload and autopause.

  • placeholder-color - Sets a background color behind the assets. Most useful in conjunction with an aspect value.

  • transition (string, boolean) - Default: 'vv-fade'. A Vue transition name that is applied when an asset is loaded. Set to an empty string to immediately render assets rather than waiting for loading.

Video

  • autoplay (boolean) - If true, begins playing immediately.

  • autopause (boolean) - If true, begins playing when the Visual enters the viewport and stops when it leaves. Overrides autoplay.

  • loop (boolean) - Sets <video> loop

  • muted (boolean) - Sets <video> muted

  • controls (boolean) - Sets <video> controls

Accessibility

  • alt (string) - Sets the alt attribute or aria-label value, depending on context.

Slots

  • default: Markup is added after the assets and before the loader
  • image-source: Adds <source> tags to the <picture> element.
  • video-source: Adds <source> tags to the <video> element.

Methods

  • load() - Manually initiate loading.
  • play() - Tell video to play.
  • pause() - Tell video to pause.
  • restart() - Tell video to restart playback from beginning.

Events

  • loaded:image - Image asset has finished loading
  • loaded:video - Video asset has finished loading
  • loaded - All assets hvae loaded

Contributing

  • Boot up the Storybook with yarn storybook and use that as your HMR friendly dev environment
  • Use npm version ... to build, tag, and update the poblished storybook

Changes from 1.x

  • Dropped props:
    • poster
    • fallback
    • per-asset variants for load, etc
  • Prop changes
    • background object-fit
    • background-position object-position
    • fill expand
  • Not testing for video support on device
  • Video playing state not stored in Vue state
  • Image and video loaded simultenously, not in series
  • Removed setDefaults for setting default options. See custom-defaults for an example of how to implement this functionality using a functional component.

migrate-1.x.coffee shows an example of a functional component that migrates the old API to the new API.

GitHub

https://github.com/BKWLD/vue-visual
Comments
  • 1. Add support for `playsinline` attribute

    Info: https://webkit.org/blog/6784/new-video-policies-for-ios/

    Either explicitly support the playsinline attribute as a prop or future proof by setting an attribute object as a config with boolean values, like :attributes="{ playsinline: true, loop: false }"

    Reviewed by thelucre at 2018-05-17 02:38
  • 2. Switching image breakpoints when there is a video showing should not be visible

    Right now there is a flash when switching between breakpoints, even when a video is up. I think this is because the image unloading makes the video v-show toggle because it is dependend on it's predecessor being loaded.

    Perhaps the refactoring of render in #1 will fix this.

    Reviewed by weotch at 2016-12-03 03:09
  • 3. Render an initial asset during SSR

    Currently, when vue-visual gets SSRed via Nuxt, there is no asset rendered. It would be nice if the rendering of the initial asset during SSG didn't depend in Nuxt hydrating the JS. This would also make it work better with lazy-hyrdate.

    Reviewed by weotch at 2019-06-27 14:28
  • 4. Demo page would be good

    Maybe creating a demo page for the different properties would be a good move. After all, a picture is worth 1,000 words!

    Great component though. Thanks for taking the trouble to create and share it.

    Reviewed by adavie1 at 2017-08-22 15:41
  • 5. videoLoaded never gets set to true in some instances when video is cached

    In some instances, the videoLoaded boolean never gets set to true. When I tested this, I found out that it's because the video element's canplaythrough event never fired. I think this is because the video was cached, and the video element triggered the canplaythrough event so quickly, it fired before Vue could register the event handler. One solution I found is to check the video readyState when the component mounts:

    @videoLoaded = true if @$refs?.video?.readyState > 3

    Here's a stack overflow that talks about this.

    Annoyingly, I can't reproduce this on Netlify, or even in vue-visual Storybook. I can only reproduce this when I run my Nuxt stack on localhost. Maybe Nuxt slows down the mounting/hydration (only in dev mode) just enough for visual to miss the canplaythrough event? I don't know.

    I'll send a pull request with the fix in a sec.

    Reviewed by jonjahr at 2020-09-15 18:56
  • 6. Add max-width:100% to .vv-slot to prevent line wrapping when .vv-slot contents

    https://github.com/BKWLD/vue-visual/blob/09f3f8b27f837b511b61fa69457af030e5aea071/index.vue#L149

    When contents of .vv-slot are wider than viewport, .vv-slot wraps below .vv-aspect-shim. Recommend adding max-width:100% to .vv-slot. I know the consumer can solve this by styling their own content's width, but this addition would make things more foolproof.

    See GIF of behavior: https://i.imgur.com/xTqPZQk.gif

    Reviewed by jonjahr at 2020-06-11 04:18
  • 7. Fix Safari issue "request is not allowed ... possibly because the user denied permission"

    The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.

    • https://sentry.io/organizations/bukwild/issues/945135646/events/c6e45d1d75704905a0ec04a025f46d41/
    • https://sentry.io/organizations/bukwild/issues/944677860/?project=1408716&statsPeriod=14d&utc=false
    Reviewed by weotch at 2019-04-02 20:09
  • 8. Add a slot align-strategy prop

    • vertical-align - The default
    • absolute - The transform apporach
    • table - Does display:table and display:table-cell on slot, useful when you want to use a ~~min-height~~ height on the visual.
    Reviewed by weotch at 2016-12-01 01:20
  • 9. Adds support for native loading="lazy" on img tag

    See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading.

    My hope is that this will improve PageSpeed scores because we don't need to create IntersectionObserver instances in order to do lazy loading.

    Reviewed by weotch at 2021-09-10 14:17
  • 10. Manual Load() method does not work

    I feel that the documentation is not clear about how to use the manual load, pause, play and restart methods.

    Screen Shot 2021-06-23 at 11 36 00 AM

    I used the code snippet from here: https://bkwld.github.io/vue-visual/?path=/story/assets--video

    However it seems that the load, pause, play and restart methods need to be manually created/defined in my component methods. In your example, all these methods are hidden, I don't know what they are supposed to be doing?

    The documentation says to use load on a click event, but what is it supposed to do? how do I actually get the video/image to load after clicking on a button? It is not mentioned anywhere.

    My assumption is that I have to add soemthing like this (see below). and then define what happens when you click on load. But i have no idea how to make it work. Please help?

    methods: {
    load() {
    ...
    },
    pause() {
    ...
    },
    play() {
    ...
    },
    restart() {
    ...
    }
    }
    

    Your example code:

    <div>
      <div style='margin-bottom: 0.5em'>
    <!-- NONE OF THESE BUTTONS WORK CAUSE THE METHODS ARE NOT DEFINED, THE EXAMPLE ON THE WEBSITE DOES NOT SHOW HOW TO HANDLE THESE METHODS, HENCE IT IS NOT USEABLE -->
      <button @click='load'>Load</button>  
      <button @click='pause'>Pause</button>
        <button @click='play'>Play</button>
        <button @click='restart'>Restart</button>
      </div>
      <visual 
        ref='visual' 
        :video='video' 
        :autoload='autoload'
        :autoplay='autoplay'
        :loop='loop'
        muted
        width='100%' />
    </div>
    
    Reviewed by vikrantRajan at 2021-06-23 18:43
  • 11. Make a responsive-height-craft-visual component.

    The point would be for 100vw x 100vh images where srcset alone isn't going to cut it. Take the case of a square viewport and a 16:9 image. It's going to get scaled up to fit the viewport. The solve would be something like this, where we create a bunch of source elements. It would pretty much requires an image CDN to work.

    This would probably consume responsive-craft-visual. I don't have a clear line of site on the API for this.

    Reviewed by weotch at 2021-04-30 23:45
  • 12. adding the ability to maintain the placeholder color if desired

    @weotch I added this, which was to solve this issue on Clifhttps://app.asana.com/0/1199094171432804/1200386443419587/f

    Problem:

    • when the image is loaded, the check for showImage does 2 things
      1. it fades in the image
      1. it fades out the placeholder element
    • Since both of those have a transition, you see the drop-shadow element for a second as the transition is happening on both
    • My idea for the fix is to pass a prop called maintainPlaceholder which doesn't wrap .vv-placeholder in the transition

    If you have an opinion on a better way to go about this, or at least how to clean up me needing to render the .vv-placeholder element twice, then let me know

    This works locally on clif for me, and passing maintainPlaceholder as a prop lets me control this on a component-by-component basis, because I don't want this to happen on say, transparent pngs

    Reviewed by mattaebersold at 2021-06-07 23:50
  • 13. fix image loading conflict with video

    The order of the switch statement in supports-images.coffee was leading to conflicts while rendering a visual that had potential to have either video or image. Reordered the switch and made a return if an image was found to be loaded.

    Reviewed by sjstark at 2021-06-02 23:43
  • 14. Detect loading to support older devices/browsers

    For ie11 and ipad 5th gen 12.1.1 type devices

    Some info on feature detection here: https://addyosmani.com/blog/lazy-loading/ and here https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement

    Need to make sure that lazyload is only set on the browsers that support it via 'loading' in HTMLImageElement.prototype detection.

    Reviewed by brokenhd at 2020-07-14 21:07
🐌 A small size Vue.js directive for lazy loading images using IntersectionObserver API

?? vue-tiny-lazyload-img A small size Vue.js directive for lazy loading images using IntersectionObserver API Demo Page https://mazipan.github.io/vue-

Nov 18, 2021
Vue.js Image Kit Component with Lazy Load built in and Responsive Images
Vue.js Image Kit Component with Lazy Load built in and Responsive Images

Vue Image Kit Vue.js Image Kit Component with Lazy Load built in and Responsive Images The inspiration comes from this and a talk from @derevandal in

Mar 31, 2022
Create lazy image, embed, video and element with animation just with attributes.

?? Lazy-attr v1.2.3 Create lazy loading request or element like image, iframe, video... Make custom animation on lazy and not lazy element on all brow

Jan 4, 2022
simplistic vue.js directive for image lazy loading

Vue Progressive Image Lazy load images while showing a preview. Super tiny, less than half a kilobyte minified and gzipped. usage v-lazy-img adds the

Aug 11, 2021
:camera: Mini Image Lazy Loader for P(R)eact and Vue
:camera: Mini Image Lazy Loader for P(R)eact and Vue

Pimg is a Progessive Image Component For React, Preact and Vue.js. It helps in lazy loading of images in a nice and cool way. It's 2KB (gzipped). It h

Apr 24, 2021
A small lazy image loader for Vue

lazy-vue lazy-vue is the easiest way to get a lazy image loader working within your vue projects. It is meant to be as simplest as possible, so you do

Jul 19, 2022
A super simple image lazy loader for Vue.

cube-vue-image-lazy A super simple image lazy loader for Vue. Install yarn add cube-vue-image-lazy Warning: You'll need to install the w3c Intersectio

Jun 19, 2020
A simple lazy-load list component based Vue 2.x: https://dwqs.github.io/v2-lazy-list/

v2-lazy-list A simple lazy-load list component based Vue 2.x, which will be on-demand rendering the list based container element's viewport. v1.x is n

Nov 18, 2020
Vue.js lazy load image directive with akamai image converter

vue-lazyload-akamai Vue.js lazy load image directive with akamai image converter ??

Aug 13, 2018
Component-based lazy (CLazy) load images in Vue.js 2

Vue Clazy Load Claziest lazy loader out there! Component-based image lazy loader for Vue.js 2 Swaps between your image and another component when load

Jun 14, 2022
A Vue.js component to lazy load images using the Intersection Observer.

vue-li-image A Vue.js component to lazy load an image automatically when it enters the viewport using the Intersection Observer API.

Mar 19, 2021
A plugin of lazy-load images for Vue2.x
A plugin of lazy-load images for Vue2.x

vue-lazyload-images A plugin of lazy-load images for Vue2.x Support images lazyload in window or build-in element. Demo Installation npm $ npm install

Mar 28, 2022
Flexible modal component for Vue with ability of asynchronous lazy loading

vue-async-modal Flexible modal component for Vue with ability of asynchronous lazy loading Usage Firstly, you should add Modal component in your templ

Mar 13, 2022
A Vue lazy loading directive.

A Vue lazy loading directive.

Feb 4, 2022
Vue progressive image loading plugin
Vue progressive image loading plugin

vue-progressive-image Vue progressive image loading plugin Installation $ npm install vue-progressive-image Usage import Vue from 'vue' import VueProg

Jul 15, 2022
Vue.js component for lazyloading YouTube videos.
Vue.js component for lazyloading YouTube videos.

vue-lazy-youtube-video 1.x documentation can be found here. vue-lazy-youtube-video Features Installation Via NPM Via Yarn Directly in browser Initiali

Jul 10, 2022
A lightweight web package that loads items in lazy way to achieve high performance and better UX in large lists
A lightweight web package that loads items in lazy way to achieve high performance and better UX in large lists

Lazy Load List Lazy Load List is a lightweight web package that loads items in lazy way to achieve high performance and better UX in large lists. Rend

Aug 10, 2022
A Lazy load plugin for Vue 3.x

vue3-lazy Status: Alpha. Lazy load plugin for Vue 3.x inspired by vue-lazyload. This plugin support very simple options, and easy to use. Install $ np

Feb 8, 2022
simple calculation lib with lazy feature 🎲➕➖➗✖️
simple calculation lib with lazy feature 🎲➕➖➗✖️

vue-lazy-calc this is a simple calculation plugin in lazy way. (inspired by lodash) features vue friendly strong typed lazy evaluation chaining method

Jul 30, 2020