How to resize Facebook Canvas app (iFrame) correct

2019-03-13 18:42发布

问题:

I need to adjust canvas size after updating content of a page. I can do it explicitly by

FB.Canvas.setSize({ width: 760, height: 1480 });

however, it doesn't work without parameters, i.e. .setSize().

Also, I can adjust the height by

FB.Canvas.setAutoResize(true);

but only increasing - it doesn't reduce the height when content is reduced.

The following lines do not work:

FB.Arbiter.inform("setSize", FB.Canvas._computeContentSize());
FB.Canvas.setSize(FB.Canvas._computeContentSize());

How can one make it working?

Some more comments on the subject:

  1. http://developers.facebook.com/blog/post/93
  2. http://developers.facebook.com/docs/reference/javascript/fb.canvas.setautoresize

Related:

  1. facebook-api: what's Facebook Connect cross-domain receiver URL?
  2. facebook-app: how can i change the height of a resizeable iframe application?
  3. Document height grows on resize when setting canvas dimensions dynamically

How do you control the size of your Facebook Canvas apps?

回答1:

Don't write your own function for timed Auto-resize. Fb has one:

FB.Canvas.setAutoResize();

If you know when you need to resize it use

FB.Canvas.setSize()

So, if you want to make is smaller when you click a link, stick it in a function and then call that function later like:

function sizeChangeCallback() {
    FB.Canvas.setSize();
  }

//start some function or on click event - here i used jquery
$("#something").click(function() {
  sizeChangeCallback()
});

You don't need to set an explicit height, but sometimes you can have trouble with dynamic xfbml elements like the comments plugin. Try using an event subscribe callback:

   FB.Event.subscribe('xfbml.render', function(response) {
    FB.Canvas.setAutoResize();
  });

http://developers.facebook.com/docs/reference/javascript/FB.Canvas.setSize/

http://developers.facebook.com/docs/reference/javascript/FB.Canvas.setAutoResize/

http://developers.facebook.com/docs/reference/javascript/FB.Event.subscribe/



回答2:

I have managed to make .setSize() working by delaying its execution (as suggested on various forums):

window.setTimeout(function() {
  FB.Canvas.setSize();
}, 250);

If you have XFBLM elements, especially fb:comments, then you need to parse the page before setting its size

window.setTimeout(function() {
  FB.XFBML.parse();
  FB.Canvas.setSize();
}, 250);

Note, that you need to run this script after your content block, otherwise increase the time interval (in ms) allowing webserver and client browser building the content before resizing canvas.

This approach only increases the height of your page and doesn't decrease it. You can achieve decreasing manually by firing the following line before the code above

FB.Canvas.setSize({height: 480}); // min height - .setSize() won't reduce it

however, there is a drawback - the page will be blinking due to the double resizing.

Also, one suggests running .setSize in several time intervals to account delayed content:

FB.Array.forEach([300, 600, 1000, 2000], function(delay) {
  setTimeout(function() {
    FB.XFBML.parse();
    FB.Canvas.setSize();
  }, delay)
});

In this case, the page and XFBML elements become quite blinky.



回答3:

We have pages in our iframe that append content to the page and then allow the user to refresh the content within the page in place. In these cases, we saw the same thing, where the content would not shrink when appropriate.

FB.Canvas.setSize() calls _computeContentSize, which is shown below:

_computeContentSize: function() {
  var body = document.body,
      docElement = document.documentElement,
      right = 0,
      bottom = Math.max(
        Math.max(body.offsetHeight, body.scrollHeight) +
          body.offsetTop,
        Math.max(docElement.offsetHeight, docElement.scrollHeight) +
          docElement.offsetTop);

  if (body.offsetWidth < body.scrollWidth) {
    right = body.scrollWidth + body.offsetLeft;
  } else {
    FB.Array.forEach(body.childNodes, function(child) {
      var childRight = child.offsetWidth + child.offsetLeft;
      if (childRight > right) {
        right = childRight;
      }
    });
  }
  if (docElement.clientLeft > 0) {
    right += (docElement.clientLeft * 2);
  }
  if (docElement.clientTop > 0) {
    bottom += (docElement.clientTop * 2);
  }

  return {height: bottom, width: right};
},

The problematic line is here:

bottom = Math.max(
      Math.max(body.offsetHeight, body.scrollHeight) +
        body.offsetTop,
      Math.max(docElement.offsetHeight, docElement.scrollHeight) +
        docElement.offsetTop);

Even if the content inside your iframe has shrunk, the value of body.offsetHeight will not shrink.

To solve this, we made a custom version of the computeContentSize function that only consults the docElement for height, like so:

function rfComputeContentSize() {
  var body = document.body,
      docElement = document.documentElement,
      right = 0,
      bottom = Math.max(docElement.offsetHeight, docElement.scrollHeight) + docElement.offsetTop;

  if (body.offsetWidth < body.scrollWidth) {
    right = body.scrollWidth + body.offsetLeft;
  } else {
    FB.Array.forEach(body.childNodes, function(child) {
      var childRight = child.offsetWidth + child.offsetLeft;
      if (childRight > right) {
        right = childRight;
      }
    });
  }
  if (docElement.clientLeft > 0) {
    right += (docElement.clientLeft * 2);
  }
  if (docElement.clientTop > 0) {
    bottom += (docElement.clientTop * 2);
  }

  return {height: bottom, width: right};
}

Anytime we want to resize and know that the content could shrink we'll use the custom function to pass content to setSize (e.g. FB.Canvas.setSize(rfComputeContentSize())), and anytime we know that the content will only grow, we'll use the standard FB.Canvas.setSize() function.

Note that we were using setAutoGrow() and I didn't check, but am assuming that it uses the same function to determine size. We disabled our call to setAutoGrow() and will have to be vigilant about calling setSize() at approrpriate times.

Logged this bug with Facebook: https://developers.facebook.com/bugs/228704057203827



回答4:

We ran into an issue where their FB.Canvas functions didn't work, although everything was properly initialized, because they’re using ‘IFRAME’ instead of iframe in their cross-domain JS setup, hence no XHTML compatibility.

We fixed this by prototyping our own createElement function and overriding theirs. Just put this right after you include Facebooks all.js:

document.__createElement = document.createElement;
document.createElement = function(tagName) {
            return document.__createElement(tagName.toLowerCase());
}


回答5:

bit of excess functionality, but this article explains why you cant do that dynamically and provides the easiest solution... http://www.twistermc.com/36764/shrink-facebook-tabs/ The answer is simple: Shrink it really small, then after a pause use AutoGrow to make it the correct size... Alice in Wonderland style.

  • I say easiest because from a dev and user point of view this slows things down by about 1/4 second, and the user gets a tiny flash of the scrollbars...


回答6:

Bobby's answer is very good. Only thing I would add to it is that some people have had success getting the page to shrink by doing the following:

FB.Canvas.setSize({ width: 760, height: 10 });

And then follow it with:

FB.Canvas.setAutoResize();

You don't have to use 10, just something smaller than the minimum size of your page. Then the FB.Canvas.setAutoResize() should go ahead and make it the proper height again and continue to update. The only time you need to call FB.Canvas.setSize({ width: 760, height: 10 }); again would be if the content shrunk again.

The danger of doing this is that if the FB.Canvas.setAutoResize(); doesn't work, you could have content that is cut off.



回答7:

None of this worked for me. Make sure to type this before the closing tag.

<div id="fb-root"></div>
<script type="text/javascript"> 
 window.fbAsyncInit = function() {

 //Der folgende Code ändert die Grösse des iFrames alle 100ms 
FB.Canvas.setAutoResize(100);

};
(function() {
var e = document.createElement('script');
e.async = true;
e.src = document.location.protocol +
 '//connect.facebook.net/en_US/all.js';
 document.getElementById('fb-root').appendChild(e);  
 }());

</script>    


回答8:

I tried to use FB.Canvas.setSize(e); to resize my app, but it did not resize at all.

I took a look in the Facebook Javascript and found out, that FB.Canvas.setSize calls the FB.Arbiter.inform('setSize',e) function.

If I call the FB.Arbiter.inform('setSize',{ width: 760, height: 1480 }) function right from my code, the canvas resizes correctly.



回答9:

This has worked for me:

<script type='text/javascript'>
window.onload=function() {
  FB.Canvas.setSize({width:760,height:document.body.offsetHeight});
}
</script>

Note that you don't need FB.init unless you are using it for other reasons.



回答10:

When resizing to the minimum height do not forget to make it a little bit bigger than it is, to account for horizontal scrolling bar and some extra pixels that some browsers add, otherwise you will end-up with vertical scroll.

Also I do not recommend to use body to count height.

This worked for me :

window.fbAsyncInit = function() 
{FB.Canvas.setSize({height:document.getElementById('m_table').offsetHeight+40});}

where m_table is table ID with all my content (you can use div instead).