« x-webkit-speech input and textareas
Imagemagick crop and center »

Social button BFFs

TL;DR: Loading JavaScript asynchronously is critical for the performance of your web app. Below is an idea how to do it for the most common social buttons out there so you can make sure these don't interfere with the loading of the rest of your content. After all people need to see your content first, then decide if it's share-worthy.

Japanese translation by Koji Ishimoto is here

Facebook now offers a new asynchronous snippet to load the JavaScript SDK, which lets you load social plugins (e.g. Like button) among doing other more powerful things.

It has always been possible to load the JS SDK asynchronously but since recently it's the default. The code looks pretty damn nice (I know, right!), here's how it looks like (taken from here):

(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) {return;}
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

Some nice steal-me JS patterns here:

  • immediate (self-invoking) function so not to bleed vars into global namespace
  • pass oft-used objects (document) and strings ("script", "facebook-jssdk") to the immediate function. Sort of rudimentary manual minification, while keeping the code readable
  • append script node by using the first available script element. That's 99.99% guaranteed to work unless all your code is in body> or img onload or something similar (insanity, I know, but let's allow generous 0.01% for it)
  • assign an ID to the node you append so you don't append it twice by mistake (e.g. like button in the header, footer and article)

All buttons' JS files

Other buttons exist, most notably the Twitter and Google+1 buttons. Both of these can be loaded with async JavaScript whether or not this is the default in their respective configurators.

So why not make them all get along and shelter them under the same facebook immediate function? We'll save some bytes and extra script tags in the HTML. For G+/T buttons all we need is a new script node. Google+'s snippet has some additional attribs such as type and async, but these are not really needed. Because type is always text/javascript and async is always true. Plus we kinda take care of the async part anyways.

The end result:

  <div id="fb-root"></div>
  <script>(function(d, s, id) {
    // fb + common
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) {return;}
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
    fjs.parentNode.insertBefore(js, fjs);
    // +1
    js = d.createElement(s); 
    js.src = 'https://apis.google.com/js/plusone.js';
    fjs.parentNode.insertBefore(js, fjs);
    // tweet
    js = d.createElement(s); 
    js.src = '//platform.twitter.com/widgets.js';
    fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));</script>

So this thing loads all three JS files required by the three buttons/plugins.

Additionally we can wrap the node creation/appending part into a function. So all the code is tighter. Here's the final snippet:

<div id="fb-root"></div><!-- fb needs this -->
<script>(function(d, s) {
  var js, fjs = d.getElementsByTagName(s)[0], load = function(url, id) {
    if (d.getElementById(id)) {return;}
    js = d.createElement(s); js.src = url; js.id = id;
    fjs.parentNode.insertBefore(js, fjs);
  };
  load('//connect.facebook.net/en_US/all.js#xfbml=1', 'fbjssdk');
  load('https://apis.google.com/js/plusone.js', 'gplus1js');
  load('//platform.twitter.com/widgets.js', 'tweetjs');
}(document, 'script'));</script>

All buttons' markup

Next is actually advising the scripts where the widgets should be rendered. Facebook offers XFBML syntax, with tags such as <fb:like>, but it also offers pure HTML(5) with data-* attributes. Luckily, so do all others.

Here's an example:

<!-- facebook like -->
<div class="fb-like" data-send="false" data-width="280"></div>
<!-- twitter -->
<a class="twitter-share-button" data-count="horizontal">Tweet</a>
<!-- g+ -->
<div class="g-plusone" data-size="medium"></div>

G+ requires a div element (with g-plusone class name), Twitter requires an a (with a twitter-share-button class name). Facebook will take any element you like with a fb-like class name (or fb-comments or fb-recommendations or any other social plugin you may need)

Also very important to note that you can (and should) load the JS files once and then render as many different buttons as you need. In Facebook's case these can be any type of plugin, not just like buttons. Economy of scale - on JS file, many plugins.

All together now

So here's the overall strategy for loading all those buttons.

  1. Copy the JS above at the bottom of the page right before /body just to be safe (G+ failed to load when the markup is after the JS). This will also help you make sure there should be only one place to load the JS files, although the snippet takes cares of dedupe-ing.
  2. sprinkle plugins and buttons any way you like anywhere on your pages using the appropriate configurator to help you deal with the data-* attributes (FB, G+, Tw)
  3. Enjoy all the social traffic you deserve!

To see it all in action - go to my abandoned phonydev.com blog. Yep, those buttons play nice in mobile too.

This entry was posted on Tuesday, September 27th, 2011 and is filed under facebook, JavaScript, performance. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.


Get notification for future posts: follow me on Twitter or subscribe to my RSS feed

40 Responses to “Social button BFFs”

  1. Nicolas Says:
    September 27th, 2011 at 10:20 pm

    Good catch how did you find out about this change?

  2. Trucos Sims Social Says:
    September 28th, 2011 at 2:10 am

    Great info! I’ll test it in one of my sites. I had noticed loading times increasing after adding G+ button to my site. I also wonder how you discovered this.

    Thanks!

  3. Nicolas Hoizey Says:
    September 28th, 2011 at 2:12 am

    Nice article, thanks!

    Are data-* attributes OK for maximum compatibility with browsers, including IE6?

    I’ev seen Lanyrd uses classes for it’s badges: lanyrd.com/services/badges/docs/

  4. Mathias Bynens Says:
    September 28th, 2011 at 2:27 am

    Nice overview!

    I wrote about optimizing the asynchronous Google Analytics snippet (and by extension, any similar snippet) a while ago, and it’s good to see the same tricks are applied here spacer

    If you want to be even more efficient, you could append all these scripts to a document fragment so you can insert them into the DOM all at once. Nicolas Gallagher wrote a script that does this: https://gist.github.com/1025811

  5. Nicolas Hoizey Says:
    September 28th, 2011 at 10:53 am

    OK, still awaiting moderation… I found the answer elsewhere, you can remove both comments: stackoverflow.com/questions/2412947/do-html5-custom-data-attributes-work-in-ie-6

  6. R. Richard Hobbs Says:
    September 28th, 2011 at 12:24 pm

    very helpful – thanks spacer

  7. Stoyan Says:
    September 28th, 2011 at 2:14 pm

    @Mathias, your analytics snippet analysis was (still is spacer ) awesome, thanks! And good point about the fragment

    @NIcholas, I’ll leave your comments if you don’t mind, so those coming after you see the answer spacer

  8. Kaelig Says:
    September 29th, 2011 at 9:35 am

    Thanks for the tip, I wish there was a way to load a translated G+ button this way, but specifying the language seems to be trickier with G+ than Facebook.

  9. Aaron Peters Says:
    October 5th, 2011 at 6:31 am

    Nice Stoyan. Good to see a new blog post. Keep ‘em coming.

    I used the snippet on my new site, www.cdnplanet.com

  10. The 25 best new web performance links of Q3 — Web Performance Today Says:
    October 5th, 2011 at 6:37 pm

    [...] Social button BFFs Good post from Stoyan Stefanov on how to make your social buttons load asynchronously. [...]

  11. Going Async! « Webforscher's Blog Says:
    October 13th, 2011 at 9:00 am

    [...] was then further fueled by a Post from Stoyan Stefanov, where he showed a way to go async for actually all of the most prominent [...]

  12. Alexander Says:
    October 13th, 2011 at 11:47 am

    That is super information! Thanks for sharing! I’m going to Tweet about your blog.

  13. Martin Borthiry Says:
    October 13th, 2011 at 1:27 pm

    Perfect Stoyan!.

    But I think that the var js must be declared inside load function.

  14. DDMDWGGH: Sticky Thing, Bollywood Action, F1 POV und vieles mehr | cmff.de Says:
    October 29th, 2011 at 9:02 pm

    [...] Wie man Social Button performance orientiert in seiner Website einbindet erklärt Stoyan Stefanov in seinem Blog [...]

  15. 最近海外で流行りのTwitter,Facebook,Google+1,Analyticsをまとめる非同期スクリプトにはてなを加えてみた | ゆっくりと… Says:
    November 17th, 2011 at 5:09 pm

    [...] JavaScript の著者である Stoyan Stefanov は、2011年9月にブログ記事 「Social button BFFs」 で類似のスクリプトを発表しました。おもしろいことに彼は、Google [...]

  16. Mike Cravey Says:
    November 18th, 2011 at 10:38 am

    I used something very similar but ran into an issue with buttons added later to the page (primarily modals). FB and Twitter seem to have reparsing methods but I couldnt find one for Digg or G+. I ended up reloading those scripts in that event. Don’t suppose you have come across a better way to do that, have ya?

  17. The day StumbleUpon stumbled: Why we removed the SU button from our sites Says:
    November 18th, 2011 at 1:06 pm

    [...] for an asynch version, but there was none to be found. Then we tried to hack a workaround, using this tutorial from Stoyan Stefanov, but no dice (not a criticism of Stoyan’s tips, just the nature of this [...]

  18. Chris Weekly Says:
    November 23rd, 2011 at 9:25 am

    Thanks Stoyan, this is great.
    Aaron Peters just wrote article (also great) in which he uses your approach but takes the additional step of making the scripts not just async, but also defers to post-onload. Check it out:
    www.aaronpeters.nl/blog/why-loading-third-party-scripts-async-is-not-good-enough

    Keep up the great work!
    /Chris

  19. John Macpherson Says:
    November 27th, 2011 at 11:02 am

    This is great.

    How do yuo go about tracking clicks from FaceBook and Twitter though?
    Using something like ‘twitterWidgets.onload = _ga.trackTwitter;’

    Any help appreciated.

  20. Performance Calendar » Frontend SPOF in Beijing Says:
    December 9th, 2011 at 3:09 am

    [...] should use. If the widgets you use don’t offer an async version you can try Stoyan’s Social button BFFs async [...]

  21. Hunter Sherman Says:
    December 15th, 2011 at 1:00 pm

    This is fantastic. Implementing it on our site now, thanks for posting!

  22. Jason Says:
    January 3rd, 2012 at 2:03 am

    I could really use some help integrating support for Flattr.com and Pinterest.com button into this, I tried adding there JS file to the load() portion but it does not load them for some reason, they have a similar button to all the others, could someone integrate those into this possibly?

  23. Jason Says:
    January 3rd, 2012 at 2:06 am

    This is the code for a Flattr button

    (function() {
    var s = document.createElement(‘script’), t = document.getElementsByTagName(‘script’)[0];
    s.type = ‘text/javascript’;
    s.async = true;
    s.src = ‘api.flattr.com/js/0.6/load.js?mode=auto’;
    t.parentNode.insertBefore(s, t);
    })();

    title

  24. Traghetti Says:
    February 22nd, 2012 at 11:45 am

    Wow. What an information! Thanks a lot for the help!

  25. David Says:
    March 5th, 2012 at 9:54 am

    Cheers for that, as a non-coder type have been able to get this up and running on a site where it was causing loads of hangs. Works a treat!

  26. Mark Says:
    March 20th, 2012 at 1:26 pm

    I can’t believe I never thought of this. I wish I could tell you how many social buttons I have added to websites.

  27. Frontend SPOF in Beijing | High Performance Web Sites Says:
    March 28th, 2012 at 3:36 pm

    [...] Radar should use. If the widgets you use don’t offer an async version you can try Stoyan’s Social button BFFs async [...]

  28. George Says:
    April 5th, 2012 at 6:56 pm

    I’d like to say thanks very much for the info and much more efficient script for calling these social buttons and they can be very very slow to load. Using on my site now ! Cheers

  29. mrPerezMarc Says:
    April 18th, 2012 at 9:34 am

    How would you include social apps like addthis that if using your technique, won’t register a vote?
    Example: If I click on the g+1 it will give me the ! saying there was a server error.
    Any updates on how to fix this?

  30. Async Social Sharing WordPress Plugin | Rachel Baker Says:
    April 25th, 2012 at 3:15 pm

    [...] code was inspired by Stoyan Stefanov’s Social Button BFFs blog post. Tweet Vote on [...]

  31. Edward Says:
    May 20th, 2012 at 11:03 pm

    I’m wondering if yo know how to integrate LinkeIN button on your code

  32. 3PO / Stoyan's phpied.com Says:
    June 27th, 2012 at 11:32 am

    [...] Use the JavaScript snippets that load the JS files asynchronously in order to speed up the user experience. Most providers offer you an asynchronous version of the script you're including on your page. If they don't, let them know and meanwhile do it yourself [...]

  33. Gautam Doddamani Says:
    June 29th, 2012 at 5:53 am

    thanks a lot this tutorial was really helpful..i had been searching for ways to load all my social media buttons asynchronously..you have provided a very neat method! spacer

  34. Nicholas Camp Says:
    July 11th, 2012 at 4:05 pm

    Actually there’s socialitejs.com too, that do exactly that! spacer

  35. Dave Artz Says:
    August 29th, 2012 at 7:56 pm

    Tighter code? spacer

    if (!d.getElementById(id)) {
    js = d.createElement(s); js.src = url; js.id = id;
    fjs.parentNode.insertBefore(js, fjs);
    }

    Would love to see a post based on your High Performance Social talk — great new ideas!

  36. John Says:
    September 20th, 2012 at 4:41 am

    Great code.
    Dave Artz, thanks for the updated code!!!

  37. Cheryll Hufstetler Says:
    December 16th, 2012 at 4:22 am

    I always give facebook likes to pages that i like. -

    My very own web site
    www.caramoantourpackage.com/

  38. Rishi Says:
    December 18th, 2012 at 10:14 pm

    Always looking for ways to optimize site performance – thanks so much for the post and valuable commentary!

  39. tararadam Says:
    January 7th, 2013 at 5:56 am

    Very interesting! Thank you very much for sharing.

  40. Coupons Canada Says:
    January 25th, 2013 at 3:46 am

    Thanks after playing around with it we are now using this on our website. Great code! Plus +1 for this post.

Leave a Reply