I recently posted three Live Photos using LivePhotosKit JS. My blog is built with Jekyll, and I wanted the Live Photos to display correctly on large and small screens. Since getting it to work took some trial and error, and there aren’t a lot of helpful resources other than Apple’s documentation, I wrote this post to explain how I got it to work.

The Apple way

First I tried Apple’s recommended method, adding the appropriate data- attributes to a <div> element:

<div
    data-live-photo
    data-photo-src="{{ site.url }}/images/live-photos/IMG_7280.JPG"
    data-video-src="{{ site.url }}/images/live-photos/IMG_7280.MOV"
    style="width: 640px; height: 852px">         
</div>

But I ran into a problem. It looked fine on a big screen, but the picture overflowed the <div>’s parent container on the iPhone screen in portrait orientation.

  Screen shot of the webpage on macOS
It looked the way I expected on macOS.
  Screen shot of the broken webpage on iOS
On iOS... not so great.

If you want it to be viewable on different screen sizes, Apple’s method doesn’t really work.

Media queries

My first thought was to use media queries to control the size of the <div>, but LivePhotosKit complained about the <div> having a width and height of zero. After a little more experimentation, I concluded that CSS wouldn’t work. It seems that LivePhotosKit expects the <div> to have a style attribute with a non-zero width and height.

Solution

To appropriately set expectations, I’ll introduce this next part by saying that my front-end development skills are pretty amateur, and my solution isn’t elegant. This is how I finally got the Live Photos to render correctly on large and small screens.

In the post’s front matter, I listed the photo, the video and a caption for each Live Photo I wanted to display on the page:

live_photos:
    -
        photo: IMG_7280.JPG
        video: IMG_7280.MOV
        caption: Taxiing in the rain in Atlanta
    -
        photo: IMG_7337.JPG
        video: IMG_7337.MOV
        caption: Sunset at <a href="https://maps.google.com/?q=37.0046,-122.188">Shark Fin Cove</a>

    -
        photo: IMG_7341.JPG
        video: IMG_7341.MOV
        caption: There were lots of rabbits on the cliffs above the cove.

In the body of the post, I put an empty <div> to serve as the container for the Live Photos:

<div id="live-photo-container"></div>

Finally, I have an include called scripts.html that’s included in my post template. I added this to the end of scripts.html:

{% if page.live_photos %}
<script>
    $(document).ready(function() {
        var divWidth;
        var divHeight;
        if (screen.width < 640) {
            divWidth = "320px";
            divHeight = "426px";
        }
        else {
            divWidth = "640px";
            divHeight = "852px";
        }
        {% for p in page.live_photos %}
        $("#live-photo-container").append('<div data-live-photo data-photo-src="{{ site.url }}/images/live-photos/{{ p.photo }}" data-video-src="{{ site.url }}/images/live-photos/{{ p.video }}" style="width: ' + divWidth + '; height: ' + divHeight + '">');
        $("#live-photo-container").append('<p class="live-photo-caption">{{ p.caption }}</p>');
        {% endfor %}
    });
</script>
<script src="https://cdn.apple-livephotoskit.com/lpk/1/livephotoskit.js"></script>
{% endif %}

{% if page.live_photos %} ensures that the JavaScript is executed, and LivePhotosKit JS is loaded, only if the post contains Live Photos.

The script is wrapped in jQuery’s $(document).ready() function to make sure the <div> with ID live-photo-container is present before the Live Photo <div> elements are added to the page. If the screen is less than 640 pixels wide, the width is set to 320px, and the height is set to 426px. Otherwise, the width and height are set to 640px and 852px.

Then for each Live Photo defined in the post’s front matter, jQuery is used to append a <div> with the proper attributes to the <div> with ID live-photo-container. Finally, LivePhotosKit JS is loaded to do the heavy lifting.

It’s not an elegant solution. It only handles two broad screen sizes, and the Live Photo isn’t centered on iOS. But it works well enough for now.

Screen shot of the webpage rendered correctly on iOS
You can actually see the whole image on iOS now.

A few oddities

In case you want to try this for yourself, here are a few issues I encountered.

When I was testing locally on my MacBook (using bundle exec jekyll serve), Firefox was the only browser that would actually render both the photo and the video elements on macOS. Safari and Chrome just rendered the static photo and showed in place of the normal control. Neither Safari nor Chrome would play the video on iOS. They behaved in the same way as Safari and Chrome on macOS.

The Live Photos rendered correctly in all browsers (sort of; see below) only after I moved everything to my web server.

In my experience, browser compatibility wasn’t consistent with the list of supported browsers in Apple’s documentation. On macOS, Live Photos on the web are best viewed in Chrome. Safari and Firefox work, but the performance is a little worse when transitioning from photo to video.

On iOS, Safari was the only browser that worked for me, but it crashed frequently, usually after playing one of the videos for the first time. Chrome on iOS didn’t work at all for me. It crashed almost immediately on both my iPhone 6S and my iPad Pro.

Unobstruct

A review of the iOS app unobstruct
Continue reading

Sunset on the Cuyahoga River

Published on August 13, 2017

Storm Clouds and Control Tower at ATL

Published on August 13, 2017