How Would You Enhance HTML Tags For Performance?

A little while ago Jason Grigsby wrote a great post outlining his “wish list” for how the <img> tag should change to simplify mobile design (and specifically Responsive Images). The post created a lot of good conversation, and hopefully some standards activity too. At the end of the day, browser makers and developers share a common goal of making the web better, so this type of feedback helps.

Ever since I read that post I’ve been thinking about my own wish list, focused on performance this time. How would I change HTML to make performance optimization easier? As it turns out, my wish list was pretty long… Below are three of my top items – add yours in the comments below!

<img> tag: Responsive & On-Demand Images Support

Two key optimizations for images are Responsive Images (loading a small image for a smaller screen) and Images On-Demand (“lazy loading” images, requesting them only if they’re in the visibile area). Grigs already covered Responsive Images well, so I’ll focus on the latter.

I’d like the <img> tag to allow an optional “lazyload” attribute. If present and set to true, the browser will only request the image if it’s in the visible area, whether it’s “above the fold” or the user scrolled or resized the window and it came into view.

The default behaviour should be “false” (load images immediately), for backward compatibility, but the <body> tag should be able to override that default. If it holds a lazyload-images=”true” attribute, images on the page would be lazy-loaded by default, and the website would have to explicitly exclude beacons or other “special” images.

<script> tag: Grouped async

The latest versions of all major browsers support the “async” attribute, which means a script won’t block the download or execution of other resources. Once marked async, these scripts are also independent of each other, and may get executed in any order, to keep one async script from delaying another.

The challenge is when scripts are related to each other. It’s very common to have an inline script set an analytics account ID, and then load the full analytics script, or to load jQuery and then use it to load a piece of the page. There’s no easy way to create a group of scripts, and make them async as a group.

I would love to see an “async-groups” attribute, which includes one or more groups this script belongs to. These scripts would be async, but within a group scripts will always be executed in the order they appear in the DOM. One script could belong to multiple groups, and the order within each group would be maintained regardless. Note that this does not mean one group delays another.

Consider the following HTML fragment:

<script src=”critical-1.js”></script>
<script src=”jquery.js” async-groups=”social,analytics”></script>
<script src=”social.js” async-groups=”social”></script>
<script async-groups=”analytics”>var analyticsAcct=12345;</script>
<script src=”analytics.js” async-groups=”analytics”></script>
<script src=”critical-2.js”></script>

Let’s take it apart:

  1. critical-1.js and critical-2.js will be downloaded and evaluated inline, blocking other files
  2. jquery.js and social.js make up the “social” group, will not block the rest of the page, but jquery.js will always be executed before social.js
  3. jquery.js, the inline script and analytics.js make up the “analytics” group, will not block the rest of the page, but will run in the order they appear.
  4. jquery.js belongs to two groups, and so will block execution of subsequent scripts in each group, but won’t block critical-2.js or the rest of the page.
  5. The scripts do not have the “async” attribute, for backward compatibility.
    Older browsers will run them inline, preserving execution order (though not as performant). Newer browsers will set an implied “async” attribute on scripts with an “async-groups” attribute.

There are probably various ways grouped async can be implemented – this is just one suggested implementation. As long as the end goal of having a group of scripts run in order but asynchronously is met, I’ll probably be happy with it.

<link> tag: Defer & Async CSS

CSS link tags block a lot on the page. They block rendering, block most subsequent resources, and are always processed one after the other. This behaviour is designed to avoid FOUC (Flash of Unstyled Content), but it doesn’t contemplate the case of a less important (or less urgent) CSS file.

The best example of a less urgent CSS is a print stylesheet. If a page links to a CSS with a media=”print” attribute, chances are the rules in this file only matter when the page is printed. The browser, however, has to process this CSS like all others, since the CSS file may set rules for other media types. As a result, the file delays page load for no good reason.

It would be great if the “async” attribute was supported for CSS <link> tags. The behaviour could match the <script> tag’s async and defer attributes, downloading the CSS and applying its rules asynchronously if async is set, or after doc complete if defer is used instead. The other advantage is that backward compatibility is implicitly achieved, as older browsers would simply keep processing this file inline.

What else?

These are but three of the changes I’d like to see, but they can each have a substantial impact on load time. They revolve around empowering developers, letting them guide the browser on how to load their page.

What’s your wish list? What would you like to see browsers add to make performance optimization easier?

Posted on December 21st, 2011
  • http://www.facebook.com/jamesgpearce James Pearce

    Interesting question in general.

    But there’s also a philosophical debate about how far something that what was originally designed as a document structure can be taken to create functionality-rich applications.

    (i.e. at some point there are only so many attributes you can add to a declarative syntax before you’d be better off using imperative approach in the first place).

    So +1 to giving, say, JavaScript more control over its own modular loading behavior. Not sure whether HTML scales to be ultimately the right API for this sort of granularity though.

    • Anonymous

      I like the radical thinking, but my bet is HTML is the platform to build on for quite a while. Do you have a specific idea in mind about what would you use instead of HTML? Maybe a layer between HTML and JavaScript?

      So far, all the attempts to replace HTML have failed. Flash got close, but now it seems clear it’s days are limited. The only path that succeeded was HTML5, which extended HTML while maintaining background compatibility. I was trying to maintain that spirit with these changes, repeating what worked before.

      HTML keeps simple things simple, even if it makes complicated things hard/impossible, and for most websites that’s more important than having the stronger capabilities. Maybe most websites just need a document structure first and foremost, so we need to work with that foundation.

  • http://getify.me/ Kyle Simpson

    The way to get a group of scripts to run in order, but asynchronously, is by doing document.createElement(“script”); dynamic script insertion, but setting the `async` property to `false` on all of them.

    See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=11295

    In fact, this is exactly how script loaders (like my LABjs) operate.

    I know the spirit of your request is to have an HTML tag/attribute for controlling that behavior, but I don’t think that’s the right way to go about it. Your exact suggestion has actually already been discussed at length on the WHATWG/W3C lists with regards to dynamic script loading, and it was tossed out as too complex/messy for a markup solution. The prevailing opinion was that this type of behavior didn’t belong in markup (it’s too “code-like”), but in code.

    However, the leading candidate for a markup based solution to “groups” of async scripts was something like this:

    <scriptgroup><script src=”…” async></script><script src=”…” async></script>
    </scriptgroup>

    I don’t think that would have been a terrible solution, but I don’t think it offers much value, either (because it’s far less capable than what dynamic script loaders can provide). I think advanced script loading should be handled in code by smart script loaders.

    ———-

    BTW, what we really need for script loading is “true preloading”. I’ve been fighting WHATWG for over a year on that, as have several others (like Nicholas Zakas, etc).

    See: http://wiki.whatwg.org/wiki/Script_Execution_Control

    • Anonymous

      Thanks for the link, there’s some great information there. I actually read it in the past, but couldn’t find it when writing this post… My google skills must be rusty. 

      I know script loaders like LABjs find ways around this problem, we do the same in the Blaze code, but I just hope it’ll be made simpler. I actually don’t mean to cling to HTML changes, but I do think the end goal is to have a simple way to describe your needs. So I don’t mind a solution that isn’t an HTML tag, I just believe it’s a better one.

      Correct me if I’m wrong on any of these, but I see the following advantages of the markup based approach (my suggestion above or the scriptgroup element) over the dynamic script creation:
      1) Browsers won’t see the scripts before the code is executed, meaning they won’t be able to do DNS resolution, open connections or even fetch the files ahead of time. 
      2) Backward compatibility is cleaner. Older browsers would just run the scripts inline (and in order), without the need for elaborate alternatives like what LABjs (and Blaze) do. Slower for those older browsers, but simpler.
      3) Better granularity. Websites can have a lot of pieces in them, so grouping is needed to make one piece not delay another (e.g. is it ok that the Facebook “like” button will delay the twitter feed, even if they both don’t delay the page?).
      4) IMO it’s simpler – less to write and more declarative (“these scripts need to run in order”). 

      I stil see room for script loaders to leverage the markup language and support more elaborate cases, but I don’t think they’re quite simple enough in the long haul.