Using HTTP/2 Responsibly: Adapting for Users

A note from the editors: This article is part one of a two-part series exploring the new HTTP/2 protocol and using it responsibly. Be sure to read part two, Considering How We Use HTTP/2.

With HTTP/2 ticking up steadily in use, it’s clear that there’s something to this long overdue update to the protocol. Implementing it, however, not only changes how websites are delivered to the user, it demands that we think critically about how we migrate existing sites to the protocol. More importantly, it demands that we consider our users’ capabilities.

Article Continues Below

Whether you’ve already migrated your site to HTTP/2 or you’re bracing yourself to take the plunge, there are challenges when it comes to tuning your site’s front end architecture to be the most performant it can possibly be for all your users. Perhaps you’ve read about what it takes to get your site ready for HTTP/2. Perhaps you haven’t. If the latter describes you best, it’s not worth getting into the weeds here. The gist of it is that HTTP/2 optimization patterns are the opposite of those for HTTP/1. Your site will perform better on HTTP/2 if you avoid practices that combine files, because caching for those resources will be more efficient when they change.

In order to cope with the limitations of the aging HTTP/1 protocol, we were more than willing to sacrifice some degree of caching effectiveness for return visitors in order to speed up the initial loading of a site. Thus, techniques like scripts and CSS concatenation, image sprites, and inline assets were embraced. In a world that’s creeping toward HTTP/2, however, we’re told to abandon these practices —and for the most part, rightly so.

The reality of the situation can be more complex than we initially thought. While HTTP/2 support on both the server and client side is steadily increasing, browsers that can’t understand the new protocol will linger on for some time yet—and that doesn’t just mean Internet Explorer. It also includes browsers like Safari on older versions of OS X, UC Browser, older versions of Android Browser, and Opera Mini.

Sometimes we hurt the ones we love#section2

HTTP/2 support is not a one-sided affair. In order for it to work, the server must not only implement it, but the browser must also be capable of understanding the new protocol. When a browser that understands HTTP/2 begins requesting content from an HTTP/2 server, the exchange will predictably occur in, well, HTTP/2. In the case of an older browser like Internet Explorer on Windows 7 (or even a current browser such as Opera Mini), the conversation proceeds in HTTP/1. The underlying mechanism that drives this behavior is nuanced, but it can be considered progressive enhancement in that we’re not breaking the experience for users on platforms that can’t use HTTP/2. They’re merely getting a less optimal experience.

Whether you’ve made the jump and optimized your site for HTTP/2 already, considering the jump from HTTP/1, or somewhere in between, it can pay (sometimes quite literally) to understand how these optimizations can impact your site’s users. Depending on your audience’s capabilities, a site optimized for HTTP/2 may well be detrimental for a segment of your audience.

HTTP/2 enjoys broad support among users in the global sense. According to the popular feature support index site, HTTP/2 currently enjoys support of roughly 78% of all browsers currently in use. Some fringe browsers such as IE 11 below Windows 10, and Safari on OS X below El Capitan muddle the picture a bit. You can count on at least 72% of users globally to support HTTP/2 (at least at the time of this writing).

Of course, this is just the big picture, and it isn’t an indicator of what your specific audience looks like. You need to consider the source of your visitors and what browsers they tend to use. You also need to consider where your users reside in the world.

In the rudimentary statistics I’ve compiled from, I’ve found that users in developing nations tend to use browsers that don’t support HTTP/2 more often than those in developed nations. Following that up with statistics from Akamai’s Q3 State of the Internet Report, developing nations generally have a lower quality of internet infrastructure than developed nations. I won’t get into the data here (though you can have a look for yourself), but if you’re curious, you can check out this short write-up I’ve done on the subject to get some context.

The confluence of these two truths creates a challenge in how we optimize sites for our visitors.

  • Even if you set up a web server that uses HTTP/2, there’s a segment of your audience that won’t receive the benefits because their connection to your server will be over HTTP/1.
  • Even worse, if you’ve optimized your site for the best performance on HTTP/2, you’ve likely made your website slower for users with older browsers.

“Aw, hell! They should just upgrade their browser!” While some of us have said this at one time or another out of utter frustration in the face of solving a challenging problem, this is a terrible sentiment. It presupposes that the user has the ability to upgrade their browser, but they’re just too damn lazy to get around to it.

The more likely problem is that users in developing nations are reliant on antiquated infrastructure or bound to a restricted data plan that makes this impractical. We need to be empathetic to this reality. It behooves you to know how many of your users are running HTTP2-capable browsers, and how many aren’t. All you need to determine this is a Google Analytics account and caniuse.

caniuse is able to comb through your site’s visitor data, then give you the status of support for a particular browser feature in the context of your site’s visitors, rather than for a particular country. Perfect for determining browser support for HTTP/2 in your audience! By opening the settings panel in the site and then clicking the “Import” button under the “From Google Analytics” header, you’ll be prompted to allow caniuse to access your analytics.

Here’s a real world scenario in which I’ve used this tool to determine an audience’s HTTP/2 support: My friend runs a reasonably popular blog about guitars and guitar accessories that receives roughly 30,000 pageviews per month. When I fed the site’s Google Analytics data into caniuse, it showed that the site’s audience over the most recent 30 day period had about 91% support for HTTP/2 (Fig 1).

Visual comparison of two equations: All Web Site Data (78.47% + 12.27% = 90.74%) and Global (70.13% + 5.95% = 76.08%)
Fig. 1:’s support threshold for HTTP/2 for a specific site, labeled “All Web Site Data.”

91% seems like a high level of support for HTTP/2 —and it is! Despite that fact, you must take into consideration the raw number of pageviews from browsers fetching resources over HTTP/1 because they don’t support HTTP/2.

Some basic math reveals that this segment represents 2,700 pageviews per month. Furthermore, the quoted support of 91% includes browsers that partially support HTTP/2. In this specific example, we can only be absolutely certain that around 78% of this site’s visitors support HTTP/2. This means that anywhere from 2,700 to 6,600 pageviews may be served over HTTP/1. The actual number is somewhere in between, and even though this is a minority of users, it’s still a significant number of pageviews on its own, and it may be too large for you to simply ignore.

Adapting your users’ limitations#section3

By this point, we know three things:

  1. HTTP/2 servers will downgrade to HTTP/1 when responding to HTTP/2-incompatible browsers.
  2. HTTP/2-specific front-end architecture optimizations are usually detrimental to users on browsers that are HTTP/2-incompatible.
  3. Users in developing nations tend to have a lower level of support for newer browser features like HTTP/2, and tend to have slower internet connection speeds.

The only thing we don’t know at this point is how to fine-tune our content delivery so that it’s beneficial for everyone. Before we can really think about modifying how content is delivered to the user, there are a couple of things we should consider first.

Is HTTP/2 right for you?#section4

Assuming you haven’t already migrated to HTTP/2, there are a few things to take into account before you invest time and resources into making the switch:

  1. While the HTTP/2 specification doesn’t explicitly require SSL, it is a de facto standard in that browsers require it. If you implement HTTP/2 on your server and fail to install a valid SSL certificate, the connection will always downgrade to HTTP/1. For the budget-conscious, certificates range from reasonably priced to 100% free via Let’s Encrypt. Even with free certificates, implementing SSL still represents a cost to your organization. It takes time and effort in the form of QA testing to ensure that existing sites aren’t broken in the migration.
  2. If your site’s footprint is very small, HTTP requests are few, and upgrading to SSL isn’t pragmatic, you may already be well-served by HTTP/1. This is especially true if you’ve implemented HTTP/1-specific optimizations and it would cost significant developer time to unravel them into HTTP/2 optimizations. This doesn’t mean that you shouldn’t upgrade to SSL, though.
  3. If most of your site’s audience uses browsers that can only support HTTP/1 and your site is well-optimized for it, you’re probably already well-served by HTTP/1. But again: consider SSL anyway.

Let me be totally clear: HTTP/2 is an excellent performance enhancement for large, complex sites with lots of assets that would otherwise perform poorly on HTTP/1. We just need to talk about how you might be able to mitigate some of the pain for users with less capable browsers, and that begins with identifying those users when they visit.

Checking for HTTP/2 and adapting to users’ needs#section5

How you deliver content based on a given user’s HTTP protocol version depends on what technologies you have available on your host. You’ll usually use a back end language like PHP to modify the markup you send to the client. Regardless of the technology you use, there are two conditions you’re covering:

  1. If the user is on HTTP/2: You’ll serve more and smaller assets. You’ll avoid stuff like image sprites, inlined CSS and scripts, and concatenated style sheets and scripts.
  2. If the user is on HTTP/1: You’ll do the opposite. You’ll bundle files, use image sprites, and inline small assets.

The specific mechanism by which you detect HTTP/2 support will depend on the back end language you use. In PHP, we can determine the protocol version of a given connection by checking the $_SERVER["SERVER_PROTOCOL"] environment variable. Below is a one-liner that stores the HTTP/2 connection status in a variable named $isHttp2:

$isHttp2 = stristr($_SERVER["SERVER_PROTOCOL"], "HTTP/2") ? true : false;

Using the stristr function, the $_SERVER["SERVER_PROTOCOL"] environment variable is checked for the presence of the substring "HTTP/2". If the substring exists, $isHttp2 is set to true. If not, it’s set to false. From here, it’s up to you to apply this logic to your site, but let’s look at a couple of things you could do. For instance, you could add a class of http1 to the tag:

if ($isHttp2 === false) {
	?><html class="http1"><?php
} else {

Using this class, you can adapt your CSS to serve an image sprite for HTTP/1 users, and individual images for your HTTP/2 users. Or maybe serve a separate CSS file with inlined assets using the data URI scheme. Speaking of serving different files, you could change your markup based on the user’s protocol version to change how you serve assets to the client:

if ($isHttp2 === true) {
	<script src="/js/script-1.js"></script>
	<script src="/js/script-2.js"></script>
	<script src="/js/script-3.js"></script>
} else {
	<script src="/js/script-bundle.js"></script>

Or you could change your markup to inline some critical CSS for HTTP/1 users with the handy file_get_contents function:

if ($isHttp2 === true) {
	<link rel="stylesheet" href="css/critical.css">
} else {
	<style><?php echo(file_get_contents("css/critical.css")); ?></style>

Of course, on HTTP/2 sites, you would take any content that you’d normally inline and use server push to confer the benefits of inlining without actually inlining content. How you specifically adapt your site’s content delivery based on the visitor’s protocol version really depends on your specific situation.

This concludes the first article! In part two of this series, we’ll:

  • Apply these techniques to a real world scenario
  • Use a performance testing tool to check for meaningful comparisons se a build system to generate HTTP/1-friendly assets so you can keep your workflow clean and efficient.

Further reading#section6

Learn more about boosting site performance with Jeremy’s book Web Performance in Action. Get 39% off with code ALAWPA.

About the Author

A photograph of Jeremy Wagner. He is standing against a backdrop of grass and trees, with a green-to-blue swash on the left side of his hair.

Jeremy Wagner

Jeremy Wagner is more of a writer than a web developer, but he does both anyway. On top of writing Responsible JavaScript and making websites for longer than he thought probable, he has written for A List Apart, CSS-Tricks, and Smashing Magazine. Jeremy will someday relocate to the remote wilderness where sand has not yet been taught to think. Until then, he continues to reside in Minnesota’s Twin Cities with his wife and stepdaughters, bemoaning the existence of strip malls.

7 Reader Comments

  1. Hey Jeremy, thanks for the article(s). While there’s undoubtedly some very interesting content and good practices, I don’t totally agree with you when you state that one needs to avoid image sprites, css/js concat and uglification.

    Though these optimisations specifically tailor HTTP 1.1, it doesn’t mean they are never suited for HTTP2.

    Despite H2’s ability to do multiplexing, many small files don’t gain as much from compression as one big files.

    Moreover, for many small files, you have to consider the http header overhead (that may represent a significant part of the total HTTP request size on tiny files).

    That’s why sometimes it’s still smart to serve some assets as sprite, or concatenated files rather that an endless list of a few kb each.

    Go the smart route and never forget to test!

    Here’s a nice study about H2 performance with sprite assets

  2. I think what you’re saying has merit, but you have to remember the reason why we want to unwind those H1 optimizations for H2: Caching. If any part of a bundled asset (be it CSS, JS or an image sprite) is changed, the entire bundle is invalidated and has to be downloaded again, even the parts that didn’t change.

    We unwind these H1 optimizations in H2 environments because connections are cheap. In fact, they’re not even connections anymore. They’re multiplexed streams encapsulated by one TCP connection.

    Now to the merit of what you’re saying: Yes, compression is a factor in this case. But you also need to gauge your audience. How many of them are return visitors? First impressions are certainly important, but if you have a high portion of your audience that is returning (and you’re deploying new code/assets frequently!) caching effectiveness is important, too.

    I think the only sensible answer to this what you said: “Go the smart route and never forget to test!” I would amend it to say, “Go the smart route, find out who your audience is and how they behave, and never forget to test!” In this ever-changing field of web performance, there are often multiple “correct” answers.

    Thanks for reading and offering your input. 🙂 I appreciate it!

  3. Hi Jeremy. Thanks for the article!

    Reading the article and the comments, I’m not entirely clear what will be the “correct” way to use http/2 protocol, like using sprites or not.

    What is the most “correct” option?
    And how much time do you think it can take to improve 78% of browser compatibility?

  4. Hi, Zapya. Thanks for reading!

    What I meant by that is that when a browser that can’t understand HTTP/2 talks to an HTTP/2 server, that server will downgrade to HTTP/1 rather than reject the connection. Sorry for the awkward phrasing. 🙂

  5. Hi, Blog.

    The “correct” way of using HTTP/2 isn’t a clear-cut thing. As another commenter pointed out, smaller assets may not compress as well as larger ones, so sprites and other bundled assets could benefit more from compression.

    I think you have to weigh the caching benefits of smaller and more numerous assets over the potential benefits that bundling could provide. You might want to look at your visitor analytics and see how many visitors are returning. If you have a high return rate, those users will benefit from smaller assets if they change, since they won’t be forced to re-downloaded an entire bundled asset. On the other hand, if many of your visitors don’t return, you may want to adhere to bundling since those may compress better.

    The hard reality is that it just takes some time to figure out what works best. I wish the answer was simpler. As far as how long it will take for more browsers to support HTTP/2, right now we’re hovering on the edge of 80% (, but that includes a slice of browsers that indicate “partial support” for HTTP/2, so the real number could be less. As long as Opera Mini doesn’t support HTTP/2 (which sees higher usage in developing nations), it could take some time to get to 90% or better, but things are slowly improving all the time.

    Thanks for reading. 🙂

  6. Hi,

    @Buzut1, when you say:

    > Moreover, for many small files, you have to consider the http header overhead (that may represent a significant part of the total HTTP request size on tiny files).

    Please note that HTTP Headers have a very less significant impact in HTTP2 than in HTTP1 (for both requests & responses)

    In HTTP2, standard HTTP headers are coded in binary, and the whole header sections are compressed using maps shared between the client & the server:

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA