代码之家  ›  专栏  ›  技术社区  ›  TCCV

调整字体大小以适应DIV(在一行上)

  •  58
  • TCCV  · 技术社区  · 14 年前

    也有类似的问题被问到,但解决办法确实与我想做的相符。基本上,我有一篇文章有标题( <h1> )我不想控制标题的长度,但我也不想标题出现在多行上。有没有使用css或jquery根据 <div> 标签?

    我知道如果我能检测到文本到 <DIV & GT; :

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

    如果有一个CSS属性,我可以设置得更好,但我似乎找不到(溢出在这种情况下不起作用)。

    13 回复  |  直到 6 年前
        1
  •  44
  •   Derzu    6 年前

    CSS否,javascript是

    使用CSS不可能做到这一点,但可以在javascript/jquery中做到这一点。以帮助您使用伪代码,因为您已经知道该怎么做了。只是你不知道如何检测多余的宽度。

    最好的方法是使用具有以下(至少)样式的DIV:

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

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

    通过这种方式,这种检查将对用户的眼睛隐藏起来,因此也将更快地工作。

    顺便说一句 :这是自动增长的常见方式 textarea 脚本工作。它们使用与原始文本区域具有相同样式设置的虚拟分隔,并根据用户在文本中键入的内容调整区域的高度。因此,文本区域一开始可能很小,但如果用户键入大量文本,它将自动增长以适应内容。

    while循环优化

    通过这样做,您可以优化while循环,从而大大减少迭代次数:

    1. 设置起始字体大小。
    2. 获取测试分区的宽度。
    3. 计算orig_div和test_div之间的宽度系数。
    4. 按此系数调整字体大小,而不是按一个单位增减
    5. 测试测试分区宽度
        2
  •  22
  •   Community clintgh    7 年前

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

    为了防止标题跨多行,只需添加一个CSS样式:

    white-space:nowrap;
    

    元素。

    在头中包含jquery和quickfit之后。您可以使用以下选项触发快速拟合:

    $('h1').quickfit();
    

    它测量并计算要匹配的每个文本字母的大小不变量measure,并使用它来计算下一个最佳字体大小,该字体大小适合文本到容器中。

    计算被缓存,这使得处理必须容纳多个文本或必须多次容纳一个文本时非常快速,例如,在窗口调整大小时(调整大小时几乎没有性能惩罚)。

    Demo for a similar situation as yours

    更多文档、示例和源代码在项目页面上。

        3
  •  20
  •   Marty McVry    11 年前

    这里有3个我经常使用的函数来获取文本的宽度、高度和调整容器的宽度。

    • GETTrimeWITH() 将返回发起程序中包含的文本的实际宽度。
    • GetTextHeight(宽度) 将返回包含在具有特定宽度的发起程序中的换行文本的实际高度。
    • 自动文本大小(最小、最大、截断) 将调整容器中文本的大小,使其适合,同时考虑最小和最大大小。
    • 自动运行文本() 只显示用户实际可以看到的字符,并以“…”结束文本。
    (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);
    
        4
  •  4
  •   Christ    13 年前

    @克洛维六 谢谢你的回答。这对我很有用。遗憾的是,我不能只感谢你的投票。

    注意:我必须更改“$J”(对于“$”,它才能在我的配置中工作。

    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));
        }
      };
    

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

        5
  •  4
  •   tkahn    11 年前

    今天我创建了一个jquery插件 jquery响应式标题 这完全符合您的要求:它调整标题的字体大小,使其适合于其包含元素(DIV、正文或其他内容)。有一些不错的选项可以设置为自定义插件的行为,我还采取了预防措施,添加了对Ben Altmans Throttle/Debounce功能的支持,以提高性能,并在用户调整窗口大小时减轻浏览器/计算机上的负载。在最简单的用例中,代码如下所示:

    $('h1').responsiveHeadlines();
    

    …这将把页面上的所有h1元素转换成响应的单行标题,这些标题将调整它们的大小以适应父/容器元素。

    您将找到源代码和插件的较长描述。 on this GitHub page .

    祝你好运!

        6
  •  3
  •   MeV    10 年前

    很简单。为文本创建一个跨距,获取宽度并减小字体大小,直到跨距与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); 
    }
    
        7
  •  1
  •   Cory    12 年前

    这可能对您的要求有点过分,但我发现这个库非常有用:

    http://fittextjs.com/

    不过,这只适合单条线路,所以我不确定这是否符合你的要求。

        8
  •  1
  •   Chris Moschini    10 年前

    我不喜欢其他解决方案,所以,这里有另一个。它需要调整以下内容中文本大小的标记:

    1. 固定高度

    2. 不需要太长时间,它就会超过10像素的边界——这个想法是,你不想让它低于10像素,调整文本的大小使其变得不可读。在我们的用例中不是一个问题,但是如果在您的用例中是可能的,那么在运行这个用例之前,您需要考虑一下单独截断。

    它使用二进制搜索来查找最佳大小,所以我怀疑它比其他许多解决方案都要好,这些解决方案只是把字体大小一个像素一个像素地缩小一个像素。现在的大多数浏览器也支持字体大小的小数,而且这个脚本在那里有一些好处,因为它将达到最佳答案的.1px以内,不管是什么,即使它是一个相对较长的小数。你可以很容易地改变 max - fontSize < .1 其他价值 .1 以降低CPU使用率而获得的精度。

    用途:

    $('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/

        9
  •  1
  •   Melicerte    10 年前

    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

        10
  •  0
  •   Community clintgh    7 年前

    我的解决方案,作为基于 Robert Koritnik's answer :

    $.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());
        });
    }
    

    这实际上创建了一个继承重要属性的临时跨度,并比较宽度差。当然,while循环需要优化(减少两个大小之间计算出的百分比差异)。

    示例用法:

    $(function(){
        $("h1").fitToWidth();
    });
    
        11
  •  0
  •   Vincent    10 年前

    我做了一些jquery的东西来调整你的分区的字体大小。它甚至可以与多行一起使用,但是只会增加字体的大小(如果你想的话,你可以简单地设置默认的字体大小为1px)。 我增加字体大小直到有一个换行符,设置减少它1倍。没有其他花哨的东西,隐藏的DIV等等。只需添加 quickfit 给你的部门上课。

    $(".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");
    });
    
        12
  •  0
  •   Arix Zajicek    8 年前

    我理解这个问题似乎已经得到了相当彻底的回答,但在某些情况下,这里的解决方案可能会引起其他问题。例如,Tkahn的库看起来非常有用,但是它改变了它所连接的元素的显示,这可能是一个问题。在我的例子中,它阻止了我将文本垂直和水平居中。在一些混乱和试验之后,我想出了一个简单的方法,它涉及jquery,使文本适合一行,而不需要修改父元素的任何属性。注意,在这段代码中,我使用了RobertKoritnik的建议来优化while循环。要使用此代码,只需将“字体修复”类添加到任何包含需要在一行中适合它的文本的div中。对于报头,这可能需要在报头周围增加一个DIV。然后,对固定大小的DIV调用一次此函数,或者将其设置为不同大小的调整大小和/或方向侦听器。

    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属性轻松实现,如下所示:

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

    希望这对某人有帮助!

        13
  •  0
  •   Luke Brown Elle H    8 年前

    在这里查看这个例子 http://codepen.io/LukeXF/pen/yOQWNb 您可以在页面加载和页面大小调整上使用一个简单的函数来实现这种魔力。但是要小心,不要让客户机延迟太多的函数调用。(示例有延迟)。

    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");
            }
        });
    }