如何使Facebook的“点赞”按钮宽度自动调整?

32
我正在实施Facebook Like Button,但是遇到了宽度的问题。我正在使用JavaScript SDK实现,而不是直接使用iframe。
根据文档,默认宽度为450。那很好,我知道可以通过<fb:like>标签上的width属性来更改宽度。然而,我的问题是我真的不能指定固定的宽度。由于按钮的性质,各状态下的宽度并不相同。例如,如果没有人喜欢该页面,它会显示“成为第一个赞此项目的朋友”;如果有人赞过,它会显示“XXX人喜欢此项。成为第一个赞此项目的朋友”;而如果是赞了它,则会显示“你赞了这个”或者“你和XXX人赞了这个”。换句话说,这个按钮有许多状态,每个状态都有不同的宽度。
如果不考虑一个问题,我想将按钮浮动在<div>的右侧显示。更确切地说,我正在做这件事:
<div id="wrapper">
    <span class="fb-like"><fb:like show_faces="false" width="450" font="lucida grande""></fb:like></span>
    ...
</div>
<style type="text/css">
.fblike {
    display: inline-block;
    padding: 0.5em;
    position: absolute;
    right: 0;
    top: 0;
}
#wrapper {
    position: relative;
}
</style>

这很好用,但问题是iframe现在有一个450像素的恒定宽度。由于iframe左对齐,当文本较短时,右侧会有额外的空间。我尝试了各种应用text-align: right的方法,但都无济于事。而且问题进一步恶化的是,这实际上只是FB SDK添加的iframe的花哨标记,所以我无法使用CSS或JavaScript更改任何内容。
我需要一个解决方案,要么保持按钮区域的宽度动态(即根据内容更改),要么将按钮区域中的所有内容右对齐。
感谢任何人可以给我的帮助!
8个回答

13
#fblike iframe {
    width: 95px !important;
}

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

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

这样评论和点赞按钮的 iframe 都具有固定的宽度,不会产生奇怪的效果。希望对您有所帮助。


1
实际上,这只是调整了 iframe 的大小,但仍然会裁剪其中的一些文本,因为 iframe 内部的某些深层标签仍然具有 CSS 宽度分配,而这些分配是在文档外无法修改的。 - i--

5
如果您使用Like按钮的XFBML版本,以及Facebook Javascript SDK,您可以订阅'xfbml.render'事件,一旦该事件触发,您可以将Like按钮iframe的宽度设置为一些较小的值(我使用50px)。然后,根据您的配置,该iframe将自动调整其宽度以显示按钮、点赞计数和其他元素。

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

这个解决方案最大的障碍是需要一个Facebook应用程序ID。您可以通过在此处创建应用程序来获得应用程序ID:https://developers.facebook.com/apps/

+1 这实际上起作用了(让我感到惊讶)。唯一的问题是,如果用户喜欢,然后取消喜欢,框将不会收缩以适应“不喜欢”的状态,但对我来说已足够了,不会再浪费精力在这上面。 - Daniel

5
众所周知,这并不容易。但我确实想出了一种程序化的方法。当我说“程序化”的时候,我真的是这个意思!我认为这还没有准备好投入使用,但有人可能会喜欢尝试这个概念并找到可行的东西。
这个想法是,虽然你不能读取iframe的内容宽度,但你可以循环遍历一系列iframe本身的宽度,直到找到一个刚好防止内部文本换行的宽度。此时,文本必须接触到iframe的右侧。换句话说,我们希望将iframe的宽度设置为比导致文本换行的宽度多1像素。
原则上检测文本是否换行很容易--你设置iframe的宽度,等待FB代码调整内容,然后读取高度。如果所有内容都在一行上,高度应该大约为25像素。超过这个范围意味着文本已经换行。
困难在于“等待FB代码调整内容”部分。我感觉有一种方法可以强制重新绘制iframe,但到目前为止我还没有找到。调用FB.XFBML.parse()是显而易见的,但似乎不起作用。这就是我卡住的地方。我通过设置其src属性来强制重新加载iframe,这样做的代价太高了。这只是“概念证明”阶段。几乎同样好的是一种简单的方法来知道任何重绘何时完成;我感觉这也应该是可能的,但在找到任何简单的东西之前,我的大脑就卡住了。
无论如何,如果你想尝试一下,这里有一些测试代码。把按钮放到正确位置需要很长时间,但它确实有效。在加载过程中,我保留了所有可见内容,这样你就可以看到它在做什么,在真正的页面上,最好在一切准备就绪之前将一切隐藏起来。还要注意,由于我每次调整5像素的宽度,所以对齐可能会略有偏差。如果事情能变得更快,使用1像素将很容易。更好的方法可能是粗略调整接近,然后微调使其完美。显然,对于想要接手的人来说,有很多实验要做。
<!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>

编辑:进行了更多实验,仍然是一个笨拙的解决方法,但比以前快:

<!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>

最终编辑:我认为这是这种方法能达到的最佳效果;代码肯定可以进行调整,但总是需要几秒钟的时间来运行试用宽度以找到适合的解决方案。但现在它已经足够快了(约5秒),可能真的可以使用。顺便说一下,我正在添加每个新的代码版本而不是替换旧版本,因为我还没有对这个代码进行大量跨浏览器测试,较高速度版本可能不适用于某些人。由于这是实验性的代码,我认为最好有不同版本可供回退。

<!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>

1
有趣的方式,感谢分享。这绝对显示了问题是多么荒谬。希望一些Facebook员工路过并看到这个。 - samvermette
我稍微改进了它,新代码已添加在上方。但是我同意,这不应该是必要的。只需要一个属性,就可以在iframe样式中添加text-align:right。真正奇怪的是,显然过去通过将data-width设置为0来实现这一点,这使得iframe自动选择适当的宽度。这显然不再起作用,这意味着它被故意删除了?! - Floyd Wilburn

3
CSS修复
.fb-like, 
.fb-like > span,
.fb-like > span iframe {
    max-width:273px;
}

1
当提供解决问题的代码时,最好也至少给出一个简短的解释,以便阅读的人不必逐行解析它来理解差异。 - Fluffeh

2

在选择尺寸时,有一些常见问题的答案值得阅读。

https://developers.facebook.com/docs/plugins/like-button

虽然这样说仍然有些晦涩:

"插件的宽度。您选择的布局会影响您可以使用的最小和默认宽度,请参阅下面的常见问题解答以获取更多详细信息。"

标准模式

最小宽度:225像素

如果动作是“推荐”,则最小宽度增加40像素,如果发送为“true”,则增加60像素。

默认宽度:450像素。高度:35像素(没有照片)或80像素(带照片)。

盒子计数模式

最小宽度:55像素。默认宽度:55像素。高度:65像素。

按钮计数模式

最小宽度:90像素。默认宽度:90像素。高度:20像素。

按钮模式

最小宽度:47像素。默认宽度:47像素。高度:20像素。


太好了!这解决了我的一个问题,即如何在一个应该是响应式,并且在宽度为300像素的移动电话上工作的页面上放置FB按钮。无论设置如何,默认布局都是450像素宽,导致页面内容右侧出现150像素多余空间的横向滚动条。而button_count布局不会导致这样的滚动条出现。 - Roland
请注意,这些数字仅适用于英语(?)——尝试德语或法语,结果将不同。 - MeSo2

2
我个人正在使用以下内容...
#fbook-like {
    width: 50px !important; /*width of just the button*/
    overflow: visible; /*so there is no cut off*/
    vertical-align: top; /*bc all other like buttons align top*/
}

我在这里所做的是将fb按钮放在最右边,这样它就与我的边缘对齐,只有添加的评论(动态宽度)会显示在边缘之外。我可以保持良好的设计,同时展示评论,无论长度如何。

0
我在我的CSS中添加了这个:
div.fb-like.fb_iframe_widget > span {
 width: 100% !important;
}

div.fb-like.fb_iframe_widget{
 width: 100%;
}

0

我曾经遇到过使用add-this插件时的同样问题,并以类似的方式解决了它:

.addthis_button_facebook_like,
.addthis_button_facebook_like span,
.addthis_button_facebook_like span iframe {
    max-width: 450px !important;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接