Improving Smashing Magazine’s Performance: A Case Study
- By Vitaly Friedman
- September 8th, 2014
- 20 Comments
<!–
Advertisement
–>
Today Smashing Magazine turns 8 years old. Eight years is a prolonged time on a web, nonetheless for us it unequivocally doesn’t feel like a prolonged tour during all. Things have changed, developed and altered on, and we gratefully take on new hurdles one during a time. To symbol this special tiny day, we’d adore to share a few things that we’ve schooled over a final year about a performance challenges of this unequivocally website and about a work we’ve finished recently. If we wish to qualification a discerning manageable website, we competence find a few engaging nuggets value considering. – Ed.
Improvement is a matter of steady, ongoing iteration. When we redesigned Smashing Magazine behind in 2012, a categorical suspicion was to settle infallible branding that would simulate a desirous editorial instruction of a magazine. We did that essentially by focusing on crafting a pleasant reading experience. Over a years, a concentration hasn’t altered a bit; however, that unequivocally item that helped to settle a branding incited into a vital performance bottleneck.
Good Old-Fashioned Website Decay
Looking behind during a early days of a redesign, some of a decisions seem to be quick’n’dirty fixes rather than sound long-term solutions. Our promotion constraints pushed us to compromises. Legacy browsers gathering us to dependencies on (relatively) complicated JavaScript libraries. Our technical infrastructure led us to heavily customized WordPress plugins and formidable PHP logic. With any new underline added, a technical debt grew, and a character sheets, markup and JavaScript weren’t stealing any leaner.
Sound familiar? Admittedly, manageable web pattern as a technique mostly gets a pretty bad rap for bloating websites and creation them formidable to maintain. (Not that non-responsive websites are any different, nonetheless that’s another story.) In practice, all resources on a manageable website will uncover adult flattering many everywhere1: be it a delayed smartphone, a quirky inscription or a imagination laptop with a Retina screen. And given media queries merely yield a ability to respond to shade magnitude — and do not, rather, have a some-more local, self-contained range — adding a new underline and adjusting a reading knowledge potentially means going by any and any media query to forestall inconsistencies and repair blueprint issues.
“Mobile First” Means “Always Mobile First”
When it comes to sourroundings priorities for a calm and functionality on a website, “mobile first” is one of those formidable nonetheless impossibly absolute constraints that assistance we concentration on what unequivocally matters, and formula vicious components of your website. We detected that conceptualizing mobile initial is one thing; building mobile initial is an wholly opposite story. In a case, both a pattern and growth phases were heavily mobile first, that helped us to concentration firmly on a calm and a presentation. But while a pattern routine was utterly straightforward, doing valid to be utterly difficult.
Because a whole website was built mobile first, we discerning satisfied that adding or changing components on a page would entail going by a mobile-first proceed for any singular (minor and major) pattern decision. We’d pattern a new member in a mobile viewpoint first, and thereafter pattern an “extended” viewpoint for a situations when some-more space is available. Often that meant adjusting media queries with any singular change, and some-more mostly it meant adding new things to character sheets and to a markup to residence new issues that came up.
2
Shortly after a new SmashingMag redesign went live, we ran into opening issues. An essay by Tim Kadlec from 20123 shows customarily that.
We found ourselves trapped: growth and upkeep were holding a lot of time, a formula bottom was full of teenager and vital fixes, and a infrastructure was apropos too slow. We finished adult with a formula bottom that had spin magisterial before a redesign was even expelled — very bloated4, in fact.
Performance Issues
In mid-2013, a home page weighed 1.4 MB and assembled 90 HTTP requests. It customarily wasn’t behaving well. We wanted to emanate a conspicuous reading knowledge on a website while avoiding a flash of unstyled text (FOUT), so web fonts were installed in a header and, hence, were restraint a digest of calm (actually it’s scold poise according to a spec5, designed to equivocate mixed repaints and reflows.) jQuery was compulsory for ads to be displayed, and a few JavaScripts depended on jQuery, so they all were restraint digest as well. Ads were installed and rendered before a calm to safeguard that they seemed as discerning as possible.
Images delivered by a ad partners were customarily complicated and unoptimized, negligence down a page further. We also installed Respond.js and Modernizr to bargain with bequest browsers and to raise a knowledge for intelligent browsers. As a result, articles were roughly untouched on delayed and inconstant networks, and a start digest time on mobile was unsatisfactory during best.
It wasn’t customarily a front-end that was arrangement a age though. The back-end wasn’t stealing any improved either. In 2012 we were personification with a suspicion of carrying wholly eccentric sections of a repository — sections that would live their possess lives, elaborating and flourishing over time as eccentric WordPress installations, with tradition facilities and calm forms that wouldn’t indispensably be common opposite all sections.
6
Yes, we do suffer a utterly savvy user base, so optimization for IE8 is unequivocally not an issue. Large view.7
Because WordPress multi-install wasn’t permitted during a time, we finished adult with 6 independent, unconstrained WordPress installs with 6 independent, unconstrained character sheets. Those installs were connected to 6 × 2 databases (a media server and a immobile calm server). We ran into dilemmas. For example, what if an author wrote for dual sections and we’d adore to uncover their articles from both sections on one singular author’s bio page? Well, we’d need to somehow lift articles from both installs and supplement redirects for any author’s page to that one one page, or should we customarily be regulating one of those page as a “host”? Well, we know where this is going: augmenting complexity and augmenting upkeep costs. In a end, a sections didn’t conduct to develop significantly — during slightest not in terms of calm — nonetheless we had already customized technical substructure of any section, adding to a CSS dirt and PHP complexity.
(Because we had outsourced WordPress tasks, some plugins depended on any other. So, if we were to deactivate one, we competence have unwittingly infirm dual or 3 others in a process, and they would have to be incited behind on in a sold sequence to work properly. There were even differences in a HTML outputted by a PHP templates behind a curtains, such as classes and IDs that differed from one designation to a next. It’s no warn that this setup finished growth a bit frustrating.)
The trade was stagnant, readers kept angry about a opening on a site and customarily a unequivocally tiny apportionment of users visited some-more than 2 pages per visit. The manifest feedback when browsing a site was visible and certainly wasn’t instant, and this loiter has been pulling readers divided from a site to Instapaper and Pocket — both on mobile and desktop. We knew that given we asked a readers, and a feedback was utterly transparent (and a bit frustrating).
It was time to lift behind — heavily, with a major refactoring of a formula base. We looked closely underneath a hood, anticipating a few flattering frightful (and nasty) things, and started regulating issues, one by one. It took us utterly a bit of time to make things right, and we schooled utterly a few things along a way.
Switching Gears
Up until mid-2013, we weren’t regulating a CSS preprocessor, nor any build tools. Good long-term solutions need a good long-term foundation, so a initial issues we tackled were production and a proceed a formula bottom was organized. Because a series of people had been operative on a formula bottom over a years, some things valid to be rather mysterious… or challenging, to contend a least.
We started with a code inventory, and we looked wholly during any singular class, ID and CSS selector. Of course, we wanted to build a complement of modular components, so a initial charge was to spin a 7 vast CSS files into maintainable, well-documented and easy-to-read modules. At a time, we’d selected LESS, for no sold reason, and so a front-end operative Marco8 started to rewrite CSS and build a modular, scalable architecture. Of course, we could unequivocally good have used Sass instead, nonetheless Marco felt utterly gentle with LESS during a time.
With a new CSS architecture, Grunt9 as a build apparatus and a few10time-saving11Grunt12tasks13, a charge of progressing a whole formula bottom became many easier. We set adult a formula new contrast environment, synced adult all with GitHub, reserved roles and permissions, and started digging. We rewrote selectors, reauthored markup, and refactored and optimized JavaScript. And yes, it took us utterly some time to get things in order, nonetheless it unequivocally wouldn’t have been so formidable if we hadn’t had a series of unequivocally opposite stylesheets to bargain with.
The Big Back-End Cleanup
With a introduction of Multisite, formulating a singular WordPress designation from a 6 apart installations became a compulsory charge for a friends during Inpsyde14. Over a march of 5 months, Christian Brückner and Thomas Herzog spotless adult a PHP templates, kicked nonessential plugins into orbit, rewrote plugins we had to keep and combined new ones where needed. They privileged a databases of all a confusion that a aged plugins had combined — one of a databases weighed in during 70 GB (no, that’s not a typo; we do meant gigabytes) — joined all of a databases into one, and thereafter combined a singular uninformed and, many importantly, maintainable WordPress Multisite installation.
The speed boost from those optimizations was remarkable. We are articulate about 400 to 500 milliseconds of improvement by avoiding sub-domain redirects and unifying a formula bottom and a back-end code. Those redirects15 are indeed a vital opening culprit, and customarily avoiding them is one of those techniques that customarily boost opening significantly given we equivocate full DNS lookups, urge time to initial byte and revoke turn trips on a network.
Thomas and Christian also refactored a whole WordPress thesis according to a coding customary of their possess thesis architecture, that is fundamentally a worldly proceed of essay PHP formed on a WordPress standard. They wrote tradition drop-ins that we use to arrangement calm during certain points in a layout. Writing a PHP utterly according to WordPress’ central API felt like stealing out of a horse-drawn carriage and into a competition car. All modifications were finished nonetheless ever touching WordPress’ core, that is outstanding given we’ll never have to fear updating WordPress itself anymore.

We’ve also noted a few millions spam comments opposite all a sections of a magazine. And before we ask: no, we did not import them into a new install.
We migrated a installations during a delayed weekend in mid-April 2014. It was a outrageous undertaking, and a server had a few hiccups during a process. We brought together over 2500 articles, including about 15,000 images, all widespread over 6 databases, that also had a few vital inconsistencies. While it was a unequivocally severe start during initial — a lot of redirects had to be set up, caching issues on a server piled up, and some articles got mislaid between a aged and new installations — a outcome was good value a effort.
Our editorial team, essentially Iris16, Melanie17 and Markus18, worked unequivocally tough to bring those mislaid articles behind to life by examining a 404s with Google Webmaster Tools. We spent a few weekends to safeguard that any singular essay was recovered and stays accessible. Losing articles, including their comments, was simply unacceptable.
We know good how many time it takes for a good essay to get published, and we have a lot of honour for authors and their work, and ensuring that a calm stays online was a matter of honour for a work published. It took us a few weeks to get there and it wasn’t a many beguiling knowledge for sure, nonetheless we used a eventuality to broach some-more coherence in a information design and to adjust tags and categories appropriately. (Ah, if we do occur to find an essay that has gotten mislaid along a way, greatfully do let us know19 and we’ll repair it right away. Thanks!)
Front-End Optimization
In Apr 2014, once a new complement was in place and had been regulating uniformly for a few days, we rewrote a LESS files formed on what was left of all of a installs. Streamlining a classes for posts and pages, stealing absolved of all unneeded IDs, cutting selectors by obscure their specificity, and rooting out anything in a CSS we could live nonetheless crunched a CSS from 91 KB down to a small 45 KB.
Once a CSS formula bottom was in correct shape, it was time to recur how resources are installed on a page and how we can urge a start digest time over carrying clean, well-structured formula base. Given a calamity we gifted with a back-end previously, we competence assume that improving opening now would have been a complex, time-consuming task, nonetheless indeed it was utterly a bit easier than that. Basically, it was customarily a matter of getting a priorities right by optimizing a vicious digest path.
The pivotal to improving opening was to concentration on what matters most: a content, and a fastest proceed for readers to indeed start reading a articles on their devices. So over a march of a few months we kept reprioritizing. With any update, we introduced mini-optimizations formed on a unequivocally simple, roughly apparent principle: optimize a smoothness of content, and defer a rest — nonetheless any compromises, anywhere.
Our optimizations were heavily shabby by a work finished by Scott Jehl20, as good as The Guardian21 and a BBC22 teams (both of that open-sourced their work). While Scott has been pity profitable insight23 into a front-end techniques that Filament Group was using, a BBC and The Guardian helped us to conclude and labour a judgment of a core experience on a website and use it as a baseline. A common categorical suspicion was to broach a calm as discerning as probable to as many people as probable regardless of their device or network capabilities, and raise a knowledge with on-going encouragement for means browsers.
However, historically we haven’t had a lot of JavaScript or formidable interactions on Smashing Magazine, so we didn’t feel that it was compulsory to broach formidable loading proof with JavaScript preloaders. However, being a content-focused website, we did wish to revoke a time compulsory for a articles to start displaying as distant as humanly possible.
Performance Budget: Speed Index = 1000
How discerning is discerning enough?24 Well, that’s a tough doubt to answer. In general, it’s utterly formidable to daydream opening and explain given any millisecond counts—unless we have tough data. At a same time, descending into trap of absolutes and relying on not truly useful opening metrics is easy. In a past, a many ordinarily cited opening metric was normal loading time. However, on a own, normal loading time isn’t that useful given it doesn’t tell we many about when a user can indeed start regulating a website. This is given articulate about “fast enough” is mostly so tricky.
25
A good proceed of visualizing opening is to use WebPageTest to beget an discernible video of a page loading and run a exam between dual competing websites. Besides, a Speed Index metric26 mostly proves to be unequivocally useful.
Different components need opposite amounts of time to load, nonetheless some components of a page are some-more vicious than others. E.g. we don’t need to bucket a footer content fast, nonetheless it’s a good suspicion to describe a manifest apportionment of a page fast. You know where it’s heading: of course, we are articulate about a “above a fold” viewpoint here. As Ilya Grigorik once said27, “We don’t need to describe a whole page in one second, [just] a above a overlay content.” To grasp that, according to Scott’s investigate and Google’s exam results, it’s useful to set desirous opening goals:
- On WebPageTest6428, aim for a Speed Index29 value of underneath 1000.
- Ensure that all HTML, CSS and JavaScript fit within a initial 14 KB.
What does it meant and given are they important? According to HCI research, “for an focus to feel instant, a obvious response to user submit contingency be supposing within hundreds of milliseconds30. After a second or more, a user’s upsurge and rendezvous with a instituted charge feels broken.” With a initial goal, we are perplexing to safeguard an present response on a website. It refers to a ostensible Speed Index metric for a start rendering time — the normal time (in ms) during that manifest tools of a page are displayed, or spin accessible. So a initial suspicion fundamentally reflects that a page starts rendering underneath 1000ms, and yes, it’s a utterly formidable plea to take on.
31
Ilya Grigorik’s book High Performance Browser Networking32 is a unequivocally useful beam with useful discipline and recommendation on creation websites fast. And it’s permitted as a giveaway HTML book, too.
The second suspicion can assistance in achieving a initial one. The value of 14 KB has been totalled empirically33 by Google and is a threshold for a initial package exchanged between a server and customer around towers on a mobile connection. You don’t need to embody images within 14 Kb, nonetheless we competence wish to broach a markup, character sheets and any JavaScript compulsory to describe a manifest apportionment of a page in that threshold. Of course, in use this value can customarily practically be achieved with gzip compression.
By mixing a dual goals, we fundamentally discernible a performance budget that we set for a website — a threshold for what was acceptable. Admittedly, we didn’t regard ourselves with a start digest time on opposite inclination on several networks, especially given we unequivocally wanted to lift behind as distant as probable all that isn’t compulsory to start digest a page. So, a ideal outcome would be a Speed Index value that is way revoke than a one we had set — as low as possible, indeed — in all settings and on all connections, both unsure and stable, delayed and fast. This competence sound naive, nonetheless we wanted to figure out how discerning we could be, rather than how discerning we should be. We did magnitude start digest time for initial and successive page loads, nonetheless we did that many later, after optimizations had already been done, and customarily to keep lane of issues on a front-end.
Our successive step would be to confederate Tim Kadlec’s Perf-Budget Grunt task34 to incorporate a opening bill right into a build routine and, thus, run any new dedicate opposite WebPagetest’s opening benchmark. If it fails, we know that a new underline has slowed us down, so we substantially have to recur how it’s implemented to fit it within a budget, or during slightest we know where we mount and can have suggestive discussions about a impact on a altogether performance.
Prioritization And Separation Of Concerns
If you’ve been following The Guardian‘s work recently, we competence be informed with a despotic subdivision of concerns that they introduced35 during a vital 2013 redesign. The Guardian separated36 a whole calm into 3 categorical groups:
- Core content
Essential HTML and CSS, serviceable non-JavaScript-enhanced experience - Enhancement
JavaScript, geolocation, hold support, extended CSS, web fonts, images, widgets - Leftovers
Analytics, advertising, third-party content
37
A despotic subdivision of concerns, or loading priorities, as discernible by The Guardian team. Large view.38
Once we have defined, arguable and concluded on these priorities, we can lift opening optimization utterly far. Just by being unequivocally specific about any form of calm we have and by clearly defining what “core content” is, we are means to bucket Core content as discerning as possible, thereafter bucket Enhancements once a page starts digest (after a DOMContentLoaded eventuality fires), and thereafter bucket Leftovers once a page has wholly rendered (after a load eventuality fires).
The categorical component here of march is to strictly apart a loading of assets around these 3 phases, so that a loading of a Core content should never be blocked by any resources grouped in Enhancement or Leftovers (we haven’t achieved a ideal subdivision customarily yet, nonetheless we are on it). In other words, we try to digest a vicious digest trail that is compulsory for a calm to start displaying by pulling a calm down a line as discerning as probable and deferring flattering many all else.
We followed this same subdivision of concerns, organisation a calm forms into a same categories and identifying what’s critical, what’s vicious and what’s secondary. In a case, we identified and distant calm in this way:
- Core content
Only essential HTML and CSS - Enhancement
JavaScript, formula syntax highlighter, full CSS, web fonts, criticism ratings - Leftovers
Analytics, advertising, Gravatars
Once we have this elementary content/functionality priority list, improving opening is apropos customarily a matter of adding a few snippets for loading resources to scrupulously simulate those priorities. Even if your server proof army we to bucket all resources on all devices, by focusing on calm smoothness first, we safeguard that a calm is permitted quickly, while all else is deferred and installed in a background, after a page has started rendering. From a vital perspective, a list also reflects your technical debt, as good as vicious issues that delayed we down. Indeed, we had utterly a list of issues to bargain with already during this point, so it remade sincerely discerning into a list of calm priorities. And a rather wily emanate sat right during a tip of that list: good ol’ web fonts.
Deferring Web Fonts
Despite a fact that a suit of Smashing Magazine’s readers on mobile has always been utterly medium (just around 15%—mainly due to a length of articles), we never deliberate mobile as an afterthought, nonetheless we never pushed user knowledge on mobile either. And when we speak about user knowledge on mobile, we mostly speak about speed, given typography was flattering many good designed from day one.
We had conversations during a 2012 redesign about how to bargain with fonts, nonetheless we couldn’t find a resolution that finished everybody happy. The manifest coming of calm was important, and given a new Smashing Magazine was all about beautiful, abounding typography, not loading web fonts during all on mobile wasn’t unequivocally an option.
With a redesign behind then, we switched to Skolar for headings and Proxima Nova for physique copy, delivered by Fontdeck. Overall, we had 3 fonts for any typeface — Regular, Italic and Bold — totalling in 6 rise files to be delivered over a network. Even after a dear friends during Fontdeck subsetted and optimized a fonts, a resources were utterly complicated with over 300 KB in total, and given we wanted to equivocate a revisit peep of unstyled calm (FOUT), we had them installed in a header of any page. Initially we suspicion that a fonts would reliably be cached in HTTP cache, so they wouldn’t be retrieved with any singular page load. Yet it incited out that HTTP cache was utterly unreliable: a fonts showed adult in a rapids loading draft any now and again for no apparent reason, both on desktop and on mobile.
The biggest problem, of course, was that a fonts were restraint rendering39. Even if a HTML, CSS and JavaScript had already installed completely, a calm wouldn’t seem until a fonts had installed and rendered. So we had this pleasing knowledge of saying couple underlines first, thereafter a few keywords in confidant here and there, thereafter subheadings in a center of a page and thereafter finally a rest of a page. In some cases, when Fontdeck had server issues, a calm didn’t seem during all, even nonetheless it was already sitting in a DOM, watchful to be displayed.
40
In his article, Web Fonts and a Critical Path41, Ian Feather provides a unequivocally minute overview of a FOUT issues and rise loading solutions. We tested them all.
We experimented with a few solutions before settling on what incited out to be maybe a many formidable one. At first, we looked into regulating Typekit and Google’s WebFontLoader42, an asynchronous book that gives we some-more granular control of what appears on a page while a fonts are being loaded. Basically, a book adds a few classes to a body element, that allows we to discuss a styling of calm in CSS during a loading and after a fonts have loaded. So we can be unequivocally accurate about how a calm is displayed in fallback fonts first, before users see a switch from fallback fonts to web fonts.
We combined fallback fonts declarations and finished adult with flattering prolix CSS rise stacks, regulating iOS fonts, Android fonts, Windows Phone fonts and good ol’ web-safe fonts as fallbacks — we are still regulating these rise stacks today. E.g. we used this cascade for a categorical headings (it reflects a sequence of recognition of mobile handling systems in a analytics):
h2
font-family: "Skolar Bold",
AvenirNext-Bold, "Avenir Bold",
"Roboto Slab", "Droid Serif",
"Segoe UI Bold",
Georgia, "Times New Roman", Times, serif;
So readers would see a mobile OS rise (or any other fallback rise first), and it substantially would be a rise that they are utterly informed with on their device, and thereafter once a fonts have loaded, they would see a switch, triggered by WebFontLoader. However, we detected that after switching to WebFontLoader, we started saying FOUT proceed too often, with HTTP cache being utterly dangerous again, and that permanent switch from a fallback rise to a web rise being utterly annoying, fundamentally ruining a reading experience.
So we looked for alternatives. One resolution was to include a @font-face gauge customarily on incomparable screens by jacket it in a media query, so avoiding loading web fonts on mobile inclination and in bequest browsers altogether. (In fact, if we announce web fonts in a media query, they will be installed customarily when a media query matches a shade size. So no opening strike there.) Obviously it helped us urge opening on mobile inclination in no time, nonetheless we didn’t feel right with carrying a “simplified” reading knowledge on mobile devices. So it was a no-go, too.
What else could we do? The customarily other choice was to improve a caching of fonts. We couldn’t do many with HTTP cache, nonetheless there was one choice we hadn’t looked into: storing fonts in AppCache or localStorage. Jake Archibald’s essay on a pleasing complexity of AppCache43 led us divided from AppCache to examination with localStorage, a technique44 that The Guardian’s group was regulating during a time.
Now, offline caching comes with one one vital requirement: we need to have a discernible rise files to be means to cache them locally in a client’s browser. And we can’t cache a lot given localStorage space is unequivocally limited45, infrequently with customarily 5Mb permitted per domain. Luckily, a Fontdeck guys were unequivocally useful and stirring with a undertaking, so notwithstanding a fact that rise smoothness services customarily need we to bucket files and have a synchronous or asynchronous callback to count a series of impressions, Fontdeck has been ideally excellent with us grabbing WOFF-files from Google Chrome’s cache and sourroundings adult a “flat” pricing formed on a series of page impressions in new history.
So we grabbed a WOFF files and embedded them, base64-encoded, in a singular CSS file, relocating from 6 outmost HTTP-requests with about 50 KB record any to during many one HTTP ask on a initial bucket and 400 KB of CSS. Obviously, we didn’t wish this record to be installed on any visit. So if localStorage is permitted on a user’s machine, we store a whole CSS record in localStorage, set a cookie and switch from a fallback rise to a web font. This switch customarily happens once during many given for a accompanying visits, we check possibly a cookie has been set and, if so, collect a fonts from localStorage (causing about 50ms in latency) and arrangement a calm in a web rise right away. Just before we ask: yes, read/write to localStorage is many slower than retrieving files from HTTP cache46, nonetheless it valid to be a bit some-more arguable in a case.
47
Yes, localStorage is many slower than HTTP cache48, nonetheless it’s some-more reliable. Storing fonts in localStorage isn’t a ideal solution, nonetheless it helped us urge opening dramatically.
If a browser doesn’t support localStorage, we embody fonts with good ol’ link href and, well, honestly customarily wish for a best — that a fonts will be scrupulously cached and insist in a user’s browser cache. For browsers that don’t support WOFF49 (IE8, Opera Mini, Android = 4.3), we yield outmost URLs to fonts with comparison rise mime types, hosted on Fontdeck.
Now, if localStorage is available, we still don’t wish it to be restraint a digest of a content. And we don’t wish to see FOUT any singular time a user loads a page. That’s given we have a tiny JavaScript dash in a header before a body element: it checks possibly a cookie has been set and, if not, we bucket web fonts asynchronously after a page has started rendering. Of course, we could have avoided a switch by customarily storing a fonts in localStorage on a initial revisit and have no switch during a initial visit, nonetheless we motionless that one switch is acceptable, given a typography is vicious to a identity.
The book was written, tested and documented by a good crony Horia Dragomir50. Of course, it’s permitted as a crux on GitHub51:
script type="text/javascript"
(function ()
"use strict";
// once cached, a css record is stored on a customer perpetually unless
// a URL subsequent is changed. Any change will nullify a cache
var css_href = './web-fonts.css';
// a elementary eventuality handler wrapper
duty on(el, ev, callback)
if (el.addEventListener)
el.addEventListener(ev, callback, false);
else if (el.attachEvent)
el.attachEvent("on" + ev, callback);
// if we have a fonts in localStorage or if we've cached them regulating a local browser cache
if ((window.localStorage localStorage.font_css_cache) ());
/scriptDuring a contrast of a technique, we detected a few startling problems. Because a cache isn’t determined in WebViews, fonts do bucket asynchronously in applications such as Tweetdeck and Facebook, nonetheless they don’t sojourn in a cache once a window is closed. In other words, with any WebViews visit, a fonts are re-downloaded. Some aged Blackberry inclination seemed to transparent cookies and undo a cache when a battery is regulating out. And depending on a pattern of a device, infrequently fonts do not insist in mobile Safari either.
Still, once a dash was in place, articles started digest many faster. By deferring a loading of Web fonts and storing them in localStorage, we’ve avoided around 700ms delay, and so condensed a vicious trail significantly by avoiding a latency for retrieving all a fonts. The outcome was utterly considerable for a initial bucket of an uncached page, and it was even some-more considerable for indicate visits given we were means to revoke a latency caused by Web fonts to customarily 40 to 50 ms. In fact, if we had to discuss customarily one alleviation to opening on a website, deferring web fonts is by distant a many effective.
At this point, we haven’t even deliberate regulating a new WOFF2 format52 for fonts customarily yet. Currently upheld in Chrome and Opera, it promises a improved application for rise files and it already showed conspicuous results. In fact, The Guardian was means to cut down on 200ms latency and 50 KB of a record weight53 by switching to WOFF2, and we intend to demeanour into relocating to WOFF2 shortly as well.
Of course, grabbing WOFFs competence not always be an choice for you, nonetheless it wouldn’t harm customarily to speak to form foundries to see where we mount or to work out a bargain to horde fonts “locally.” Otherwise, tweaking WebFontLoader for Typekit and Fontdeck is unequivocally value considering.
Dealing With JavaScript
With a suspicion of stealing all nonessential resources from a vicious digest path, a second aim we motionless to bargain with was JavaScript. And it’s not like we utterly dislike JavaScript for some reason, nonetheless we always tend to cite non-JavaScript solutions to JavaScript ones. In fact, if we can equivocate JavaScript or reinstate it with CSS, thereafter we’ll always try that option.
Back in 2012, we weren’t regulating a lot of scripts on a page, nonetheless displaying promotion around OpenX depended on jQuery, that finished it proceed too easy to lazily proceed simple, candid tasks with ready-to-use jQuery plugins. At a time, we also used Respond.js to obey manageable poise in bequest browsers. However, Internet Explorer 8 use has forsaken significantly between 2012 and 2014: with 4.7% before a redesign, it was now 1.43%, with a dropping bent any singular month. So we motionless to broach a fixed-width blueprint with a specific IE8.css stylesheet to those users, and private Respond.js altogether.
As a vital decision, we motionless to defer a loading of all JavaScripts until a page has started rendering and we looked into replacing jQuery with lightweight modular JavaScript components.
jQuery was firmly firm to ads, and ads were ostensible to start displaying as discerning as possible, so to make it happen, we had to bargain with promotion first. The preference to defer a loading of ads wasn’t easy to get agreement on, nonetheless we managed to make a convincing evidence that improved opening would boost click rates given users would see a calm sooner. That is, on any page, readers would be captivated by a high-quality calm and then, when a ads flog in, would compensate courtesy to those squares in a sidebar as well.
Florian Sander54, a partner in crime when it comes to advertising, rewrote a book for a ensign ads so that banners would be installed customarily after a calm has started rendering, and customarily thereafter a promotion spots would be put into place. Florian was means to get absolved of dual render-blocking HTTP-requests that a ad-script routinely generated, and we were means to mislay a dependency on jQuery by rewriting a book in vanilla JavaScript.
Obviously, given a sidebar’s ad calm is generated on a fly and is installed after a describe tree has been constructed, we started saying reflows (this still happens when a page is being constructed). Because we used to bucket ads before a content, a whole page (with flattering many everything) used to bucket during once. Now, we’ve altered to a some-more modular structure, organisation together sold tools of a page and queuing them to bucket after any other. Obviously, this has finished a altogether knowledge on a site a bit noisier given there are a few jumps here and there, in a sidebar, in a comments and in a footer. That was a concede we went for, and we are operative on a resolution to haven space for “jumping” elements to equivocate reflows as a page is being loaded.
Deferring Non-Critical JavaScript
When a awaiting of stealing jQuery altogether became discernible as a long-term goal, we started operative step by step to decouple jQuery dependencies from a library. We rewrote a book to beget footnotes for a imitation character piece (later replacing it with a PHP solution), rewrote a functionality for rating comments, and rewrote a few other scripts. Actually, with a savvy user bottom and a plain share of intelligent browsers, we were means to pierce to vanilla JavaScript utterly quickly. Moreover, we could now pierce scripts from a header to a footer to equivocate restraint construction of a DOM tree. In mid-July, we private jQuery from a formula bottom entirely.
We wanted full control of what is installed on a page and when. Specifically, we wanted to safeguard that no JavaScript blocks a digest of calm during any point. So, we use a Defer Loading JavaScript55 book to bucket JavaScript after a load eventuality by injecting a JavaScript after a DOM and CSSOM have already been assembled and a page has been painted. Here’s a dash that we use on a website, with a defer.js book (which is installed asynchronously after a load event):
function downloadJSAtOnload()
var component = document.createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else
window.onload = downloadJSAtOnload;However, given script-injected asynchronous scripts are deliberate harmful56 and delayed (they retard a browser’s suppositional parser), we competence be looking into regulating a good ol’ defer and async attributes instead. In a past, we couldn’t use async for any book given we indispensable jQuery to bucket before a dependencies; so, we used defer, that respects a loading sequence of scripts. With jQuery out of a picture, we can now bucket scripts asynchronously, and fast. Actually by a time we examination this article, we competence already be regulating async.
Basically, we customarily deferred a loading of all JavaScripts that we identified previously, such as syntax highlighter and criticism ratings, and privileged a trail in a header for HTML and CSS.
Inlining Critical CSS
That wasn’t good enough, though. Performance did urge dramatically; however, even with all of these optimizations in place, we didn’t strike that enchanting Speed Index value of underneath 1000. In light of a ongoing contention about inline CSS and above-the-fold CSS, as endorsed by Google57, we looked into some-more radical ways to broach calm quickly. To equivocate an HTTP ask when loading CSS, we totalled how discerning a website would be if we were to bucket vicious CSS inline and thereafter bucket a rest of a CSS once a page has rendered.
58
Scott Jehl’s article59 explains how accurately to remove and inline vicious CSS.
But what accurately is vicious CSS? And how do we remove it from a potentially formidable formula base? As Scott Jehl points out60, vicious CSS is a subset of CSS that is indispensable to describe a tip apportionment of a page opposite all breakpoints. What does that mean? Well, we would confirm on a certain tallness that we would cruise to be “above a fold” calm — it could be 600, 800 or 1200 pixels or anything else — and we would collect into their possess character piece all of a styles that discuss how to describe calm within that tallness opposite all shade widths.
Then we inline those styles in a head, and so give a browser all it needs to start describe that manifest apportionment of a page — within one singular HTTP request. You’ve listened it a few times by now: all else is deferred after a initial initial rendering. You equivocate an HTTP-request, and we bucket a full CSS asynchronously, so once a user starts scrolling, a full CSS will (hopefully) already have loaded.
Visually speaking, calm will seem to describe some-more quickly, nonetheless there will also be more reflowing and jumping on a page. So, if a user has followed a couple to a sold criticism subsequent a “fold”, thereafter they will see a few reflows as a website is being assembled given a page is rendered with vicious CSS initial (there is customarily so many we can fit within 14 KB!) and practiced after with a finish CSS. Of course, inline CSS isn’t cached; so, if we have vicious CSS and bucket a finish CSS on rendering, it’s useful to set a cookie, so that inline styles aren’t inlined with any singular load. The obstacle of march is that we competence have transcribe CSS given we would be defining styles both inline and in a full CSS, unless you’re means to utterly apart them.
Because we had customarily refactored a CSS formula base, identifying vicious CSS wasn’t unequivocally difficult. Obviously, there are smart61tools62 that investigate a markup and CSS, formula vicious CSS styles and trade them into a apart record during a build process, nonetheless we were means to do it manually. Again, we have to keep in mind that 14 Kb is your bill for HTML and CSS, so in a finish we had to rename a few classes here and there, and restrict CSS as well.
We analyzed a initial 800px, checking a examiner for a CSS that was indispensable and separating a character piece into dual files – and indeed that was flattering many it. One of those files, above-the-fold.css, is minified and compressed, and a calm is placed inline in a conduct of a ask as early as probable – not restraint rendering. The other file, a full CSS file, is thereafter installed with JavaScript after a calm has loaded, and if JavaScript isn’t permitted for some reason or a user is on a bequest browser, we’ve put a full CSS record inside noscript tab during a finish of a head, so they don’t get an unstyled HTML page.
Was It All Worth It?
Because we’ve customarily implemented these optimizations, we haven’t been means to magnitude their impact on traffic, nonetheless we’ll tell these formula after as well. Obviously, we did notice a utterly conspicuous technical alleviation though. By deferring and caching web fonts, inlining CSS and optimizing a vicious digest trail for a initial 14Kb, we were means to grasp thespian improvements in loading times. The start digest time started encircling around 1s for an uncached page on 3G and was around 700ms (including latency!) on successive loads.
63
We’ve been regulating WebPageTest6428 a lot for regulating tests. Our rapids draft was apropos improved over time and reflected a priorities we had discernible earlier. Large view.65
On average, Smashing Magazine’s front page creates 45 HTTP-requests and has 440 KB in bandwidth on a initial uncached load. Because we heavily cache all nonetheless ads, successive visits have around 15 HTTP requests and 180 KB of traffic. The First Byte time is still around 300–600ms (which is a lot), nonetheless Start Render time is customarily underneath 0.7s66 on a DSL tie in Amsterdam (for a unequivocally first, uncached load), and customarily underneath 1.7s on a delayed 3G67. On a discerning wire connection, a site starts digest within 0.8s68, and on a discerning 3G, within 1.1s69. Obviously, a formula change significantly depending on a First Byte time that we can’t urge customarily yet, during a time of writing. That’s a customarily item that introduces unpredictability into a loading process, and as such has a wilful impact on a altogether performance.
Just by following simple discipline by a colleagues mentioned above and Google’s recommendations, we were means to grasp a 97–99 Google PageSpeed score70 both on desktop and on mobile. The measure varies depending on a peculiarity and a optimization turn of promotion resources displayed incidentally in a sidebar. Again, a categorical law-breaker is a server’s response time — not for long, though.
71
After a fewoptimizations, we achieved a Google PageSpeed measure of 99 on mobile72.
73
We got a Google PageSpeed measure of 99 on a desktop74 as well.
By a way, Scott Jehl has also published a outstanding essay on a front-end techniques75 FilamentGroup uses to remove vicious CSS and bucket it inline while loading a full CSS thereafter and equivocate downloading overheads. Patrick Hamann’s speak on “Breaking News during 1000ms”76 explains a few techniques that The Guardian is regulating to strike a SpeedIndex 1000 mark. Definitely value reading and watching, and indeed utterly identical to what we implemented on this unequivocally site as well.
Work To Be Done
While a formula we were means to grasp are utterly satisfactory, there is still a lot of work to be done. For example, we haven’t deliberate optimizing a smoothness of images customarily yet, and are now adjusting a editorial routine to confederate a new picture component and srcset/sizes with Picturefill 2.1.077, to make a loading even faster on mobile devices. At a moment, all images have a bound breadth of 500px and are fundamentally scaled down on smaller views. Every picture is optimized and compressed, nonetheless we don’t broach opposite images for opposite inclination — and no, we aren’t delivering any Retina images during all. That is all about to change soon.
While Smashing Magazine’s home page is good optimized, some pages and articles still perform poorly. Articles with many comments are utterly delayed given we use a Gravatar78 for comments. Because any Gravatar URL is unique, any criticism generates one HTTP request, negligence down a loading of a altogether page. We are going to defer a loading of Gravatars and cache them locally with a Gravatar Cache WordPress plugin79. We competence have already finished it by a time we examination this.
We’re personification around with DNS prefetching and HTML5 preloading to solve DNS lookups proceed forward of time (for example, for Gravatars and advertising). However, we are being clever and wavering here given we don’t wish to emanate a loading beyond for users on delayed or costly connections. Besides, we’ve combined third-party meta data80 to make a articles a bit easier to share. So, if we couple to an essay on Facebook, Facebook will lift optimized images, a outline and a pretension from a meta data, that is crafted away for any article. We’ve also happily beheld that essay pages corkscrew uniformly during 60fps81, and that with comparatively vast images and ads.
82
Yes, we can use SPDY today83. We customarily need to implement SPDY Nginx Module84 or Apache SPDY Module85. This is what we are going to tackle next.
Despite all of a optimizations, a categorical emanate still hasn’t been resolved: unequivocally delayed servers and a First Byte response times. We’ve been experiencing problems with a stream server setup and design nonetheless are tied with a long-term contract, nonetheless we will be relocating to a new server soon. We’ll take that eventuality to also pierce to SPDY86 on a server, a prototype of HTTP 2.0 (which is good upheld in vital browsers87, by a way), and we are looking into regulating a calm smoothness network as well.
Performance Optimization Strategy
To sum up, optimizing a opening of Smashing Magazine was utterly an bid to figure out, nonetheless many aspects of optimization can be achieved unequivocally quickly. In particular, front-end optimization is utterly easy and candid as prolonged as we have a common bargain of priorities. Yes, that’s right: we optimize calm delivery, and defer all else.
Strategically speaking, a following could be your opening optimization roadmap:
- Remove restraint scripts from a header of a page.
- Identify and defer non-critical CSS and JavaScript.
- Identify vicious CSS and bucket it inline in a head, and thereafter bucket a full CSS after rendering. (Make certain to set a cookie to forestall inline styles from loading with any page load.)
- Keep all vicious HTML and CSS to underneath 14 KB, and aim for a Speed Index of underneath 1000.
- Defer a loading of Web fonts and store them in localStorage or AppCache.
- Consider regulating WOFF2 to serve revoke latency and record distance of a web fonts.
- Replace JavaScript libraries with leaner JavaScript modules.
- Avoid nonessential libraries, and demeanour into options for stealing Respond.js and Modernizr; for example, by “cutting a mustard88” to apart browsers into buckets. Legacy browsers could get a fixed-width layout. Clever SVG fallbacks89 also exist.
That’s fundamentally it. By following these guidelines, we can make your manageable website really, really fast.
Conclusion
Yes, anticipating customarily a right plan to make this unequivocally website discerning took a lot of experimentation, blood, persperate and cursing. Our discussions kept encircling around successive stairs and on vicious and not-so-critical components and infrequently we had to take 3 stairs behind in sequence to focus in a opposite direction. But we schooled a lot along a way, and we have a flattering transparent suspicion of where we are streamer now, and, many importantly, how to get there.
So here we have it. A tiny story about a things that happened on this tiny website over a final year. If we notice any issues, greatfully let us know on Twitter @smashingmag90 and we’ll hunt them down for good.
Ah, and interjection for gripping us reading around all these years. It means a lot. You are utterly outstanding indeed. You should know that.
A large “thank you” to Patrick Hamann and Jake Archibald for a technical examination of a essay as good as Andy Hume and Tim Kadlec for their illusory support around a years. Also a large “thank you” to a front-end engineer, Marco, for his assistance with a essay and for his consummate and untiring front-end work, that concerned many experiments, failures and successes along a way. Also, kind interjection to a Inpsyde group and Florian Sander for technical implementations.
A final appreciate we goes out to Iris, Melanie, Cosima and Markus for gripping an eye out for those nasty bugs and looking after a calm on a website. Without you, this website wouldn’t exist. And appreciate we for carrying my behind all this time. we honour and value any singular bit of it. You rock.
(al, vf, il)
Footnotes
- 1 http://www.guypo.com/mobile/performance-implications-of-responsive-design-book-contribution/
- 2 http://timkadlec.com/2012/01/work-to-be-done/
- 3 http://timkadlec.com/2012/01/work-to-be-done/
- 4 http://timkadlec.com/2012/01/work-to-be-done/
- 5 http://www.w3.org/TR/resource-priorities/#intro-download-priority
- 6 http://www.smashingmagazine.com/wp-content/uploads/2014/09/browser-stats.png
- 7 http://www.smashingmagazine.com/wp-content/uploads/2014/09/browser-stats.png
- 8 https://twitter.com/nice2meatu
- 9 http://www.smashingmagazine.com/2013/10/29/get-up-running-grunt/
- 10 https://github.com/gruntjs/grunt-contrib-less
- 11 https://github.com/nDmitry/grunt-autoprefixer
- 12 https://github.com/gruntjs/grunt-contrib-cssmin
- 13 https://github.com/gruntjs/grunt-contrib-watch
- 14 http://inpsyde.com/en/
- 15 https://twitter.com/markodugonjic/statuses/478980625215782912
- 16 https://twitter.com/smash_it_on
- 17 https://twitter.com/mel_in_media
- 18 https://twitter.com/indysigner
- 19 http://www.twitter.com/smashingmag
- 20 https://github.com/scottjehl
- 21 https://github.com/guardian
- 22 https://github.com/BBC-News
- 23 http://filamentgroup.com/lab/performance-rwd.html
- 24 http://timkadlec.com/2014/01/fast-enough/
- 25 https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index
- 26 https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index
- 27 http://www.lukew.com/ff/entry.asp?1756
- 28 http://www.webpagetest.org/
- 29 https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index
- 30 http://chimera.labs.oreilly.com/books/1230000000545/ch10.html#SPEED_PERFORMANCE_HUMAN_PERCEPTION
- 31 http://chimera.labs.oreilly.com/books/1230000000545
- 32 http://chimera.labs.oreilly.com/books/1230000000545
- 33 https://www.youtube.com/watch?v=YV1nKLWoARQ
- 34 http://timkadlec.com/2014/05/performance-budgeting-with-grunt/
- 35 https://speakerdeck.com/andyhume/anatomy-of-a-responsive-page-load-whiskyweb-2013
- 36 https://vimeo.com/77967591
- 37 http://www.smashingmagazine.com/wp-content/uploads/2014/09/separation-concerns.png
- 38 http://www.smashingmagazine.com/wp-content/uploads/2014/09/separation-concerns.png
- 39 http://ianfeather.co.uk/web-fonts-and-the-critical-path/
- 40 http://ianfeather.co.uk/web-fonts-and-the-critical-path/
- 41 http://ianfeather.co.uk/web-fonts-and-the-critical-path/
- 42 https://github.com/typekit/webfontloader
- 43 http://alistapart.com/article/application-cache-is-a-douchebag
- 44 https://github.com/ahume/webfontjson
- 45 http://www.html5rocks.com/en/tutorials/offline/quota-research/
- 46 https://github.com/addyosmani/basket.js/issues/24
- 47 https://github.com/addyosmani/basket.js/issues/24
- 48 https://github.com/addyosmani/basket.js/issues/24
- 49 http://caniuse.com/#search=woff
- 50 https://twitter.com/hdragomir
- 51 https://gist.github.com/hdragomir/8f00ce2581795fd7b1b7
- 52 https://gist.github.com/sergejmueller/cf6b4f2133bcb3e2f64a
- 53 https://twitter.com/patrickhamann/status/497767778703933442
- 54 http://www.kreativrauschen.de/
- 55 http://www.feedthebot.com/pagespeed/defer-loading-javascript.html
- 56 https://www.igvita.com/2014/05/20/script-injected-async-scripts-considered-harmful/
- 57 https://developers.google.com/web/fundamentals/performance/critical-rendering-path/page-speed-rules-and-recommendations
- 58 http://www.filamentgroup.com/lab/performance-rwd.html
- 59 http://www.filamentgroup.com/lab/performance-rwd.html
- 60 http://www.filamentgroup.com/lab/performance-rwd.html
- 61 http://css-tricks.com/authoring-critical-fold-css/
- 62 https://github.com/addyosmani/above-the-fold-css-tools
- 63 http://www.webpagetest.org/result/140904_H4_T5R/1/details/
- 64 http://www.webpagetest.org/
- 65 http://www.webpagetest.org/result/140904_H4_T5R/1/details/
- 66 http://www.webpagetest.org/result/140904_ZJ_T62/
- 67 http://www.webpagetest.org/result/140904_Y5_SXS/
- 68 http://www.webpagetest.org/result/140904_DB_T5Y/
- 69 http://www.webpagetest.org/result/140904_H4_T5R/
- 70 https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fwww.smashingmagazine.comtab=desktop
- 71 https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fwww.smashingmagazine.comtab=mobile
- 72 https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fwww.smashingmagazine.comtab=mobile
- 73 https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fwww.smashingmagazine.comtab=desktop
- 74 https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fwww.smashingmagazine.comtab=desktop
- 75 http://filamentgroup.com/lab/performance-rwd.html
- 76 https://www.youtube.com/watch?v=dfweWyVScaI
- 77 http://scottjehl.github.io/picturefill/
- 78 https://en.gravatar.com/
- 79 https://wordpress.org/plugins/fv-gravatar-cache/
- 80 http://alistapart.com/article/like-able-content-spread-your-message-with-third-party-metadata
- 81 http://jankfree.org
- 82 http://caniuse.com/#search=SPDY
- 83 http://caniuse.com/#search=SPDY
- 84 http://nginx.org/en/docs/http/ngx_http_spdy_module.html
- 85 https://code.google.com/p/mod-spdy/
- 86 https://developers.google.com/speed/spdy/
- 87 http://caniuse.com/#search=SPDY
- 88 http://responsivenews.co.uk/post/18948466399/cutting-the-mustard
- 89 http://css-tricks.com/svg-fallbacks/
- 90 http://www.twitter.com/smashingmag
↑ Back to topShare on Twitter
Improving Smashing Magazine’s Performance: A Case Study
Nenhum comentário:
Postar um comentário