ダイナミックテキストのサイズを自動調整して、固定サイズのコンテナーを埋める


312

ユーザーが入力したテキストを固定サイズのdivに表示する必要があります。フォントサイズを自動的に調整して、テキストができるだけボックスに入るようにする必要があります。

つまり-divが400px x 300pxの場合。ABCを入力すると、それは本当に大きなフォントになります。彼らが段落を入力すると、それは小さなフォントになります。

私はおそらく最大フォントサイズ(おそらく32px)から始めたいと思います。テキストが大きすぎてコンテナーに収まらない場合は、フォントサイズを収まるまで縮小します。


119
おそらく、JSを必要とせずにHTML5 / CSS3に追加されるべき最も驚くべき機能の1つです。
John Magnolia

いくつかの測定を行って、ダイナミックテキストの長さを変更し、コンテナのサイズを変更して、テキストを完全にフィットさせるフォントサイズを特定しました。そして、いくつかの回帰分析を行った後、最適なフォントサイズを自動的に生成する簡単な数学関数を思いつきました。
キム

2
実際には、最適なフォントサイズを与えるグラフはf(x)= g(letters)*(x / 1000)^ nで与えられることがわかります。ここで、g(x)は単純な関数で、nは使用しているフォント。(すべてのフォントに標準値を設定できますが、調整して完全に完璧にしたくない場合は...)xは、コンテナーの正方形ピクセル単位のサイズです。
キムの友人

1
あなたがまだ興味があるなら、私は答えを加えることができます。個人的には、スクリプトが「正しくなる」まで試行して失敗するのではなく、最初から正しいフォントサイズを生成する方がはるかに良い方法だと思います。
キム

1
これを行うためのより良い方法については、私の答えを確認してください
Hoffmann

回答:


167

ありがとう攻撃。jQueryを使いたかった。

あなたは私を正しい方向に向けました、そしてこれは私が結局終わったものです:

ここにプラグインへのリンクがあります:https : //plugins.jquery.com/textfill/
そしてソースへのリンク:http : //jquery-textfill.github.io/

;(function($) {
    $.fn.textfill = function(options) {
        var fontSize = options.maxFontPixels;
        var ourText = $('span:visible:first', this);
        var maxHeight = $(this).height();
        var maxWidth = $(this).width();
        var textHeight;
        var textWidth;
        do {
            ourText.css('font-size', fontSize);
            textHeight = ourText.height();
            textWidth = ourText.width();
            fontSize = fontSize - 1;
        } while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
        return this;
    }
})(jQuery);

$(document).ready(function() {
    $('.jtextfill').textfill({ maxFontPixels: 36 });
});

そして私のhtmlはこのようなものです

<div class='jtextfill' style='width:100px;height:50px;'>
    <span>My Text Here</span>
</div>

これは私の最初のjqueryプラグインなので、おそらく本来あるべきほど良くはありません。ポインタはもちろん大歓迎です。


8
私は実際にそれをクリーンアップし、jquery.comから入手できるプラグインとしてplugins.jquery.com/project/TextFillで
GeekyMonkey

3
@GeekyMonkey、プラグインをプルしましたか?このページへの重複リンクをたどっただけで、私は一見すると思いましたが、jQuery.comがサイトにリンクしています404
デビッドはモニカを

注:何らかの理由でこのプラグインが機能するのは、div(上記の例では$( '。jtextfill'))がルートドキュメントの一部である場合のみです。divが他のdiv内に埋め込まれている場合、.width()はゼロを返すように見えます。
Jayesh、2011

1
そのループの「while」行は私には間違っているように見えます-「||」の前後に括弧があるはずです 部分式。現在の表記では、フォントサイズの最小値は、高さではなく幅が大きすぎる場合にのみチェックされます。
Pointy

4
このアプローチは非常に遅く、フォントのサイズが変わるたびに、要素を再レンダリングする必要があります。これを行うためのより良い方法については、私の答えを確認してください。
ホフマン

52

パフォーマンスが悪いため、これまでの解決策のいずれも十分であるとは思えなかったため、ループの代わりに単純な数学を使用する独自の解決策を作成しました。すべてのブラウザでも正常に動作するはずです。

このパフォーマンステストケースによるとここにある他のソリューションよりもはるかに高速です。

(function($) {
    $.fn.textfill = function(maxFontSize) {
        maxFontSize = parseInt(maxFontSize, 10);
        return this.each(function(){
            var ourText = $("span", this),
                parent = ourText.parent(),
                maxHeight = parent.height(),
                maxWidth = parent.width(),
                fontSize = parseInt(ourText.css("fontSize"), 10),
                multiplier = maxWidth/ourText.width(),
                newSize = (fontSize*(multiplier-0.1));
            ourText.css(
                "fontSize", 
                (maxFontSize > 0 && newSize > maxFontSize) ? 
                    maxFontSize : 
                    newSize
            );
        });
    };
})(jQuery);

貢献したい場合は、これをGistに追加しました。


1
@ジョン、ありがとう!私のスクリプトは複数行を実行しないことは正しいですが、OPは特にそれを要求しなかったため、想定が間違っている可能性があります。また、そのような動作はあまり意味がありません。複数行のサポートを追加する最善の方法は、単語の数に基づいて文字列を分割し、上記のスクリプトで各部分を計算することであると思います。とにかく高速です。
mekwall

4
@ジョン、私は複数行のテキスト入力で少し遊んで、この解決策に終わりました。砂嵐の方法はおそらくより正確ですが、これはより高速です;)
mekwall

2
最小フォントサイズと最大フォントサイズのバージョンは次のとおり
Jess Telford

1
@ホフマンうーん。私の解決策は.css("font-size")ループを呼び出しません。どこから手に入れたの?私の解決策は、プラグインに追加した特別なものがないため、おそらくより高速です。プラグインをjsperfに追加することを歓迎します。どのプラグインが最速かを確認します;)
mekwall

1
@MarcusEkwallすみません、なぜか私はそこにしばらくループがあったのを見ました。あなたのアプローチは私のものと似ていますが、実際には私のプラグインが他のいくつかのことも行うので、少し遅くなります(高さと幅の両方に合わせて調整し、テキストと他のオプションを一元化するなど)。ループ内で.css関数を呼び出しています。
ホフマン

35

私がこの回答にときどき得る賛成票を気に入っている限り(ありがとう!)、これは本当にこの問題に対する最大のアプローチではありません。ここで、他の素晴らしい答えのいくつかをチェックしてください。特に、ループすることなく解決策を見つけたものです。


それでも、参考のために、ここに私の元の答えがあります

<html>
<head>
<style type="text/css">
    #dynamicDiv
    {
    background: #CCCCCC;
    width: 300px;
    height: 100px;
    font-size: 64px;
    overflow: hidden;
    }
</style>

<script type="text/javascript">
    function shrink()
    {
        var textSpan = document.getElementById("dynamicSpan");
        var textDiv = document.getElementById("dynamicDiv");

        textSpan.style.fontSize = 64;

        while(textSpan.offsetHeight > textDiv.offsetHeight)
        {
            textSpan.style.fontSize = parseInt(textSpan.style.fontSize) - 1;
        }
    }
</script>

</head>
<body onload="shrink()">
    <div id="dynamicDiv"><span id="dynamicSpan">DYNAMIC FONT</span></div>
</body>
</html>

そしてここにクラスを持つバージョンがあります

<html>
<head>
<style type="text/css">
.dynamicDiv
{
    background: #CCCCCC;
    width: 300px;
    height: 100px;
    font-size: 64px;
    overflow: hidden;
}
</style>

<script type="text/javascript">
    function shrink()
    {
        var textDivs = document.getElementsByClassName("dynamicDiv");
        var textDivsLength = textDivs.length;

        // Loop through all of the dynamic divs on the page
        for(var i=0; i<textDivsLength; i++) {

            var textDiv = textDivs[i];

            // Loop through all of the dynamic spans within the div
            var textSpan = textDiv.getElementsByClassName("dynamicSpan")[0];

            // Use the same looping logic as before
            textSpan.style.fontSize = 64;

            while(textSpan.offsetHeight > textDiv.offsetHeight)
            {
                textSpan.style.fontSize = parseInt(textSpan.style.fontSize) - 1;
            }

        }

    }
</script>

</head>
<body onload="shrink()">
    <div class="dynamicDiv"><span class="dynamicSpan">DYNAMIC FONT</span></div>
    <div class="dynamicDiv"><span class="dynamicSpan">ANOTHER DYNAMIC FONT</span></div>
    <div class="dynamicDiv"><span class="dynamicSpan">AND YET ANOTHER DYNAMIC FONT</span></div>
</body>
</html>

3
これはでうまく機能することがわかりました。offsetWidthサイズの変数を作成し、pxを追加する必要もありましたtextSpan.style.fontSize = size+"px";
Wez

2
必ず「+ "px"」が必要です。
sandun dhammika 2014年

@IdanShechterお待たせしました!例を追加しました!
攻撃する

ライフセーバーありがとうございます!私はjQueryを知らないので、私はあなたの解決策に固執します:)
vintproykt

32

他のほとんどの回答はループを使用して、divに収まるまでフォントサイズを縮小します。フォントがサイズを変更するたびにページが要素を再レンダリングする必要があるため、これは非常に遅くなります。最終的には、ユーザーブラウザーをフリーズせずにコンテンツを定期的に更新できるように、独自のアルゴリズムを記述して実行する必要がありました。他のいくつかの機能(テキストの回転、パディングの追加)を追加し、jQueryプラグインとしてパッケージ化しました。

https://github.com/DanielHoffmann/jquery-bigtext

単に電話する

$("#text").bigText();

そしてそれはあなたのコンテナーにうまくフィットします。

ここでそれを実際に見てください:

http://danielhoffmann.github.io/jquery-bigtext/

現時点では、いくつかの制限があります。divの高さと幅は固定でなければならず、テキストを複数行に折り返すことはできません。

最大フォントサイズを設定するオプションの取得に取り組みます。

編集:私はプラグインにいくつかの問題を見つけました、それは標準のもの以外の他のボックスモデルを処理せず、divはマージンやボーダーを持つことができません。私はそれに取り組みます。

Edit2:これらの問題と制限を修正し、オプションを追加しました。最大フォントサイズを設定でき、幅、高さ、またはその両方を使用してフォントサイズを制限することもできます。ラッパー要素で最大幅と最大高さの値を受け入れるように働きます。

Edit3:プラグインをバージョン1.2.0に更新しました。コードと新しいオプション(verticalAlign、horizo​​ntalAlign、textAlign)の大幅なクリーンアップと、spanタグ内の内部要素のサポート(改行やフォントの素晴らしいアイコンなど)。


1
テキストを複数行に折り返すことがサポートされていないのはなぜですか。
マニッシュサパリヤ2014年

1
@ManishSapariyaサポートされていますが、改行(brタグ)を手動で追加する必要があります。自動テキストラップをサポートしない理由は、高速にするためです(フォントサイズを複数回ではなく2回変更するだけです)。テキストが単語間でラップしないことを前提とする必要があります。私のプラグインが機能する方法は、font-sizeを1000pxに設定してから、テキストがコンテナーと比較されるサイズの係数を確認し、同じ係数でfont-sizeを減らします。通常のテキストの折り返しをサポートするには、非常に遅い遅いアプローチ(font-sizeを複数回減らす)を使用する必要があります。
ホフマン

おい!ここにはプライベートメッセージがないので、StackOverflowで、あなたの答えにコメントして質問する必要があります。私はあなたのjQueryプラグインが大好きですが、それを動作させることができません。適切なjQueryライブラリを含め、プラグインをダウンロードして含めました。これを試して使用すると、コンソールに「Uncaught TypeError:undefined is not a function」と表示されます。これはあなたがよく知っていることですか?これを修正する方法を知っていますか?ありがとう
Gust van de Wal

@GustvandeWal jqueryライブラリをインクルードした後、プラグインをインクルードする必要があります
Hoffmann

やった。<script type = "text / javascript" src = " code.jquery.com/jquery-2.1.1.min.js"></…src " js / jquery-bigtext.js "> </ scriptがあります>ブラウザは、jQueryライブラリまたはプラグインをロードできないことを通知しません。
Gust van de Wal

9

これは、GeekyMonkeyが上記に投稿したものに基づいており、いくつかの変更が加えられています。

; (function($) {
/**
* Resize inner element to fit the outer element
* @author Some modifications by Sandstrom
* @author Code based on earlier works by Russ Painter (WebDesign@GeekyMonkey.com)
* @version 0.2
*/
$.fn.textfill = function(options) {

    options = jQuery.extend({
        maxFontSize: null,
        minFontSize: 8,
        step: 1
    }, options);

    return this.each(function() {

        var innerElements = $(this).children(':visible'),
            fontSize = options.maxFontSize || innerElements.css("font-size"), // use current font-size by default
            maxHeight = $(this).height(),
            maxWidth = $(this).width(),
            innerHeight,
            innerWidth;

        do {

            innerElements.css('font-size', fontSize);

            // use the combined height of all children, eg. multiple <p> elements.
            innerHeight = $.map(innerElements, function(e) {
                return $(e).outerHeight();
            }).reduce(function(p, c) {
                return p + c;
            }, 0);

            innerWidth = innerElements.outerWidth(); // assumes that all inner elements have the same width
            fontSize = fontSize - options.step;

        } while ((innerHeight > maxHeight || innerWidth > maxWidth) && fontSize > options.minFontSize);

    });

};

})(jQuery);

違いは、複数の子要素を使用できることと、パディングを考慮に入れることです。javascriptとcssの混在を避けるために、デフォルトの最大サイズとしてfont-sizeを使用します。
サンドストローム2009年

5
これはすばらしいですが、どのように使用しますか?$( '。outer')。textfill(); 変化はありません。
Drew Baker

3
おかげで、これは非常に素晴らしい実装です。私が遭遇したことの1つ:非常に長いテキスト文字列と非常に狭いコンテナーを処理している場合、テキスト文字列はコンテナーからはみ出しますが、outerWidthはまだそうでないかのように計算されます。トス "word-wrap:break-word;" そのコンテナーのCSSに追加すると、この問題が修正されます。
ジョン

8

これは、バイナリ検索を使用して、可能な限り少ないステップで親に収まる最大サイズを見つける改善されたループ方法です(これは、固定フォントサイズでステップするよりも速くて正確です)。コードは、パフォーマンスのためにいくつかの方法で最適化されています。

デフォルトでは、10のバイナリ検索ステップが実行され、最適なサイズの0.1%以内になります。代わりに、numIterをある値Nに設定して、最適なサイズの1/2 ^ N以内にすることができます。

CSSセレクターで呼び出します。例: fitToParent('.title-span');

/**
 * Fit all elements matching a given CSS selector to their parent elements'
 * width and height, by adjusting the font-size attribute to be as large as
 * possible. Uses binary search.
 */
var fitToParent = function(selector) {
    var numIter = 10;  // Number of binary search iterations
    var regexp = /\d+(\.\d+)?/;
    var fontSize = function(elem) {
        var match = elem.css('font-size').match(regexp);
        var size = match == null ? 16 : parseFloat(match[0]);
        return isNaN(size) ? 16 : size;
    }
    $(selector).each(function() {
        var elem = $(this);
        var parentWidth = elem.parent().width();
        var parentHeight = elem.parent().height();
        if (elem.width() > parentWidth || elem.height() > parentHeight) {
            var maxSize = fontSize(elem), minSize = 0.1;
            for (var i = 0; i < numIter; i++) {
                var currSize = (minSize + maxSize) / 2;
                elem.css('font-size', currSize);
                if (elem.width() > parentWidth || elem.height() > parentHeight) {
                    maxSize = currSize;
                } else {
                    minSize = currSize;
                }
            }
            elem.css('font-size', minSize);
        }
    });
};

このオプションが大好きです。私はのためのパラメータを追加するには、それを修正vAlignしてpaddingvAlign == true選択した要素の行の高さを親の高さに設定します。パディングは、渡された値によって最終サイズを減らします。デフォルトは5です。本当に見栄えが良いと思います。
デビルズアドボケート

6

AngularJSのディレクティブを作成しました-GeekyMonkeyの回答に強く影響を受けていますが、jQueryの依存関係はありません。

デモ: http : //plnkr.co/edit/8tPCZIjvO3VSApSeTtYr?p=preview

マークアップ

<div class="fittext" max-font-size="50" text="Your text goes here..."></div>

指令

app.directive('fittext', function() {

  return {
    scope: {
      minFontSize: '@',
      maxFontSize: '@',
      text: '='
    },
    restrict: 'C',
    transclude: true,
    template: '<div ng-transclude class="textContainer" ng-bind="text"></div>',
    controller: function($scope, $element, $attrs) {
      var fontSize = $scope.maxFontSize || 50;
      var minFontSize = $scope.minFontSize || 8;

      // text container
      var textContainer = $element[0].querySelector('.textContainer');

      angular.element(textContainer).css('word-wrap', 'break-word');

      // max dimensions for text container
      var maxHeight = $element[0].offsetHeight;
      var maxWidth = $element[0].offsetWidth;

      var textContainerHeight;
      var textContainerWidth;      

      var resizeText = function(){
        do {
          // set new font size and determine resulting dimensions
          textContainer.style.fontSize = fontSize + 'px';
          textContainerHeight = textContainer.offsetHeight;
          textContainerWidth = textContainer.offsetWidth;

          // shrink font size
          var ratioHeight = Math.floor(textContainerHeight / maxHeight);
          var ratioWidth = Math.floor(textContainerWidth / maxWidth);
          var shrinkFactor = ratioHeight > ratioWidth ? ratioHeight : ratioWidth;
          fontSize -= shrinkFactor;

        } while ((textContainerHeight > maxHeight || textContainerWidth > maxWidth) && fontSize > minFontSize);        
      };

      // watch for changes to text
      $scope.$watch('text', function(newText, oldText){
        if(newText === undefined) return;

        // text was deleted
        if(oldText !== undefined && newText.length < oldText.length){
          fontSize = $scope.maxFontSize;
        }
        resizeText();
      });
    }
  };
});

これで私が抱えていた1つの問題はresizeText、がng-bind実際に要素にテキストを割り当てる前に呼び出され、現在のテキストではなく前のテキストに基づいてサイズが決定されることです。これは、ユーザーが入力するときに繰り返し呼び出される上記のデモではそれほど悪くありませんが、nullから実際の値に(一方向バインディングのように)一度呼び出されると、最大サイズのままです。
ミラル2014年

5

Marcus Ekwall:https ://gist.github.com/3945316から上記のスクリプトを分岐し、私の好みに合わせて微調整しました。ウィンドウのサイズが変更されると起動し、子が常にコンテナーに収まるようにしました。以下のスクリプトを参考のために貼り付けました。

(function($) {
    $.fn.textfill = function(maxFontSize) {
        maxFontSize = parseInt(maxFontSize, 10);
        return this.each(function(){
            var ourText = $("span", this);
            function resizefont(){
                var parent = ourText.parent(),
                maxHeight = parent.height(),
                maxWidth = parent.width(),
                fontSize = parseInt(ourText.css("fontSize"), 10),
                multiplier = maxWidth/ourText.width(),
                newSize = (fontSize*(multiplier));
                ourText.css("fontSize", maxFontSize > 0 && newSize > maxFontSize ? maxFontSize : newSize );
            }
            $(window).resize(function(){
                resizefont();
            });
            resizefont();
        });
    };
})(jQuery);

2
質問者を助けようとしているのは素晴らしいことです。ただし、リンクのみを使用して回答を残すと、場合によっては害を及ぼす可能性があります。あなたの答えは今は良いですが、もしリンクが死ぬとしたら、あなたの答えはそれの価値を失うでしょう。記事の内容を回答にまとめておくと参考になります。詳しくは、この質問を参照してください。
Cody Guldner、2013

5

これがOPの答えの私の修正です。

つまり、これを最適化しようとした多くの人々は、ループが使用されていると不平を言っていました。はい、ループは遅くなる可能性がありますが、他のアプローチは不正確になる可能性があります。

したがって、私のアプローチでは、バイナリ検索を使用して最適なフォントサイズを見つけます。

$.fn.textfill = function()
{
    var self = $(this);
    var parent = self.parent();

    var attr = self.attr('max-font-size');
    var maxFontSize = parseInt(attr, 10);
    var unit = attr.replace(maxFontSize, "");

    var minFontSize = parseInt(self.attr('min-font-size').replace(unit, ""));
    var fontSize = (maxFontSize + minFontSize) / 2;

    var maxHeight = parent.height();
    var maxWidth = parent.width();

    var textHeight;
    var textWidth;

    do
    {
        self.css('font-size', fontSize + unit);

        textHeight = self.height();
        textWidth = self.width();

        if(textHeight > maxHeight || textWidth > maxWidth)
        {
            maxFontSize = fontSize;
            fontSize = Math.floor((fontSize + minFontSize) / 2);
        }
        else if(textHeight < maxHeight || textWidth < maxWidth)
        {
            minFontSize = fontSize;
            fontSize = Math.floor((fontSize + maxFontSize) / 2);
        }
        else
            break;

    }
    while(maxFontSize - minFontSize > 1 && maxFontSize > minFontSize);

    self.css('font-size', fontSize + unit);

    return this;
}

function resizeText()
{
  $(".textfill").textfill();
}

$(document).ready(resizeText);
$(window).resize(resizeText);

これにより、要素で最小フォントと最大フォントを指定することもできます。

<div class="container">
    <div class="textfill" min-font-size="10px" max-font-size="72px">
        Text that will fill the container, to the best of its abilities, and it will <i>never</i> have overflow.
    </div>
</div>

さらに、このアルゴリズムには単位がありません。、、、などを指定するemrem%最終結果にそれが使用されます。

これがフィドルです:https : //jsfiddle.net/fkhqhnqe/1/


2

私のウェブサイトでもまったく同じ問題がありました。プロジェクター、壁、大画面に表示されるページがあります。

フォントの最大サイズがわからないので、@ GeekMonkeyの上記のプラグインを再利用しましたが、fontsizeをインクリメントしています。

$.fn.textfill = function(options) {
        var defaults = { innerTag: 'span', padding: '10' };
        var Opts = jQuery.extend(defaults, options);

        return this.each(function() {
            var ourText = $(Opts.innerTag + ':visible:first', this);
            var fontSize = parseFloat(ourText.css('font-size'),10);
            var doNotTrepass = $(this).height()-2*Opts.padding ;
            var textHeight;

            do {
                ourText.css('font-size', fontSize);
                textHeight = ourText.height();
                fontSize = fontSize + 2;
            } while (textHeight < doNotTrepass );
        });
    };

+1は、このページで実際に機能した唯一のプラグインです。
skybondsor '28年

2
このプラグインは、ページをクラッシュさせます。
Jezen Thomas

1

これは、minFontSizeパラメータを受け取ることもできる、受け入れられた回答のバージョンです。

(function($) {
    /**
    * Resizes an inner element's font so that the inner element completely fills the outer element.
    * @author Russ Painter WebDesign@GeekyMonkey.com
    * @author Blake Robertson 
    * @version 0.2 -- Modified it so a min font parameter can be specified.
    *    
    * @param {Object} Options which are maxFontPixels (default=40), innerTag (default='span')
    * @return All outer elements processed
    * @example <div class='mybigdiv filltext'><span>My Text To Resize</span></div>
    */
    $.fn.textfill = function(options) {
        var defaults = {
            maxFontPixels: 40,
            minFontPixels: 10,
            innerTag: 'span'
        };
        var Opts = jQuery.extend(defaults, options);
        return this.each(function() {
            var fontSize = Opts.maxFontPixels;
            var ourText = $(Opts.innerTag + ':visible:first', this);
            var maxHeight = $(this).height();
            var maxWidth = $(this).width();
            var textHeight;
            var textWidth;
            do {
                ourText.css('font-size', fontSize);
                textHeight = ourText.height();
                textWidth = ourText.width();
                fontSize = fontSize - 1;
            } while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > Opts.minFontPixels);
        });
    };
})(jQuery);

感謝しますが、コードの先頭にあるべきではないセミコロンがあると思います
Patrick Moore

1

この問題を解決するには、FitText.jsgithub page)を使用できます。TextFillと比較して本当に小さくて効率的です。TextFillは高価なwhileループを使用し、FitTextは使用しません。

また、FitTextはより柔軟です(私は非常に特別な要件を持つプロジェクトで使用し、チャンピオンのように機能します!)。

HTML:

<div class="container">
  <h1 id="responsive_headline">Your fancy title</h1>
</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="jquery.fittext.js"></script>
<script>
  jQuery("#responsive_headline").fitText();
</script>

オプションを設定することもできます:

<script>
  jQuery("#responsive_headline").fitText(1, { minFontSize: '30px', maxFontSize: '90px'});
</script>

CSS:

#responsive_headline {
   width: 100%;
   display: block;
}

また、必要に応じて、FitTextには非jQueryバージョンもあります。


fittextは高さを考慮しますか?
マニッシュサパリヤ2014年

1
@ManishSapariyaいいえ、ありません。コンテナーの幅を10で割り、フォントサイズとして使用します。
Dan H

1

編集:このコードは、HTML5ビデオの上にメモを表示するために使用されました。ビデオのサイズが変更されると(ブラウザーウィンドウのサイズが変更されると)、フォントサイズがオンザフライで変更されます。ノートはビデオに接続され(YouTubeのノートと同じように)、そのため、コードはDOMハンドルではなくインスタンスを使用します。直接。

リクエストに従って、これを達成するために使用したコードをいくつかスローします。(HTML5ビデオ上のテキストボックス。)コードはずっと前に記述されたものであり、率直に言って、かなり面倒です。質問はすでに回答されていて、回答はすでにかなり前に受け入れられているので、私はこれを書き換える必要はありません。しかし、誰かがこれを少し単純化したいのであれば、あなたは大歓迎です!

// Figure out the text size:
var text = val['text'];
var letters = text.length;
var findMultiplier = function(x) { // g(x)
    /* By analysing some functions with regression, the resulting function that
     gives the best font size with respect to the number of letters and the size
     of the note is:
     g(x) = 8.3 - 2.75x^0.15 [1 < x < 255]
     f(x) = g(letters) * (x / 1000)^0.5
     Font size = f(size)
     */
    return 8.3 - 2.75 * Math.pow(x, 0.15);
};

var findFontSize = function(x) { // f(x)
    return findMultiplier(letters) * Math.pow(x / 1000, 0.5);
};

val.setFontSizeListener = function() {
    p.style.fontSize = '1px'; // So the text should not overflow the box when measuring.
    var noteStyle = window.getComputedStyle(table);
    var width = noteStyle.getPropertyValue('width');
    var height = noteStyle.getPropertyValue('height');
    var size = width.substring(0, width.length - 2) * height.substring(0, height.length - 2);
    p.style.fontSize = findFontSize(size) + 'px';
};
window.addEventListener('resize', val.setFontSizeListener);

これらの数値をfont-familyからfont-familyに微調整する必要があるでしょう。これを行う良い方法は、GeoGebraと呼ばれる無料のグラフビジュアライザをダウンロードすることです。テキストの長さとボックスのサイズを変更します。次に、手動でサイズを設定します。手動の結果を座標系にプロットします。次に、ここに投稿した2つの方程式を入力し、「my」グラフが手動でプロットした独自のポイントに適合するまで数値を微調整します。


1

提案された反復ソリューションは、2つの面で劇的にスピードアップできます。

1)フォントサイズに1を加算または減算するのではなく、定数を掛けます。

2)まず、コース定数を使用してゼロにします。たとえば、各ループのサイズを2倍にします。次に、どこから始めればよいかおおまかに考えて、同じことをさらに細かく調整します。たとえば、1.1を掛けます。完璧主義者は理想的なフォントの正確な整数ピクセルサイズを望んでいるかもしれませんが、ほとんどの観察者は100ピクセルと110ピクセルの違いに気づいていません。あなたが完璧主義者なら、さらに細かい調整で3回繰り返します。

正確な質問に答える特定のルーチンまたはプラグインを作成するのではなく、基本的なアイデアに頼り、さまざまなコードを記述して、フィットのdiv、スパン、イメージなど、テキストだけでなく、あらゆる種類のレイアウトの問題を処理します。 ..コンテナ内の幅、高さ、面積などで、別の要素に一致する...

次に例を示します。

  var                           nWindowH_px             = jQuery(window).height();
  var                           nWas                    = 0;
  var                           nTry                    = 5;

  do{
   nWas = nTry;
   nTry *= 2;
   jQuery('#divTitle').css('font-size' ,nTry +'px');
  }while( jQuery('#divTitle').height() < nWindowH_px );

  nTry = nWas;

  do{
   nWas = nTry;
   nTry = Math.floor( nTry * 1.1 );
   jQuery('#divTitle').css('font-size' ,nTry +'px');
  }while( nWas != nTry   &&   jQuery('#divTitle').height() < nWindowH_px );

  jQuery('#divTitle').css('font-size' ,nWas +'px');

1

これは私が作成した最もエレガントなソリューションです。バイナリ検索を使用して、10回の繰り返しを行います。素朴な方法は、whileループを実行し、要素がオーバーフローし始めるまでフォントサイズを1ずつ増やすことでした。element.offsetHeightおよびelement.scrollHeightを使用して、要素がいつオーバーフローし始めるかを判別できます。scrollHeightがoffsetHeightよりも大きい場合、フォントサイズが大きすぎます。

二分探索は、このためのはるかに優れたアルゴリズムです。また、実行する反復回数によっても制限されます。単にflexFontを呼び出し、divのIDを挿入し、それが間のフォントサイズを調整します8px96px

私はこのトピックを調査し、さまざまなライブラリを試すのに少し時間を費やしましたが、最終的にはこれが実際に機能する最も簡単で最も簡単なソリューションだと思います。

offsetWidthとを使用するように変更したい場合scrollWidth、または両方をこの関数に追加できることに注意してください。

// Set the font size using overflow property and div height
function flexFont(divId) {
    var content = document.getElementById(divId);
    content.style.fontSize = determineMaxFontSize(content, 8, 96, 10, 0) + "px";
};

// Use binary search to determine font size
function determineMaxFontSize(content, min, max, iterations, lastSizeNotTooBig) {
    if (iterations === 0) {
        return lastSizeNotTooBig;
    }
    var obj = fontSizeTooBig(content, min, lastSizeNotTooBig);

    // if `min` too big {....min.....max.....}
    // search between (avg(min, lastSizeTooSmall)), min)
    // if `min` too small, search between (avg(min,max), max)
    // keep track of iterations, and the last font size that was not too big
    if (obj.tooBig) {
        (lastSizeTooSmall === -1) ?
            determineMaxFontSize(content, min / 2, min, iterations - 1, obj.lastSizeNotTooBig, lastSizeTooSmall) :
                determineMaxFontSize(content, (min + lastSizeTooSmall) / 2, min, iterations - 1, obj.lastSizeNotTooBig, lastSizeTooSmall);

    } else {
        determineMaxFontSize(content, (min + max) / 2, max, iterations - 1, obj.lastSizeNotTooBig, min);
    }
}

// determine if fontSize is too big based on scrollHeight and offsetHeight, 
// keep track of last value that did not overflow
function fontSizeTooBig(content, fontSize, lastSizeNotTooBig) {
    content.style.fontSize = fontSize + "px";
    var tooBig = content.scrollHeight > content.offsetHeight;
    return {
        tooBig: tooBig,
        lastSizeNotTooBig: tooBig ? lastSizeNotTooBig : fontSize
    };
}

ありがとうございます。私はちょうど得ていReferenceError: lastSizeTooSmall is not definedます。多分それはどこかで定義する必要がありますか?
ndbroadbent

0

同じ問題が発生し、解決策は基本的にJavaScriptを使用してフォントサイズを制御することです。コードペンでこの例を確認してください:

https://codepen.io/ThePostModernPlatonic/pen/BZKzVR

これは高さの例であり、幅の場合はいくつかを置く必要があります。

サイズを変更してみてください

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Documento sem título</title>
<style>
</style>
</head>
<body>
<div style="height:100vh;background-color: tomato;" id="wrap">        
  <h1 class="quote" id="quotee" style="padding-top: 56px">Because too much "light" doesn't <em>illuminate</em> our paths and warm us, it only blinds and burns us.</h1>
</div>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
  var multiplexador = 3;
  initial_div_height = document.getElementById ("wrap").scrollHeight;
  setInterval(function(){ 
    var div = document.getElementById ("wrap");
    var frase = document.getElementById ("quotee");
    var message = "WIDTH div " + div.scrollWidth + "px. "+ frase.scrollWidth+"px. frase \n";
    message += "HEIGHT div " + initial_div_height + "px. "+ frase.scrollHeight+"px. frase \n";           
    if (frase.scrollHeight < initial_div_height - 30){
      multiplexador += 1;
      $("#quotee").css("font-size", multiplexador); 
    }
    console.log(message);          
  }, 10);
</script>
</html>

0

私は好きでした

let name = "Making statements based on opinion; back them up with references or personal experience."
let originFontSize = 15;
let maxDisplayCharInLine = 50; 
let fontSize = Math.min(originFontSize, originFontSize / (name.length / maxDisplayCharInLine));

0

contenteditablesのバージョンを追加したかっただけです。

$.fn.fitInText = function() {
  this.each(function() {

    let textbox = $(this);
    let textboxNode = this;

    let mutationCallback = function(mutationsList, observer) {
      if (observer) {
        observer.disconnect();
      }
      textbox.css('font-size', 0);
      let desiredHeight = textbox.css('height');
      for (i = 12; i < 50; i++) {
        textbox.css('font-size', i);
        if (textbox.css('height') > desiredHeight) {
          textbox.css('font-size', i - 1);
          break;
        }
      }

      var config = {
        attributes: true,
        childList: true,
        subtree: true,
        characterData: true
      };
      let newobserver = new MutationObserver(mutationCallback);
      newobserver.observe(textboxNode, config);

    };

    mutationCallback();

  });
}

$('#inner').fitInText();
#outer {
  display: table;
  width: 100%;
}

#inner {
  border: 1px solid black;
  height: 170px;
  text-align: center;
  display: table-cell;
  vertical-align: middle;
  word-break: break-all;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="outer">
  <div id="inner" contenteditable=true>
    TEST
  </div>
</div>


0

テキストを縮小するループの使用を防ぐ方法を見つけました。コンテナの幅とコンテンツの幅の間の比率を乗算することにより、フォントサイズを調整します。したがって、コンテナの幅がコンテンツの1/3の場合、font-sizeは1/3だけ減少し、コンテナの幅になります。スケールアップするために、コンテンツがコンテナーより大きくなるまで、whileループを使用しました。

function fitText(outputSelector){
    // max font size in pixels
    const maxFontSize = 50;
    // get the DOM output element by its selector
    let outputDiv = document.getElementById(outputSelector);
    // get element's width
    let width = outputDiv.clientWidth;
    // get content's width
    let contentWidth = outputDiv.scrollWidth;
    // get fontSize
    let fontSize = parseInt(window.getComputedStyle(outputDiv, null).getPropertyValue('font-size'),10);
    // if content's width is bigger than elements width - overflow
    if (contentWidth > width){
        fontSize = Math.ceil(fontSize * width/contentWidth,10);
        fontSize =  fontSize > maxFontSize  ? fontSize = maxFontSize  : fontSize - 1;
        outputDiv.style.fontSize = fontSize+'px';   
    }else{
        // content is smaller than width... let's resize in 1 px until it fits 
        while (contentWidth === width && fontSize < maxFontSize){
            fontSize = Math.ceil(fontSize) + 1;
            fontSize = fontSize > maxFontSize  ? fontSize = maxFontSize  : fontSize;
            outputDiv.style.fontSize = fontSize+'px';   
            // update widths
            width = outputDiv.clientWidth;
            contentWidth = outputDiv.scrollWidth;
            if (contentWidth > width){
                outputDiv.style.fontSize = fontSize-1+'px'; 
            }
        }
    }
}

このコードは、Github https://github.com/ricardobrg/fitText/にアップロードしたテストの一部です


0

私はgeekMonkeyソリューションを使いましたが、遅すぎます。彼は、フォントサイズを最大(maxFontPixels)に調整し、それがコンテナー内に収まるかどうかを確認しています。それ以外の場合は、フォントサイズを1ピクセル縮小して、再度チェックします。前のコンテナの高さを確認してその値を送信しないのはなぜですか?(はい、私は理由を知っていますが、私は今解決策を作りました、それは高さでのみ機能し、最小/最大オプションもあります)

これははるかに迅速な解決策です:

var index_letters_resize;
(index_letters_resize = function() {
  $(".textfill").each(function() {
    var
      $this = $(this),
      height = Math.min( Math.max( parseInt( $this.height() ), 40 ), 150 );
    $this.find(".size-adjust").css({
      fontSize: height
    });
  });
}).call();

$(window).on('resize', function() {
  index_letters_resize();
);

これはHTMLになります。

<div class="textfill">
  <span class="size-adjust">adjusted element</span>
  other variable stuff that defines the container size
</div>

繰り返しますが、このソリューションではコンテナの高さのみをチェックします。そのため、この関数は、要素が内部に収まるかどうかを確認する必要がありません。しかし、私は最小/最大値(40min、150max)も実装したので、これは完璧に機能します(ウィンドウのサイズ変更でも機能します)。


-1

このソリューションの別のバージョンを次に示します。

shrinkTextInElement : function(el, minFontSizePx) {
    if(!minFontSizePx) {
        minFontSizePx = 5;
    }
    while(el.offsetWidth > el.parentNode.offsetWidth || el.offsetHeight > el.parentNode.offsetHeight) {

        var newFontSize = (parseInt(el.style.fontSize, 10) - 3);
        if(newFontSize <= minFontSizePx) {
            break;
        }

        el.style.fontSize = newFontSize + "px";
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.