调整字体大小以适合div(在一行中)

也有类似的问题,但解决scheme确实与我正在做的事情相吻合。 基本上,我有一个标题( <h1> )的文章。 我不想控制标题的长度,但我也不希望标题出现在多行上。 有没有一种方法与CSS或jQuery的基础上调整文本的宽度<div>标签?

我知道如果我可以检测到文本与<div>边缘的重叠,我会用伪代码做些什么:

 var fontize = $("#title").css("font-size"); var i = /*remove unit from integer*/ while( /*text overlaps div*/ ){ $("#title").css("font-size", --i+"pt"); } 

如果有一个CSS属性,我可以设置更好,但我似乎无法find一个(溢出不会在这种情况下工作)。

CSS不,Javascript是的

没有办法使用CSS来做到这一点,但是你可以在javascript / jQuery中做到这一点。 为了帮助你解决你的伪码,因为你已经知道该怎么做了。 只是你不知道如何检测多余的宽度。

最好的办法是有一个至less有以下风格的DIV:

 position: absolute; visibility: hidden; whitespace: nowrap; font-family: /* same as your title's */ 

然后将文本复制到它并设置一些开始字体大小。 然后你可以迭代你的while循环,当div的宽度合适时停止。 然后将计算的字体大小设置为您的原始标题。

这样,这种检查将被用户的眼睛隐藏起来,因此也会更快地工作。

顺便说一句 :这是自动生长textarea脚本如何工作的通常方式。 他们使用与原始文本区域具有相同样式设置的虚拟div,并在用户input文本时调整区域的高度。 所以文本区域起初可能非常小,但如果用户input大量文本,它会自动增长以容纳内容。

while循环优化

你可以通过这样做来优化你的while循环来减less迭代次数:

  1. 设置开始字体大小。
  2. 得到testingDIV的宽度。
  3. 计算orig_div和test_div之间的宽度因子。
  4. 调整字体大小的这个因素,而不是增加/减less一个单位
  5. testingtest_div的宽度

我有一个类似的问题,这使我为此写了自己的插件。 看看jquery-quickfit (与Robert Koritnik的解决scheme非常相似,我非常喜欢)。

为了防止标题跨越多行,只需添加一个css风格:

 white-space:nowrap; 

元素。

在标题中包含jquery和quickfit之后。 您可以触发quickfit:

 $('h1').quickfit(); 

它为文本的每个字母测量和计算尺寸不变的尺寸,并使用它来计算适合文本到容器中的下一个最佳字体尺寸。

计算被caching,这使得处理不得不适应多个文本或者不得不适应文本多次,例如在窗口大小调整(在resize时几乎不存在性能损失)时非常快速。

演示与你类似的情况

更多的文档,例子和源代码在项目页面上。

下面是我经常使用的3个函数来获取文本的宽度,高度,并调整容器宽度的大小。

  • getTextWidth()将返回包含在启动器中的文本的实际宽度。
  • getTextHeight(width)将以特定的指定宽度返回启动器中包含的包装文本的实际高度。
  • autoTextSize(minSize,maxSize,truncate)会根据容器的最小和最大尺寸来调整容器中的文本大小,以适合它。
  • autoTruncateText()将只显示用户可以看到的字符,并用“…”结束文本。
 (function ($) { $.fn.getTextWidth = function() { var spanText = $("BODY #spanCalculateTextWidth"); if (spanText.size() <= 0) { spanText = $("<span id='spanCalculateTextWidth' style='filter: alpha(0);'></span>"); spanText.appendTo("BODY"); } var valu = this.val(); if (!valu) valu = this.text(); spanText.text(valu); spanText.css({ "fontSize": this.css('fontSize'), "fontWeight": this.css('fontWeight'), "fontFamily": this.css('fontFamily'), "position": "absolute", "top": 0, "opacity": 0, "left": -2000 }); return spanText.outerWidth() + parseInt(this.css('paddingLeft')) + 'px'; }; $.fn.getTextHeight = function(width) { var spanText = $("BODY #spanCalculateTextHeight"); if (spanText.size() <= 0) { spanText = $("<span id='spanCalculateTextHeight'></span>"); spanText.appendTo("BODY"); } var valu = this.val(); if (!valu) valu = this.text(); spanText.text(valu); spanText.css({ "fontSize": this.css('fontSize'), "fontWeight": this.css('fontWeight'), "fontFamily": this.css('fontFamily'), "top": 0, "left": -1 * parseInt(width) + 'px', "position": 'absolute', "display": "inline-block", "width": width }); return spanText.innerHeight() + 'px'; }; /** * Adjust the font-size of the text so it fits the container. * * @param minSize Minimum font size? * @param maxSize Maximum font size? * @param truncate Truncate text after sizing to make sure it fits? */ $.fn.autoTextSize = function(minSize, maxSize, truncate) { var _self = this, _width = _self.innerWidth(), _textWidth = parseInt(_self.getTextWidth()), _fontSize = parseInt(_self.css('font-size')); while (_width < _textWidth || (maxSize && _fontSize > parseInt(maxSize))) { if (minSize && _fontSize <= parseInt(minSize)) break; _fontSize--; _self.css('font-size', _fontSize + 'px'); _textWidth = parseInt(_self.getTextWidth()); } if (truncate) _self.autoTruncateText(); }; /** * Function that truncates the text inside a container according to the * width and height of that container. In other words, makes it fit by chopping * off characters and adding '...'. */ $.fn.autoTruncateText = function() { var _self = this, _width = _self.outerWidth(), _textHeight = parseInt(_self.getTextHeight(_width)), _text = _self.text(); // As long as the height of the text is higher than that // of the container, we'll keep removing a character. while (_textHeight > _self.outerHeight()) { _text = _text.slice(0,-1); _self.text(_text); _textHeight = parseInt(_self.getTextHeight(_width)); _truncated = true; } // When we actually truncated the text, we'll remove the last // 3 characters and replace it with '...'. if (!_truncated) return; _text = _text.slice(0, -3); // Make sure there is no dot or space right in front of '...'. var lastChar = _text[_text.length - 1]; if (lastChar == ' ' || lastChar == '.') _text = _text.slice(0, -1); _self.text(_text + '...'); }; })(jQuery); 

@克洛维斯六谢谢你的回答。 这对我来说非常有用。 可惜我不能感谢你,而不仅仅是一个投票。

注意:我必须更改“$ J(”为“$(”它为我的configuration工作。

evendo,这个问题的范围超出了这个问题的范围,而不是在使用SO的时候,我扩展了你的代码,使它适用于带有最大高度的多行框。

  /** * Adjust the font-size of the text so it fits the container * * support multi-line, based on css 'max-height'. * * @param minSize Minimum font size? * @param maxSize Maximum font size? */ $.fn.autoTextSize_UseMaxHeight = function(minSize, maxSize) { var _self = this, _width = _self.innerWidth(), _boxHeight = parseInt(_self.css('max-height')), _textHeight = parseInt(_self.getTextHeight(_width)), _fontSize = parseInt(_self.css('font-size')); while (_boxHeight < _textHeight || (maxSize && _fontSize > parseInt(maxSize))) { if (minSize && _fontSize <= parseInt(minSize)) break; _fontSize--; _self.css('font-size', _fontSize + 'px'); _textHeight = parseInt(_self.getTextHeight(_width)); } }; 

PS:我知道这应该是一个评论,但评论不让我正确地发布代码。

今天,我创build了一个名为jQuery Responsive Headlines的jQuery插件,它完全符合你的要求:它调整标题的字体大小以适应其包含的元素(div,body或其他)。 有一些很好的选项,你可以设置自定义插件的行为,我也采取了预防措施,以添加支持Ben Altmans油门/去抖动function,以提高性能和减轻浏览器/计算机上的负载,当用户调整窗口。 在最简单的用例中,代码如下所示:

 $('h1').responsiveHeadlines(); 

…将把页面元素上的所有h1转换为响应的单行标题,将其大小调整为父/容器元素。

你可以在这个GitHub页面find源代码和一个更长的插件描述。

祝你好运!

很简单。 为文本创build一个跨度,获取宽度并减小字体大小,直到跨度与div容器的宽度相同:

 while($("#container").find("span").width() > $("#container").width()) { var currentFontSize = parseInt($("#container").find("span").css("font-size")); $("#container").find("span").css("font-size",currentFontSize-1); } 

这可能是你所需要的矫枉过正,但我​​发现这个库是非常有用的:

http://fittextjs.com/

虽然只有单行的好处,所以我不确定这是否符合您的要求。

我没有爱上其他解决scheme,所以,这里是另一个解决scheme。 它需要你正在调整其中的文本的标签:

  1. 固定高度

  2. 不要这么长时间,它会超过10px的界限 – 这个想法是,你不希望它拍摄下来,并调整文本的大小,使其变得不可读。 在我们的用例中不是一个问题,但是如果在你的情况下可能的话,在运行这个之前,你会想要分别截断一些思路。

它使用二进制search来find最佳尺寸,所以我怀疑它在这里和其他地方的performance都优于其他的解决scheme,只是将字体大小逐个像素地逐步下降。 现在大多数浏览器都支持字体大小的小数,而且这个脚本也有一些好处,因为它会在最佳答案的.1px范围内,不pipe是什么,即使它是一个相对长的小数。 您可以轻松地将max - fontSize < .1更改为除.1之外的其他值,以减lessCPU使用率的精度。

用法:

 $('div.event').fitText(); 

码:

 (function() { function resizeLoop(testTag, checkSize) { var fontSize = 10; var min = 10; var max = 0; var exceeded = false; for(var i = 0; i < 30; i++) { testTag.css('font-size', fontSize); if (checkSize(testTag)) { max = fontSize; fontSize = (fontSize + min) / 2; } else { if (max == 0) { // Start by growing exponentially min = fontSize; fontSize *= 2; } else { // If we're within .1px of max anyway, call it a day if (max - fontSize < .1) break; // If we've seen a max, move half way to it min = fontSize; fontSize = (fontSize + max) / 2; } } } return fontSize; } function sizeText(tag) { var width = tag.width(); var height = tag.height(); // Clone original tag and append to the same place so we keep its original styles, especially font var testTag = tag.clone(true) .appendTo(tag.parent()) .css({ position: 'absolute', left: 0, top: 0, width: 'auto', height: 'auto' }); var fontSize; // TODO: This decision of 10 characters is arbitrary. Come up // with a smarter decision basis. if (tag.text().length < 10) { fontSize = resizeLoop(testTag, function(t) { return t.width() > width || t.height() > height; }); } else { testTag.css('width', width); fontSize = resizeLoop(testTag, function(t) { return t.height() > height; }); } testTag.remove(); tag.css('font-size', fontSize); }; $.fn.fitText = function() { this.each(function(i, tag) { sizeText($(tag)); }); }; })(); 

http://jsfiddle.net/b9chris/et6N6/1/

在github上有一个jquery插件可能只是做你想做的。 它被称为jquery-quickfit。 它使用Jquery提供了一种快速和肮脏的方法来将文本放入其周围的容器中。

HTML:

 <div id="quickfit">Text to fit*</div> 

使用Javascript:

 <script src=".../jquery.min.js" type="text/javascript" /> <script src="../script/jquery.quickfit.js" type="text/javascript" /> <script type="text/javascript"> $(function() { $('#quickfit').quickfit(); }); </script> 

更多信息: https : //github.com/chunksnbits/jquery-quickfit

我的解决scheme,作为一个基于Robert Koritnik的答案的jQuery扩展:

 $.fn.fitToWidth=function(){ $(this).wrapInner("<span style='display:inline;font:inherit;white-space:inherit;'></span>").each(function(){ var $t=$(this); var a=$t.outerWidth(), $s=$t.children("span"), f=parseFloat($t.css("font-size")); while($t.children("span").outerWidth() > a) $t.css("font-size",--f); $t.html($s.html()); }); } 

这实际上会创build一个临时范围,inheritance重要的属性,并比较宽度差异。 当然,while循环需要优化(减less两个尺寸之间计算的百分比差异)。

用法示例:

 $(function(){ $("h1").fitToWidth(); }); 

我做了一个非常小的jQuery的东西来调整你的div的字体大小。 它甚至可以使用多行,但只会增加字体大小(如果需要,可以简单地设置1px的默认字体大小)。 我增加字体大小,直到有一个换行符,设置减less1px。 没有别的花哨的东西,隐藏div或如此。 只需将quickfit类添加到您的div。

 $(".quickfit").each(function() { var jThis=$(this); var fontSize=parseInt(jThis.css("font-size")); var originalLines=jThis.height()/fontSize; for(var i=0;originalLines>=jThis.height()/fontSize && i<30;i++) { jThis.css("font-size",""+(++fontSize)+"px"); } jThis.css("font-size",""+(fontSize-1)+"px"); }); 

我明白,这个问题似乎已经得到了相当彻底的回答,但也有一些解决scheme可能会导致其他问题。 例如,tkahn的库看起来非常有用,但它改变了它所连接的元素的显示,这可能是一个问题。 就我而言,它阻止了我纵向和横向的文本居中。 经过一些搞乱和试验之后,我想出了一个简单的方法,使用jQuery来将文本放在一行上,而不需要修改父元素的任何属性。 请注意,在这段代码中,我使用了Robert Koritnik的build议来优化while循环。 要使用此代码,只需将“font_fix”类添加到任何包含需要适合它的文本的div中。 对于标题,这可能需要额外的标题。 然后,要么为一个固定大小的div调用这个函数一次,要么将其设置为不同大小的resize和/或方向侦听器。

 function fixFontSize(minimumSize){ var x = document.getElementsByClassName("font_fix"); for(var i = 0; i < x.length; i++){ x[i].innerHTML = '<div class="font_fix_inner" style="white-space: nowrap; display: inline-block;">' + x[i].innerHTML + '</div>'; var y = x[i].getElementsByClassName("font_fix_inner")[0]; var size = parseInt($("#" + x[i].id).css("font-size")); size *= x[i].clientWidth / y.clientWidth; while(y.clientWidth > x[i].clientWidth){ size--; if(size <= minimumSize){ size = minimumSize; y.style.maxWidth = "100%"; y.style.overflow = "hidden"; y.style.textOverflow = "ellipsis"; $("#" + x[i].id).css("font-size", size + "px"); break; } $("#" + x[i].id).css("font-size", size + "px"); } } } 

现在,为了方便起见,我添加了一个额外的案例,如果文本太小(低于传入函数的最小阈值),文本将被截断。 一旦达到可能或不需要的阈值,就会发生另一件事情,就是将最大宽度改为100%。 这应该针对每个用户的情况进行更改。 最后,发布这个答案作为替代的全部目的是为了将内容集中在父div中。 这可以很容易地通过添加css属性到内部div类,如下所示:

 .font_fix_inner { position: relative; float: center; top: 50%; -webkit-transform: translateY(-50%); transform: translateY(-50%); } 

希望这有助于某人!

看看这个例子http://codepen.io/LukeXF/pen/yOQWNb ,你可以使用一个简单的函数在页面加载和页面resize,使魔术发生。 虽然要注意不要太多的函数调用拉客户端。 (这个例子有一个延迟)。

 function resize() { $('.resize').each(function(i, obj) { $(this).css('font-size', '8em'); while ($(this).width() > $(this).parent().width()) { $(this).css('font-size', (parseInt($(this).css('font-size')) - 1) + "px"); } }); }