Image Placeholders: Do it right or don’t do it at all. Please.

Hello. I’m a grumpy old web dev. I’m still wasting valuable memory on things like the deprecated img element’s lowsrc attribute (bring it back!), the hacks needed to get a website looking acceptable in both Firefox 2.5 and IE5.5 and IE on Mac, and what “cards” and “decks” meant in WAP terminology.

Having this – possibly pointless – information to hand means I am constantly getting frustrated at supposed “breakthrough” approaches to web development and optimisation which seem to be adding complexity for the sake of it, sometimes apparently ignoring existing tech.

What’s more annoying is when a good approach to something is implemented so badly that it reflects poorly on the original concept. I’ve previously written about how abusing something clever like React results in an awful user experience.

Don’t get me wrong, I absolutely love new tech, new approaches, new thinking, new opinions. I’m just sometimes grumpy about it because these new things don’t suit my personal preferences. Hence this article! Wahey!

In case you’re not sure why web optimisation is a good thing: if you don’t have any problems with your internet connectivity, speed, and data usage, then you’re one of the privileged internet users and you most likely live in a tech bubble. Lucky you! Optimise for everyone who isn’t so lucky.

I Hate…

… BADLY IMPLEMENTED IMAGE PLACEHOLDERS

I thoroughly enjoy learning about new approaches to dealing with the scourge of the internet, the concrete shoes of the average web page, the source of almost all web perf articles, that is… (dun dun DAAAHH) – images!

I’ve written about various image loading techniques for improved web performance a few times, and I’ve spoken about it at a couple of conferences and a few meetups.

When you have a long page full of images, then deferring loading those that aren’t immediately visible gives your page an initial speed boost due to fewer requests and less data needed; just make sure you’re careful about how and when you load those deferred images though, in case you cause terrible jerky scrolling and layout juddering.

One approach that’s really, really, annoyingly, really popular at the moment is poorly implemented LQIP – or “Low Quality Image Placeholder”; a term used for approaches that display something extra skinny in place of the actual image that’s intended to be displayed, while waiting for the full fat image to be downloaded.

The original concept was written about back in 2013 buy the extremely clever Guy Podjarny whilst he was working at Akamai, in an article called Introducing Low Quality Image Placeholders .

Originally the Low Quality version of the image was meant to be a still recognisable version of the image, which completely makes sense:

Small Image – 5.2KB

small image

Big Image – 15.6KB

big image

Can you see the difference? Not so obvious, right? It’s significantly smaller in file size, but you can still see what the content of the image is.

LQIP gone wrong

Happy days. Guy has given us web perf nerds another great tool to add to the ever-growing toolbox! Let’s rejoice. Everything is well in the world and 5 years on we’re all benefiting. Or are we?..

So many sites and developers have taken this approach to the extreme, and made Low Quality Placeholders so low quality that they’re making the implementation of LQIP a worse experience than doing nothing instead.

For example, a Medium article image placeholder:

Small Image

Medium article LQIP - can you tell what it's meant to be?..

What the?..

Big Image

Medium article fully loaded image - oh, is THAT what it is?!

OH I SEE….

What was the point in that? The placeholder was not representative of the final image, gave me no useful information at all, and on anything other than a super speedy connection I would have already scrolled away before it loaded. (Mainly because Medium combine LQIP with Lazy Loading. Sigh.)

The only times that I ever notice LQIP are on a slow connection (which makes sense). My grievances are:

  1. The placeholder image adds no value, since it’s far too low quality to represent the full image.
  2. The images are so different that when the full image loads in there’s a blip of mental load as you register a change in the page; this really annoys me as it takes focus away from the thing I was reading momentarily.
  3. I’ve usually almost scrolled past the image in question before it has loaded in, so I either gain no value from the image OR I find myself scrolling back up (ooh! shiny thing!) and losing focus.

I never actually see the LQIP when I’m on a decent connection (i.e., the full fat image loads in so quickly that the placeholder isn’t noticeable), so it’s only evident when it’s probably least useful.

So why do sites use LQIP (and other placeholder solutions)? Since the full image may take a while to load (we’re talking milliseconds – or possibly seconds, but hopefully not), LQIP would be a good idea when your images are so damn large that – even on a fast connection and high spec laptop – you will still have scrolled way past the image before it actually loads.

Case in point – most articles on The Verge website currently do this:

It’s the other side of this particular “poor web performance practise” coin: if one side is “badly implemented LQIP” then the other is “weird lazy-loading that’s not actually dealing with unoptimised images”.

The Verge black magic placeholder debacle

They have some horrible, JavaScript heavy, black pixel data uri placeholder solution weirdness that causes layout shifting when the image actually loads in and is so slow that the article is really annoying. Sigh. This site would actually benefit from a nice sprinkling of correctly implemented LQIPs throughout. Or… well… not doing anything and just let the images load. Or use progressive jpegs (which I’ll get on to soon!)

So, what should we be doing instead? Let’s review…

I Like…

… SETTING IMAGE DIMENSIONS

If you want to avoid the page jumping around as images are loaded in, changing the page flow, then set the image dimensions either on the element itself or in css; either way, the browser now knows how much space the image will take up and can lay the rest of the page out accordingly.

You don’t need to use a placeholder image to determine the page layout. Just set width and height in HTML or CSS.

… PROGRESSIVE JPEGS

In a progressive JPEG (or an interlaced gif/png) one image contains many scans of the actual picture at various levels of detail. Your device doesn’t need to download the entire file in order to start displaying something, and it could choose to stop loading the subsequent – higher detail – scans under certain conditions (low battery or poor connectivity, for example). They’re like built-in LQIP, but without extra JS functionality, CSS hacks, or extra images.

Progressive JPEG example
(picture borrowed from the excellent Book Of Speed website by Stoyan Stefanov)

The resulting image files can be slightly bigger than baseline jpegs (and non-interlaced gifs/pngs) in some cases, so be sure to balance this against any “placeholder” solution you may be planning to use.

However, there’s extra cognitive load (and some anxiety) with these approaches, as people aren’t sure when an image has actually finished loading. The difference between the 70% complete version and the 80% and 100% versions will be barely noticeable, so how can a user tell when an image is fully loaded? I mean, the point is that it shouldn’t matter, so long as the image is “good enough” as quickly as possible, but users still tend to wonder if the image is completed yet.

A baseline (or non-interlaced) image is much easier to know when it’s finished, but you won’t be able to see the actual contents of the image as quickly.

… WELL IMPLEMENTED LQIP

If you’re going to use low quality placeholder images, make them representative of the image they’re… uh… placeholding.

  • Don’t use placeholders that are blurry, pointless, meaningless, rubbish.
  • Do use placeholders that are somewhat smaller images than the originals (i.e. optimised to the point of not looking as good as you’d like, but still completely recognisable)

Think about the less privileged internet users out there; especially in the wake of the Net Neutrality upset – users might literally be paying more to see high quality images, even in your privileged tech bubble.

Consider high quality images a progressive enhancement; the page should be completely usable without them.

… NOT USING IMAGES!

Think about whether you even need to use images. Yes, images are worth a thousand words, but they might weigh more than that in kilobytes!

Here’s a quick “grumpy-old-web-dev” checklist to not wasting your user’s bandwidth/time/sanity:

Are you using images to enhance and explain your article or textual content?

Good work, carry on. Be sure to set alt attributes and image dimensions and all that. Be absolutely sure to optimise all the things too, obviously (right?)

Are you sending big hero images even to a low end device on a poor connection with low battery?

Don’t be daft. It’s wasteful for everyone involved; you pay for data transferred (at some point in the process) and they pay for data downloaded/battery used/time wasted. Remember Net Neutrality, right?..

Too old school for you?

Don’t fancy using progressive jpegs (or interlaced gif/png) and can’t bear to remove those lovely arty pictures of discarded shopping trolleys and whatnot? Try these alternatives:

picture

Go for the picture element with several srcsets defined. This allows your browser to decide to only download the most appropriate image.

<img src="img-base.png" 
    srcset="img-120.png 120w, 
            img-240.png 240w,
            img-1200.png 1200w" />

You can generate the image dynamically on your own backend (see my “client hints” github repo’s ImageController, mentioned below) or use a gulp or grunt task to do so prior to release.

Client Hints

Add in a Client Hints header – and even a Save Data header – being sure to actually check for the headers on the server (or in a service worker) to determine the response, then you can send only the most appropriate image for the client.

I’ve written about client hints before in some detail, even with an example implementation.

Summary

There are so many different approaches for loading images and giving a great user experience without impacting performance and speed; really think about your use case and implement the correct solution for that particular situation.

Consider solutions like:

  • LQIP (with recognisable placeholder images)
  • Progressive JPEGs
  • picture element with srcset attributes
  • Client Hint headers
  • Save Data headers

Got some spare money? Use a CDN’s built in optimisations instead, saving you significant time and effort

A great place to read about various solutions over the years is the annual Perf Planet Performance Calendar.

Got an opinion? Great, let me hear it. Like I said at the start of this, I love new approaches, new thinking, new tech – so I’d love to hear about yours.

London Bot Framework Meetup the Third

Welcome to the Third London BotFramework Meetup! Here's the line up

On Wednesday 22nd November 2017 I had the pleasure of running the third London Bot Framework meetup at the lovely Just Eat office in central London. The offices have been recently upgraded and the new meetup space has a huge 9 screen display a multiple mic speaker system, including a fantastic CatchBox throwable mic for ensuring everyone hears the audience questions

It has been a year since the previous one (whoops) but it was great to see some familiar faces return in the attendees. I had forgotten how much fun it is to emcee an event like this! Maybe next time I’ll be sure to just emcee and not also commit presenting a session too.

Video

If you want to just cut to the chase, then here’s the video – there are gaps between sessions as we refuel and natter, but skip along a few minutes and we’ll get back to business soon enough.

  1. Jamie Dalton: 1m40s
  2. Robin Osborne: 28m50s
  3. Kristian Brimble & Sam Kavanagh: 1h09m

Sessions

There were three sessions spanning the evening, covering a varying selection and level of botframework and cognitive services content.

1) Handing off to a human for agents/supervisors with C# and the BotBuilder SDK

The first session started with us all overcoming some technical difficulties – the Just Eat system works great if you’re presenting from the one PC that’s wired up to the AV system, but plugging another laptop is was proving very tricky! We got around it by starting a Google Meet (nee Hangout) on the presentation PC and having Jamie connect as the presenter from his laptop. Phew.

Luckily the pizza arrived perfectly timed to cover this technical blip!

Jamie Dalton – Microsoft UK Technical Evangelist

Jamie showing us how to handle botchats between multiple channels

Jamie works as a technical evangelist in the UK, helping customers and partners develop solutions based on the Microsoft platform. He really is as old as he looks, with over 20 years’ experience as a Microsoft software developer. He is passionate about Application Lifecycle Management, developer tooling, DevOps and creating new experiences using Microsoft technologies in the cloud. He has a degree from the university of life and once read some books!

I had first seen Jamie’s solution via a twitter link of a video where he shows a Skype client and a Slack client both connecting to a Bot Framework chatbot and asking to be transferred to a human, which has a UI for all currently connected chats; this was inspirational to me at the time, as I was working on the Just Eat customer help chatbot which needed to hand over to a human help agent in various scenarios. Could it use this solution?

Slides

So so cool.

2) Cognitive Services: The Speaker Recognition API

Robin Osborne - ME - listing off the phrases needed to set up speaker verification
The filling in this botframework session sandwich was my own session about the fantastic Speaker Recognition API from the Microsoft Cognitive Services.
I talked about some of the incredible offerings from Cognitive Services, then gave a potentially chaotic live demo of the Speaker Verification and Speaker Identification APIs!

3) Robots Testing Robots

Kristian Brimble answering the big questions

Sam Kavanagh telling it how it is

Kristian Brimble and Sam Kavanagh from the Just Eat Help Chatbot dev team took us through the Just Eat chatbot testing process, referring to the classic test pyramid approach.

Summary

Another fantastic meetup from my perspective; the JustEat meetup space is great, as is their beer and pizza.

The recorded video even has embedded camera footage of the speaker, so you feel like you’re in the room (or at least, on a live video stream!) which I found added a lot to the video.

I’m looking forwards to the next one, hopefully in January.

The Tesco Mobile Website and The Importance of Device Testing

A constant passion of mine is efficiency: not being wasteful, repeating something until the process has been refined to the most effective, efficient, economical, form of the activity that is realistically achievable.

I’m not saying I always get it right, just that it’s frustrating when I see this not being done. Especially so when the opposite seems to be true, as if people are actively trying to make things as bad as possible.

Which brings me on the the current Tesco mobile website, the subject of this article, and of my dislike of the misuse of a particular form of web technology: client side rendering.

What follows is a mixture of web perf analysis and my own opinions and preferences. And you know what they say about opinions…

Client Side Rendering; What is it good for?

client side rendering frameworks

No, it’s not “absolutely nothing”! Angular, React, Vue; they all have their uses. They do a job, and in the most part they do it well.

The problem comes when developers treat every problem like something that can be solved with client side rendering.

Continue reading

Building your first Botframework based Cortana Skill

Hi. I'm Cortana.

At //BUILD 2017 Microsoft announced support for Cortana Skills and connecting a Cortana Skill into a Bot Framework chatbot; given the number of chatbots out there using Microsoft Bot Framework, this is an extremely exciting move.

In this article I’ll show you how to create your first Cortana Skill from a Bot Framework chatbot and make it talk!

Cortana

If you’re not already familiar with Cortana, this is Microsoft’s “personal assistant” and is available on Windows 10 (version 1607 and above) and a couple of Windows phones (Lumia 950/950 XL), a standalone speaker – like an Amazon Echo – and a plethora of devices that can run the Cortana app, including iOS and Android and plenty of laptops.

Cortana all the things, Derrick.

You’re going to be seeing a lot more of this little box of tricks (“Bot” of tricks? Box of bots?.. hmm…), so you might as well get in on the act right now!

Continue reading

Involved in a startup? Read this!

Having been the VP of Engineering at a startup, I understand a lot of the challenges. The technical ones relating to the solution you think you need to build, more technical ones relating to the solutions the investors want you to build, the development process to best fit a rapidly changing product, team, requirements, and priorities, as well as managing the team through uncertain terrain.

They’re the fun ones. The easy ones! Especially given how talented my dev team was.

The founder had the difficult challenges; define a product that could be a success, iterate that idea based on extensive user testing, and most importantly, ensure there was funding.

Luckily, our founder was as talented at soliciting funds as we were at building epic tech!

If you are involved in a startup, perhaps Just Eat’s Accelerator programme can help with both types of challenge!

Continue reading

Receiving Images to Your Skype Botframework Bot (v2!)

If you’re getting a “403” HTTP error when attempting to receive an image sent to your Skype bot, and the previous use of message.ServiceUrl to create a ConnectorClient didn’t work, try this more verbose version which explicitly sets the authorization header:

byte[] data;

if (image.ContentUrl != null)
{
    using (var connectorClient 
        = new ConnectorClient(new Uri(message.ServiceUrl)))
    {
        var token = 
            await (connectorClient.Credentials as MicrosoftAppCredentials)
                .GetTokenAsync();

        var uri = new Uri(image.ContentUrl);

        using (var httpClient = new HttpClient())
        {
            if (uri.Host.EndsWith("skype.com") 
                && uri.Scheme == Uri.UriSchemeHttps)
            {
                httpClient
                    .DefaultRequestHeaders
                    .Authorization = 
                        new AuthenticationHeaderValue("Bearer", token);

                httpClient
                    .DefaultRequestHeaders
                    .Accept
                    .Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
            }

            // Get the image in a byte[] variable
            data = await httpClient.GetByteArrayAsync(uri);
        }
    }
}

Generating Image Hashtags using Microsoft’s Computer Vision API

Whatever your social media tool of choice is these days, it’s almost guaranteed to be filled with images and their associated hashtags #sorrynotsorry #lovelife #sunnyday

Sometimes coming up with those tags is more work than perfectly framing your latest #flatlay shot.

In the age of amazing image recognition tech, it must be possible to create something that can help us out and give us more time to move that light source around to cast the right shadow over your meal.

Turns out, it is possible! Yay! (of course..)

In this article I’ll show you how to automatically generate image hashtags via a chatbot using Microsoft’s Computer Vision API.

Continue reading

Sentiment Analysis using Microsoft’s Cognitive Services

Now that we are making more conversational interfaces thanks to technology like botframework, interaction with the user is no longer limited to a tap on a link or a button.

Having written language as the primary form of interaction with our systems gives significant difficulties in terms of intent understanding, but also gives great opportunities for further understanding of the user.

Intent understanding has already been tackled by the likes of LUIS; what about the user’s sentiment?

In this article I’m going to introduce Microsoft’s Text Analysis API and show you how to easily get sentiment analysis for a message coming in to your bot.

Continue reading

MVP led TechDays Online: Videos!

As part of Microsoft’s recent Tech Days Online, I was very pleased to be able to record a couple of short videos about botframework, LUIS, the QnA Maker, and how I have been working with JustEat to use these technologies in their Customer Help chatbot solution.

Unfortunately I wasn’t able to attend the live TechDays sessions, so instead of an hour or two of my dulcet tones you only have the pleasure of ten minutes; feel free to replay those minutes as many times as you like!

First up, a ten minute session on the JustEat Customer Care chatbot implementation:

Continue reading

5 Cool Chatbots: Feb 2017 Edition

ChristopherBot (Facebook)

Never forget your homework again

I have to include this bot first; it’s received a lot of press over the past few weeks, and rightly so. A great little concept from a 14 year old schoolboy who was forever forgetting about his homework. He created a Facebook messenger chatbot in Ruby and hosted on Heroku to help him (and you!) keep track of work that’s pending.

ChristopherBot

Read more about ChristopherBot on the BBC and try it out over at christopherbot.co. You can view the code (mainly Ruby) over on GitHub – annoyingly good code from someone so young! He puts me to shame..

Continue reading