Publishing Live Photos with Jekyll and LivePhotosKit JS

Published on by Geoff Taylor

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:

    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">         

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.


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:

        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=",-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 %}
    $(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/{{ }}" data-video-src="{{ site.url }}/images/live-photos/{{ }}" style="width: ' + divWidth + '; height: ' + divHeight + '">');
        $("#live-photo-container").append('<p class="live-photo-caption">{{ p.caption }}</p>');
        {% endfor %}
<script src=""></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 Live Photo control error in place of the normal Live Photo control 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.

Live Photos from California

Published on by Geoff Taylor

A few Live Photos I took on a recent trip to California, posted using LivePhotosKit JS. To see the video, hover your mouse pointer over the “LIVE” button in the top right corner of the photo. On a phone or tablet, tap and hold the picture.

For best results, use Safari if you’re on iOS. Chrome seems to work best on macOS. It works fine on macOS but seems to be a little buggy on iOS. (Apple says Chrome may work on Android, and any of the major browsers should work on Windows, but I haven’t tried those.)

Where Do Airport Codes Come From

Published on by Geoff Taylor

Interesting fact: Newark Liberty International Airport is EWR because in the U.S., “N” can only be used by the Navy.


Published on by Geoff Taylor

Experimenting with depth of field blur in Affinity Photo for iPad
Experimenting with depth of field blur in Affinity Photo for iPad

Day One Premium

Published on by Geoff Taylor

I’ve been using Day One since February 17, 2014, and I have 5,916 entries (although the majority of those are automated entries) in four journals. I’ve recorded everything from my daily routine to job changes to vacations in it.

When I read about the new premium service, I subscribed right away. It’s a valuable service that I use every day, and I want to see it continue for many years into the future, so it’s definitely worth the cost to me. It’s also a rock-solid, dead-simple way to keep a journal, and I strongly recommend it if you’re looking for such an app. The premium service is $49.99/year, but right now it’s discounted to $34.99 for new subscribers and $24.99 for current users of Day One 2.0.