[Jquery] divに収まるようにフォントをサイズ変更する(1行で)



Answers

私は同様の問題を抱えていました。これにより、私自身のプラグインを作成しました。 jquery-quickfit (これは、私が本当に好きなRobert Koritnikのソリューションに非常に似ています)を見てください。

見出しが複数の行にまたがるのを防ぐには、次のCSSスタイルを追加するだけです。

white-space:nowrap;

要素に。

ヘッダーにjqueryとquickfitを追加した後。 次の方法でクイックフィットを起動できます。

$('h1').quickfit();

これは、テキストの各文字のサイズ不変のmeassureを測定して計算し、これを使用してテキストをコンテナに収める次の最良のフォントサイズを計算します。

計算はキャッシュされているので、複数のテキストに適合させる必要がある場合や、ウィンドウのサイズ変更(サイズ変更時にパフォーマンス上の不利益はほとんどありません)など、テキストを複数回挿入する必要がある場合には非常に高速です。

あなたと同様の状況のデモ

さらに詳しいドキュメンテーション、サンプル、ソースコードはプロジェクトページにあります。

Question

同様の質問がありましたが、解決策は私がしようとしていることと絡み合っています。 基本的には、タイトル( <h1> )の記事があります。 タイトルの長さをコントロールしたくないのですが、複数の行にタイトルを表示させたくありません。 <div>タグの幅に基づいてテキストのサイズを変更するCSSまたはjQueryの方法はありますか?

私は<div>端にテキストの重なりを検出できれば、私が擬似コードで何をするのか知っています:

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

もし私が設定できるCSS属性があれば、それはもっと良いでしょうが、私はそれを見つけることができません(オーバーフローはこの状況ではうまくいかないでしょう)。




私はそこにある他の解決策に恋していなかったので、ここに別の解決策があります。 それはあなたの中でテキストのサイズを変更しているタグが必要です:

  1. 固定された高さ

  2. それは10pxで限界を超えてしまうほど長くはありません。つまり、あなたはそれを下回るようにしてテキストをサイズ変更できないようにすることは望ましくありません。 私たちのユースケースでは問題ではありませんが、可能であれば、これを実行する前に別々に切り捨てることを考えてください。

バイナリ検索を使用して最適なサイズを見つけるので、他の多くのソリューションより優れていると思われます。また、ピクセル単位でフォントサイズをステップダウンするだけです。 今日のほとんどのブラウザでは、フォントサイズの小数点もサポートされています。このスクリプトは、それが比較的長い小数であっても、最良の答えの0.1px以内になるので、そこにいくつかの利点があります。 max - fontSize < .1max - fontSize < .1以外の値に簡単に変更して、より少ないCPU使用量で精度を.1ことができます。

使用法:

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




@クロービスはあなたの答えに感謝します。 それは私にとって非常に便利です。 残念なことに、投票だけではなく、あなたに感謝することはできません。

注:私は "$ 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));
    }
  };

PS:これはコメントでなければならないことは分かっていますが、コメントでコードを適切に投稿することはできません。




私の解決策は、 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());
    });
}

これにより、実際に重要なプロパティを継承する一時的なスパンが作成され、幅の差が比較されます。 確かに、whileループは最適化される必要があります(2つのサイズの間で計算されたパーセンテージの差を減らす必要があります)。

使用例:

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



非常に簡単です。 テキストのスパンを作成し、幅を取得し、幅が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); 
}



私は、この質問がかなり徹底的に答えられたようだが、ここでの解決策が他の問題を引き起こす可能性があるいくつかの例があることを理解する。 例えば、tkahnのライブラリは非常に有用であるように見えましたが、それが添付された要素の表示を変更しました。これは問題になります。 私の場合は、縦と横の両方のテキストのセンタリングを妨げていました。 いくつか混乱して実験した後、親要素の属性を変更することなく、テキストを1行に収めるためのjQueryを含む簡単なメソッドを思いつきました。 このコードでは、whileループを最適化するためのRobert Koritnikの提案を使用しました。 このコードを使用するには、 "font_fix"クラスを1行に収める必要のあるテキストを含むdivに追加するだけです。 ヘッダーの場合、ヘッダーの周りに余分なdivが必要な場合があります。 次に、固定サイズのdivに対してこの関数を1回呼び出すか、サイズを変更するためにサイズ変更および/または方向リスナーに設定します。

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内に集中させることです。 これは、内部divクラスに以下のようにCSS属性を追加することで簡単に行うことができます:

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

これが誰かを助けたと願っています!




Links