Cloud Four Blog

Technical notes, War stories and anecdotes

Cloudinary updates responsive images breakpoint tool

In January, Cloudinary released a free tool for generating responsive image breakpoints that was based on some of the ideas I had for picking breakpoints based on performance budgets. Today they’ve updated with some amazing new features that I’m incredibly excited about.

The big new feature is that Cloudinary (and by extension, the free breakpoints tool) can now do art direction and output the <picture> element automatically!

This works because Cloudinary now has an algorithm that identifies the area of interest in each image. Then the tool allows you to define art-direction for each screen size by selecting the aspect ratio and viewport ratio, then it will do all the remaining work.

You can see this in action by using the Responsive Breakpoints tool and turning on all of the art direction options.

Simply handling the aspect ratio options is pretty cool by itself.

Responsive Breakpoints converts an image to 16:9 aspect ratio

There are a bunch of other improvement to the Cloudinary service including:

  • Analyzing every image to find the best quality compression level and optimal encoding settings
  • Automatically converting images to the whatever format the user’s browser supports that will compress best
  • Support for browser client hints which automates even more the responsive images work

For the full details on the improvement, check out Nadav Soferman’s announcement on the Cloudinary blog.

Service Workers at Scale, Part II: Handling Fallback Resources

Part I of this series established that some of the challenges in building service workers for complex websites stem from having to accommodate page request variations. In this iteration, we’ll touch on how to handle similar variations in the acquiring and delivering of fallback resources.

Pre-caching fallback dependencies

A familiar pattern for caching dependencies is to request them in bulk during the installation stage. We began with this approach in our own service worker, specifying path strings for all fallback resources:

addEventListener('install', event => {
  event.waitUntil(
    caches.open('dependencies')
      .then(cache => {
        return cache.addAll([
          '/offline',
          '/books-offline',
          '/assets/offline-avatar.png',
          '/assets/offline-photo.png'
        ]);
      )
      .catch(err => console.warn(err))
      .then(skipWaiting())
  );
});

Cache.addAll() converts each element of the array it receives into a new Request object, so you can conveniently pass it an array of strings. This simple approach worked well during local development, but there were some issues on our more complicated test server. We needed more control over the requests made by Cache.addAll(), so we created them explicitly:

cache.addAll([
  new Request('/offline', {...}),
  new Request('/books-offline', {...}),
  new Request('/assets/offline-avatar.png', {...}),
  new Request('/assets/offline-photo.png', {...})
]);

Constructing our own requests gave us the ability to override their default options. The necessity to supply these options became obvious once we saw 401 responses to our fallback page requests. The server had enabled HTTP auth, so requests sent from our worker in attempt to pre-cache resources were failing.

The credentials option solved this problem, allowing our requests to break through the authentication barrier:

cache.addAll([
  new Request('/offline', {credentials: 'same-origin'}),
  // ...
]);

We also decided to use the cache option for future-proofing. This will be useful for controlling how requests interact with the HTTP cache. While it currently only works in Firefox Developer Edition, we included it to make sure pre-cached responses are fresh1:

cache.addAll([
  new Request('/assets/offline-photo.png', {cache: 'reload'}),
  // ...
]);

For an overview of other cache option values, check out Jake Archibald’s article with various examples of service worker and HTTP cache interoperability.

Responding with fallback images

Our pre-cache items include generic images intended to serve as “fallbacks” for unfulfilled requests. We needed to account for two different fallback image types, each with their own visual treatment:

  1. Images embedded in articles
  2. Avatars for authors and commenters

To determine which fallback should be used for a given request, we associated each with a URL hostname:

const fallbackImages = new Map([
  [location.hostname, '/assets/offline-photo.png'],
  ['secure.gravatar.com', '/assets/offline-avatar.png']
]);

Using a map like this, we can conveniently lookup the proper fallback based on the URL of an unfulfilled request:

function matchFallback (req) {
  const {hostname} = new URL(req.url);
 
  if (isImageRequest(req)) {
    const image = fallbackImages.get(hostname);
    return caches.match(image);
  }
 
  // ...
}

“Redirecting” to offline pages

As with our fallback images, we also needed to accommodate a bit of variation in our handling of fallback pages. Some pages that we wanted to make available offline had too many images to justify pre-caching. In these cases, simplified versions of those pages (minus the images) were created to use as substitutes, as if they were redirected.

Because all of the pages with offline variations are local, they can be mapped by their URL pathname, and incorporated into our matchFallback() handler accordingly:

const fallbackPages = new Map([
  ['/books', '/books-offline'],
  ['/workshops', '/workshops-offline']
]);
function matchFallback (req) {
  const {hostname, pathname} = new URL(req.url);
 
  if (isImageRequest(req)) {
    const imagePath = fallbackImages.get(hostname);
    return caches.match(imagePath);
  }
 
  if (isPageRequest(req)) {
    const pagePath = fallbackPages.get(pathname);
    return caches.match(pagePath);
  }
 
  // Use an new response if nothing better can be found.
  return Promise.resolve(new Response(/* ... */));
}

Coming up next: Cache trimming and invalidation

In the next part of this series, we’ll cover strategies for invalidating old caches and limiting the amount of storage space they can occupy.


  1. To fill in for the sparse browser implementation, it’s recommended to use some form of cache-busting when pre-caching static resources. 

Why Mobile First Design Works

Spending the last few days in New York City for Smashing Conference reminded me of an analogy for Mobile First Design that seems to resonate with people.

If you’ve made your life fit in a tiny New York apartment, you’ll have no trouble when you move to a house in the suburbs.

But going the other way, from a house full of stuff to a tiny apartment, is much more difficult.

Designing for small screens works the same way.

Android Instant Apps, Progressive Web Apps and the Future of the Web

Google’s announcement of Android Instant Apps caused me to fear for the future of the web for the first time.

I’ve participated in many native versus web debates over the years. We even contemplated becoming an iOS-only shop after working on the Obama ’08 iPhone App.

But we chose to bet on the future of the web, and I had never doubted that decision in the years since until seeing Android Instant Apps.

Why Android Instant Apps Unnerved Me

When we placed that bet on the web years ago, we didn’t bet on the web “winning”. I didn’t think there was a contest to win. I expected apps and web to live side-by-side, and thus far, it has played out that way.

Plus, there were three factors that made me believe the web was the correct long term bet:

  1. PhoneGap/Cordova showed how most apps could be built using web technology once the web got access to device capabilities and features like push notifications.
  2. Scott Jenson’s Mobile Apps Must Die and the Triumph of the Mundane made compelling arguments that the app store model wouldn’t scale into an Internet of Things future. This belief is the foundation of the Physical Web project.
  3. Worst-case scenario, it seemed like a good future could be made simply building websites to promote apps.

We’ve finally reached a point where the promise of PhoneGap is becoming reality due to browser advances and Progressive Web Apps. And yet just as that promise is about to bear fruit, Android Instant Apps come along.

Stephanie Rieger once observed that we often install apps; give them space on our devices; and use our bandwidth to update them all “just in case” we need them. What we really need is “just in time” apps instead of “just in case” apps.

We need to use apps and throw them away. These sorts of transient experiences are something the web is excellent and that apps are poor at providing.

That is until Android Instant Apps which, in theory, make just-in-time apps possible.

And it is notable that one of the examples Google is showing off not only uses a common Physical Web example—a parking meter, but also uses the Physical Web beacon to launch the Android Instant App without ever opening the browser.

And if search results can open apps without needing to install apps, well, there goes my future career building websites for those apps.

Android Instant Apps may be vaporware

This year’s I/O keynote was full of promises and short on shipping code. Android Instant Apps was a prime example.

The scuttlebutt at the event is that Android Instant Apps have a long ways to go before they are ready for prime time. There are big questions about security, privacy, performance, and user experience that remain to be solved. And converting existing apps to Android Instant Apps in a single day is…optimistic.

But even if there are challenges, Android Instant Apps are a shot across the bow of the web. If there was ever any doubt that the owners of native platforms would eliminate the web if they could, there should be no doubt now.

Progressive Web Apps

At I/O, Google also heavily promoted the best alternative that we’ve had yet to native apps: Progressive Web Apps. The fact they were both promoted by the same company at the same event still blows my mind.

Over the last few days, there has been a lot of debate about progressive web apps between people who appear to be in violent agreement with each other. There’s been a lot more discussion than I can cover here so I am going to try (and probably fail) to summarize the debate thusly:

  1. Early progressive web apps are not responsive, not progressive, and only work on one platform and thus Google shouldn’t be promoting them.
  2. Chrome’s criteria for the app install prompt doesn’t support URLs as well as it should.
  3. Progressive web apps are a Google thing that they’re pushing that only works on Android to the determent of the broader web.
  4. People spend far too much time talking about apps and trying to make things that compete with native.

On the first two points, there is mostly broad consensus. The folks on the Chrome team dislike that the best examples they have thus far all have shortcomings, but they are the best ones have so far. They want to encourage developers to make them better instead of chastising them for not doing everything right out of the gate.

I sympathize with both perspectives. I agree with Michael Scharnagl when he cautions us to not repeat the errors from the beginning of responsive web design when it comes to progressive web apps.

And yet, if a client came to us and said they wanted to move to responsive web design, but they felt it was risky, I might very well suggest they start by using device detection to route mobile traffic to a m-dot site where they could test the design before rolling it out further.

That is what the BBC did with their beta responsive web design and they were praised for their work. How is that substantially different than Flipkart’s Progressive Web App for which they are getting grief? Yes, it started on Android Chrome only, but they promised to make it work elsewhere and are about to deliver on those promises.

I think the only major difference is that by the time the BBC did their mobile-only beta, we already had the Boston Globe to look at. Plus, we didn’t have a large company like Google using the BBC site as an example.

Keep in mind, Flipkart had actually shutdown its mobile website earlier so this is a welcome return to the web for them.

As far as URLs are concerned, the Chrome team agrees. Both Chrome and Opera are working on ways to fix it.

I find the third point fruitless to discuss as it seems to emanate from distrust of Google. I understand why people distrust Google, but distrust often makes for circular conversations because you can never address the core issue.

Which bring us to the final point and the question of whether or not we’re spending too much time worrying about native.

The web that cried wolf

In response to some of the progressive web apps criticism, Alex Russell went on a bit of a Twitter rant about the challenges facing the web. Peter Gaston collected the tweets and added some thoughts. Bruce Lawson from Opera chimed in saying that Alex “is not being alarmist; it's true.

And yet, the day after Alex issued a clarion call to save the web, Recode’s big headline is that The App Boom is Over:

Last month, the top 15 app publishers saw downloads drop an average of 20 percent in the U.S., according to research from Nomura.

Because this isn’t the first time that someone has sounded the web’s death knell, people were rightly skeptical.

I’ve been in the skeptical camp in the past. And I’ve previously ascribed a lot of the concern about the web from Chrome Googlers to their internal battles with the Android team.

It can’t be fun to be part of the Google’s Web Developer Relations team—recently renamed from Chrome Developer Relations to emphasize that their role is to promote the web, not one browser—and have the company you work for releasing Android Instant Apps. Worse, announcing it at a conference where you have to spend the next three days answering multiple questions about it from people like me. (Sorry!)

But the Google Web DevRel team also has more opportunity to talk to people working in companies around the world. Same with Opera. It would be foolish to completely dismiss what they say.

Plus, in addition to my fears of Android Instant Apps, I’ve recently been spending some time in Google Trends and the graphs for web-related searches are a bit depressing.

Web development vs. Android Development Google Trends

Web design Google Trends

Lately, I vacillate on whether the web is endangered or poised for a massive growth due to the web’s new capabilities. Frankly, I think there are indicators both ways.

Pascal’s Wager

A few years ago, I watched a video on climate change that applied a decision matrix to the question of whether or not climate change is real. The matrix looked something like this for worst case scenarios:

Climate Change Do Something Do Nothing
Not real Spend money unnecessarily, possible global recession Status quo
Real Save the world Destroy the world

That’s simplified, but it gets at the heart of the matter. If climate change deniers are right, the worst case scenario is a recession which sucks, but is something we’ve recovered from. If climate change deniers are wrong, the consequences for inaction are something that puts our existence as a species at risk.

I’ve been thinking about a similar matrix for this question of whether or not the web is imperiled by native and if we should do the things that Google advocates. That decision matrix might look like this:

Web is threatened Build PWAs Don’t Build PWAs
Not real Users get a faster, better web experience Current slow web
Real Users get a faster, better web experience, plus we save the web Web loses to native

I need to provide a few caveats on this table. First, I’m not equating people who say the web is fine with climate change deniers. The scientific evidence and consensus on climate change is overwhelming. Whereas I already mentioned that support for whether or not the web is endangered seems to change daily.

Second, I used progressive web apps here, but I’m using them as a placeholder for doing the work necessary to create faster and better experiences on the web. Basically, whatever we need to do to have less of this:

And more experiences that are so snappy—particularly on mobile devices—that people aren’t driven to native apps.

Build better experiences

When I think about the problem this way, the question of whether or not the web is imperiled doesn’t matter. The collection of web tools under the umbrella of Progressive Web Apps provide a better experience for people using our sites. This should be a no brainer.

Yes, none of the current examples of Progressive Web Apps are perfect. We have yet to see the Boston Globe or ESPN of Progressive Web Apps.

I see that as opportunity. An opportunity to build Progressive Web Apps that show how these tools can provide a better experience for everyone regardless of the device or browser they are using.

And I’ll say it again, I really want to work on the Boston Globe of Progressive Web Apps, so if you want to be that site, we should talk.

Whether you see the web as threatened or see Chicken Little in people’s fears and whether you like progressive web apps or feel it is a stupid Google marketing thing, we can all agree that putting energy into improving the experience for the people using our sites is always a good thing.

Introducing Drizzle

It’s hard to believe it’s been over three years since Dave Rupert wrote Responsive Deliverables, challenging the rest of us to start making “tiny bootstraps, for every client.” It’s been almost as long since Brad Frost and Dave Olsen created Pattern Lab, the first tool for building atomic design systems in the browser.

In true Portland hipster fashion, we at Cloud Four were designing in-browser before it was cool. This made the transition from page-level mockups to holistic design systems welcome and natural. It solved a lot of problems for us and (more importantly) our clients.

But presenting these deliverables could still be challenging. Some projects emphasized UX prototyping, others production-ready patterns. Some incorporated additional resources like element collages, project timelines or JavaScript documentation.

Because of this variety, we switched between a few different tools frequently. Our favorites were Pattern Lab (for its emphasis of atomic design principles) and Fabricator (for its speed and customization), but sometimes our needs were just too idiosyncratic for anything but a custom solution.

Which is why we decided to make Drizzle.

Drizzle logo

Drizzle is Cloud Four’s tool for generating pattern libraries and style guides. It started as a fork of Fabricator, incorporating features based on our team’s recent project needs and other style guides we admired. It uses Node, Gulp and Handlebars to generate static HTML you can host anywhere. Out of the box, it includes our Gulp tasks and Handlebars helpers to make prototyping and pattern-building fast and fun.

Screenshot of a Drizzle style guide page

Here’s what a brand-new Drizzle project looks like. We’re also using Drizzle for the Cloud Four redesign, as well as client work we aren’t able to share quite yet.

Drizzle is still a work in progress (as our issue queue will attest), but we’ve really enjoyed using it so far. Some of our favorite features:

  • The style guide UI is straightforward and easy to tweak.
  • Patterns, pages and layout templates can be reused and extended.
  • Control meta data, visibility and sorting via front matter.
  • Write patterns or pages in Handlebars or Markdown.
  • The template helpers are easy to extend, with a lot of really nice prototyping shortcuts out of the box. Dummy images, placeholder content, inline SVG and more are a snap.
  • The project uses PostCSS by default. Even if you need to add a heavier processor, Drizzle’s styles won’t slow you down.

If any of that sounds like your cup of tea, you can check out the Drizzle alpha now on GitHub.