How can I make the Facebook Like button's width automatically resize? How can I make the Facebook Like button's width automatically resize? javascript javascript

How can I make the Facebook Like button's width automatically resize?


#fblike iframe {    width: 95px !important;}#fblike .fb_edge_comment_widget iframe {    width: 330px !important;}

And

<div id="fblike"><fb:like show-faces="false" layout="button_count"></fb:like></div>

This way both comment and like button iframes are fixed width. No funny effects. Hope it helps.


As everyone probably knows by now, there is no easy way to do this. I did come up with a programatic kludge of sorts, though. And when I say kludge, I really mean it! I do not consider this ready for prime time, but someone may like to tinker with the concept and try to find something workable.

The idea is that although you can't read the content width of the iframe, you can loop through a series of widths for the iframe itself until you find one that just barely prevents the text inside from wrapping. At that point, the text must touching the right-hand side of the iframe. In other words, we want to set the width of the iframe to 1px wider than the width that would cause the text to wrap.

Detecting whether the text is wrapping is easy enough in principle -- you set the iframe width, wait for the FB code to adjust the content, and then read the height. If everything fit on one line, the height should be about 25px. More than that means the text has wrapped.

The difficulty comes with the "wait for the FB code to adjust the content" part. I feel like there must be someway to force a "redraw" of the iframe, but so far I haven't found it. Calling FB.XFBML.parse() is obvious, but it doesn't seem to work. This is the part where I got stuck. I'm forcing the iframe to reload by setting its src attribute, which does the job but at a horrible price in speed. It is just meant as "proof of concept" at this point. Almost as good would be a simple way to know when any redraw was finished; I feel that should also be possible but my brain bogged down before I found anything simple.

Anyway here is some test code if you want to give it a try. It takes forever to get the button in position, but it does at least work. I left everything visible during the loading process so you can see what it's doing, on a real page it would be better to keep things hidden until everything is ready. Also note that the alignment may be slightly off because I am adjusting the width 5px at a time. If things could be made faster it would be easy to use 1px instead. Even better would probably be a rough adjustment to get close, then a fine adjustment to get it perfect. Obviously lots of experimenting to do, for whoever might want to take it up.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><script type='text/javascript'>var likediv, likeframe;function loadcode(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);}function init(){loadcode(document, 'script', 'facebook-jssdk');likediv=document.getElementById('d2');setTimeout(initx, 10);}function initx(){likeframe=likediv.getElementsByTagName('iframe')[0];if (!likeframe) { setTimeout(initx, 10); return; }likeframe.style.width='225px';setTimeout(shrink, 10);}function shrink(){likeframe=likediv.getElementsByTagName('iframe')[0];var currwidth=parseInt(likeframe.style.width);if (currwidth>=500) return;newwidth=currwidth+5;likeframe.style.width=newwidth+'px';likeframe.style.height='0';likeframe.src=likeframe.src;setTimeout(checkframe, 10);}function checkframe(){var h=parseInt(likeframe.offsetHeight);if (h==0) setTimeout(checkframe, 10);else if (h>25) shrink();//else we are done; make the frame visible if we hid it earlier}</script></head><body onload='init()' style='margin:10px 50px'><div id="fb-root"></div><div style='text-align:right'>Here is some right-aligned text to compare to.</div><div id='d2' style='float:right;height:25px;overflow:hidden;border:1px dotted red'><div class="fb-like" data-send="false" data-width="225" data-show-faces="false" data-action="recommend"></div></div></body></html>

EDIT: Did a little more experimenting, still an awkward workaround but faster than before:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><script type='text/javascript'>var likediv, likeframe, targwidth;function loadcode(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);}function init(){loadcode(document, 'script', 'facebook-jssdk');likediv=document.getElementById('d2');setTimeout(initx, 10);}function initx(){likeframe=likediv.getElementsByTagName('iframe')[0];if (!likeframe) { setTimeout(initx, 10); return; }likeframe.style.width='225px';setTimeout(shrink, 10);}function shrink(){likeframe=likediv.getElementsByTagName('iframe')[0];var currwidth=parseInt(likeframe.style.width);if (currwidth>=500) return;targwidth=currwidth+5;likeframe.style.width='10px';likeframe.style.height='0';setTimeout(checkframe, 10);}function checkframe(){var h=parseInt(likeframe.offsetHeight);if (h==0) { setTimeout(checkframe, 10); return; }likeframe.style.width=targwidth+'px';likeframe.style.height='0';setTimeout(checkframe2, 10);}function checkframe2(){var h=parseInt(likeframe.offsetHeight);if (h==0) setTimeout(checkframe2, 10);else if (h>25) shrink();//else we are done; make the frame visible if we hid it earlier}</script></head><body onload='init()' style='margin:10px 50px'><div id="fb-root"></div><div style='text-align:right'>Here is some right-aligned text to compare to.</div><div id='d2' style='float:right;height:25px;overflow:hidden;border:1px dotted red'><div class="fb-like" data-send="false" data-width="225" data-show-faces="false" data-action="recommend"></div></div></body></html>

FINAL EDIT: This is the best I think this method is ever going to get; the code could certainly be tweaked but it's always going to take several seconds to run through the trial widths to find what works. But it's now quick enough (around 5 seconds) that it might actually be usable. BTW I am adding each new code version rather than replacing the old ones because I haven't done much cross-browser testing of this code and it's possible the higher-speed versions won't work for someone. Since it's all experimental code I think it's better to have the different versions available for fallback.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><script type='text/javascript'>var minwidth=225, maxwidth=500, finished=false, last_was_good=null;var likediv, likeframe, targwidth, boundlow, boundhigh;function loadcode(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);}function init(){loadcode(document, 'script', 'facebook-jssdk');likediv=document.getElementById('d2');setTimeout(initx, 10);}function initx(){likeframe=likediv.getElementsByTagName('iframe')[0];if (!likeframe) { setTimeout(initx, 10); return; }likeframe.style.width=minwidth+'px';setTimeout(trynewwidth, 1);}function trynewwidth(){if (last_was_good==null) { boundlow=minwidth; boundhigh=maxwidth; }else if (last_was_good) boundhigh=targwidth;else boundlow=targwidth;finished=((boundhigh-boundlow)<2);if (finished && last_was_good) { done(); return; }if (finished && !last_was_good) targwidth=boundhigh;else targwidth=parseInt((boundlow+boundhigh)/2);setTimeout(setwidth, 1);}function done(){//All finished, if we were hiding the div make it visible now}function setwidth(){likeframe=likediv.getElementsByTagName('iframe')[0];likeframe.style.width='10px';likeframe.style.height='0';setTimeout(checkframe, 10);}function checkframe(){var h=parseInt(likeframe.offsetHeight);if (h==0) { setTimeout(checkframe, 10); return; }likeframe.style.width=targwidth+'px';likeframe.style.height='0';setTimeout(checkframe2, 10);}function checkframe2(){var h=parseInt(likeframe.offsetHeight);if (h==0) { setTimeout(checkframe2, 10); return; }if (finished) { done(); return; }last_was_good=(h<26);setTimeout(trynewwidth, 1);}</script></head><body onload='init()' style='margin:10px 50px'><div id="fb-root"></div><div style='text-align:right'>Here is some right-aligned text to compare to.</div><div id='d2' style='float:right;height:25px;overflow:hidden;border:1px dotted red'><div class="fb-like" data-send="false" data-width="225" data-show-faces="false" data-action="recommend"></div></div></body></html>


If you use the XFBML version of the Like button, along with the Facebook Javascript SDK, you can subscribe to the 'xfbml.render' event, and once that event fires, you can set the width of the like button iframe to some small value. (I use 50px.) The iframe will then auto-adjust its width as needed in order to display button and like count and whatever other elements, according to your config.

https://developers.facebook.com/docs/reference/javascript/

The biggest obstacle to this solution is that you will need a Facebook App ID. You can get an App ID by creating an app here: https://developers.facebook.com/apps/