Sabit boyutlu kapsayıcıyı doldurmak için otomatik boyutlu dinamik metin


312

Kullanıcı girilen metni sabit boyutlu bir div görüntülemek gerekiyor. Ne istiyorum metin kutusu mümkün olduğunca doldurur, böylece yazı tipi boyutu otomatik olarak ayarlanması içindir.

Yani - div 400 piksel x 300 piksel ise. Birisi ABC'ye girerse, o zaman gerçekten büyük yazı tipidir. Paragraf girerse, küçük bir yazı tipi olur.

Muhtemelen maksimum yazı tipi boyutu ile başlamak istiyorum - belki 32 piksel ve metin kabı sığmayacak kadar büyük olsa da, yazı tipi boyutunu sığacak kadar küçültün.


119
Muhtemelen HTML5 / CSS3'e JS gerekmeden eklenmesi gereken en şaşırtıcı özellikler.
John Magnolia

Dinamik bir metnin uzunluğunu ve konteynerin boyutunu değiştirdiğim bazı ölçümler yaptım ve hangi yazı tipi boyutunun metnin mükemmel bir şekilde sığacağını anlamak için. Ve bazı regresyon analizi yaptıktan sonra, otomatik olarak en iyi yazı tipi boyutunu oluşturacak basit bir matematiksel fonksiyon geliştirdim.
Kim

2
Aslında size en iyi yazı tipi boyutunu veren grafiğin f (x) = g (harfler) * (x / 1000) ^ n tarafından verildiği, burada g (x) basit bir işlev olduğu için n, kullandığınız yazı tipi. (Tüm fontlar için standart bir değere sahip olsa da, kesinlikle mükemmel olmasını sağlamak için ayarlamak istemiyorsanız ...). x, kabın kare piksel cinsinden boyutudur.
Kim

1
Eğer hala ilgileniyorsanız, bir cevap ekleyebilirim. Şahsen ben ilk etapta doğru yazı tipi boyutu oluşturmak için daha iyi bir yöntem olduğunu düşünüyorum, yerine "doğru olsun" komut dosyası kadar başarısız ve denemek.
Kim

1
Bunu yapmanın daha iyi bir yolu için cevabımı kontrol et
Hoffmann

Yanıtlar:


167

Teşekkürler Saldırı . JQuery kullanmak istedim.

Beni doğru yöne doğrulttun, ben de bununla sonuçlandım:

İşte eklentiye bir bağlantı: https://plugins.jquery.com/textfill/
Ve kaynağa bir bağlantı: 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 });
});

ve html'im böyle

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

Bu benim ilk jquery eklentim, bu yüzden olması gerektiği kadar iyi değil. İşaretçiler kesinlikle bekliyoruz.


8
Aslında sadece en jquery.com onu temizlemiş ve bir eklentisi mevcut olarak paketlenmiş plugins.jquery.com/project/TextFill
GeekyMonkey

3
@GeekyMonkey, eklentiyi çektiniz mi? Sadece bu sayfaya bir dupe bağlantısı izledi ve bir göz olacağını düşündüm, ancak jQuery.com sitenize dönüş bağlantıları 404.
David, Monica

Not: Herhangi bir nedenle bu eklentinin yalnızca yukarıdaki örnekte div ($ ('. Jtextfill')) kök belgenin bir parçası olduğunda çalıştığını gördüm. Div diğer div'lerin içine gömüldüğünde .width () sıfırı verir.
Jayesh

1
Bu döngüdeki "while" satırı bana yanlış görünüyor - "||" etrafında parantez olmalı subexpression. Şimdi yazıldığı gibi, minimum yazı tipi boyutu yalnızca yükseklik değil genişlik çok büyük olduğunda kontrol edilir.
Sivri

4
Bu yaklaşım ÇOK yavaştır, font her boyut değiştirdiğinde öğenin yeniden oluşturulmasını gerektirir. Bunu yapmanın daha iyi bir yolu için cevabımı kontrol et.
Hoffmann

52

Önceki çözümlerden hiçbirinin kötü performans nedeniyle yeterli olduğunu bulamadım, bu yüzden döngü yerine basit matematik kullanan kendi çözümümü yaptım. Tüm tarayıcılarda da iyi çalışmalıdır.

Bu performans testi durumuna göre, burada bulunan diğer çözümlerden çok daha hızlıdır.

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

Eğer katkıda bulunmak istiyorsanız bunu Gist'e ekledim .


1
@Jon, teşekkürler! Senaryomun birden fazla satır yapmadığından haklısın, ama sonra tekrar OP özellikle bunu talep etmediği için varsayımın yanlış olabilir. Ayrıca, bu tür bir davranış imo anlamına gelmez. Ben çok satırlı destek eklemek için en iyi yolu kelime miktarına göre dizeyi bölmek ve daha sonra yukarıdaki komut dosyası ile her parçayı hesaplamak ve herhalde daha hızlı olurdu sanırım.
mekwall

4
@Jon, çok satırlı metin doldurma ile biraz oynadım ve bu çözüm ile sona erdi . sandstorm'un yöntemi büyük olasılıkla daha doğrudur, ancak bu daha hızlıdır;)
mekwall

2
İşte minimum yazı tipi boyutunun yanı sıra maksimum olan bir sürüm: gist.github.com/1714284
Jess Telford

1
@Hoffmann Hmm. Çözümüm .css("font-size")bir döngüde çağırmıyor. Bunu nereden aldın? Eklentinize eklediğiniz süslü şeylerden hiçbirine sahip olmadığından çözümüm muhtemelen daha hızlı. Eklentinizi jsperf'e eklemeye hoş geldiniz ve hangisinin en hızlı olduğunu göreceğiz;)
mekwall

1
@MarcusEkwall Üzgünüm, nedense orada bir süre döngü gördüm. Yaklaşımınız benimkine benzer ve eklentim de başka şeyler yapıyor (hem yükseklik hem de genişliğe uyum sağlamak, metni ve diğer seçenekleri merkezileştirmek gibi), bu önemli değil, gerçekten yavaş kısım bir döngü içinde .css işlevini çağırıyor.
Hoffmann

35

Bu cevap için aldığım ara sıra upvote'ları sevdiğim kadar (teşekkürler!), Bu gerçekten bu soruna en büyük yaklaşım değil. Lütfen buradaki diğer harika cevaplara, özellikle de döngüsüz çözümler bulanlara göz atın.


Yine de, referans uğruna, benim orijinal cevabım :

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

Ve burada sınıfları olan bir versiyon :

<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
Bunun daha iyi çalıştığını offsetWidthgördüm, ayrıca boyut için bir değişken oluşturmak ve sonra px eklemek zorunda kaldımtextSpan.style.fontSize = size+"px";
Wez

2
"+" px "" gerektiğinden emin olun.
sandun dhammika

@IdanShechter Uzun, çok beklediğim için özür dilerim! Bir örnek eklendi!
Saldırı

Teşekkür ederim hayat kurtarıcı!
JQuery'nin

32

Diğer yanıtların çoğu, div'a sığana kadar yazı tipi boyutunu azaltmak için bir döngü kullanır; bu, yazı tipinin boyutu her değiştiğinde sayfanın öğeyi yeniden oluşturması gerektiğinden ÇOK yavaştır. Sonunda, kullanıcı tarayıcısını dondurmadan içeriğini düzenli olarak güncellememe izin verecek şekilde yapmak için kendi algoritmamı yazmak zorunda kaldım. Başka bir işlevsellik ekledim (metin döndürme, dolgu ekleme) ve bir jQuery eklentisi olarak paketledim, şu adresten alabilirsiniz:

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

sadece ara

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

ve kabınıza güzel uyacak.

Buraya çalışırken bakın:

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

Şimdilik bazı sınırlamaları var, div sabit bir yüksekliğe ve genişliğe sahip olmalı ve metni birden çok satıra kaydırmayı desteklemiyor.

Maksimum yazı tipi boyutunu ayarlamak için bir seçenek elde etmeye çalışacağım.

Düzenleme: Eklenti ile ilgili bazı sorunlar buldum, standart olanın yanı sıra diğer kutu modelini işlemez ve div kenar boşlukları veya kenarlıklar olamaz. Üstünde çalışacağım.

Edit2: Şimdi bu sorunları ve sınırlamaları düzelttim ve daha fazla seçenek ekledim. Maksimum yazı tipi boyutunu ayarlayabilir ve genişlik, yükseklik veya her ikisini birden kullanarak yazı tipi boyutunu sınırlamayı seçebilirsiniz. Sarıcı öğesinde bir maksimum genişlik ve maksimum yükseklik değerlerini kabul etmeye çalışacağım.

Edit3: Eklentiyi 1.2.0 sürümüne güncelledim. Kodda büyük temizleme ve yeni seçenekler (verticalAlign, horizontalAlign, textAlign) ve yayılma etiketi içindeki iç öğeler için destek (satır kesmeleri veya font harika simgeleri gibi).


1
Neden birden fazla satıra metin sarma desteklenmiyor merak ediyorum?
Manish Sapariya

1
@ManishSapariya Desteklenir, ancak satır sonlarını (br etiketleri) manuel olarak eklemeniz gerekir. Otomatik metin kaydırmayı desteklemememin nedeni, hızlı yapmak (yalnızca yazı tipi boyutunu birden çok kez yerine iki kez değiştirmek) çünkü metnin kelimeler arasında sarılmayacağı varsayımını yapmam gerekiyor. Eklentimin çalışma şekli yazı tipi boyutunu 1000 piksel olarak ayarlamak, ardından metnin kapla karşılaştırıldığı boyut faktörünü görmek, daha sonra yazı tipi boyutunu aynı faktörle küçültmek. Normal metin kaydırmayı desteklemek için çok yavaş olan yavaş yaklaşımı (yazı tipi boyutunu birkaç kez küçültmek) kullanmam gerekir.
Hoffmann

Hey! Burada özel bir mesaj olmadığından, StackOverflow'da, cevabınıza yorum yaparak sizden sormam gerekecek. JQuery eklentinizi seviyorum, ancak benim için çalışmaya başlayamıyorum. Doğru jQuery kütüphanesini ekledim, eklentinizi indirdim ve ekledim. Şimdi denediğimde ve kullandığımda, konsol 'Uncaught TypeError: undefined bir işlev değil' diyor. Bu aşina olduğunuz bir şey mi? Bunu nasıl düzeltebileceğinizi biliyor musunuz? Teşekkürler
Gust van de Wal

@GustvandeWal Jquery kütüphanesini ekledikten sonra eklentiyi eklemeniz gerekiyor
Hoffmann

Yaptım. <Script type = "text / javascript" src = " code.jquery.com/jquery-2.1.1.min.js"></… src" js / jquery-bigtext.js "> </ script > Tarayıcı bana jQuery kütüphanesini veya eklentisini yükleyemediğini bildirmiyor.
Gust van de Wal

9

Bu, GeekyMonkey'in bazı değişikliklerle birlikte yayınladıklarına dayanmaktadır.

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

fark, birden çok alt öğeyi alabilmesi ve doldurmayı dikkate almasıdır. Javascript ve css karıştırmayı önlemek için yazı tipi boyutunu varsayılan maksimum boyut olarak kullanır.
sandstrom

5
Bu harika, ama nasıl kullanırım? $ ('. Dış'). Textfill (); ve hiçbir değişiklik almıyorum.
Drew Baker

3
Teşekkürler, bu çok güzel bir uygulama. Karşılaştığım bir şey var: Çok uzun metin dizeleri ve çok dar kaplarla uğraşıyorsanız, metin dizesi kaptan dışarı yapışır, ancak externalWidth yine de yokmuş gibi hesaplanır. "Word-wrap: sonu-sözcük;" söz konusu kapsayıcı için CSS'nize girdiğinizde bu sorun çözülür.
Jon

8

Burada, mümkün olan en az adımda üst öğeye sığabilecek en büyük boyutu bulmak için ikili aramayı kullanan gelişmiş bir döngü yöntemi vardır (bu, sabit yazı tipi boyutuna basmaktan daha hızlı ve daha doğrudur). Kod ayrıca performans için çeşitli şekillerde optimize edilmiştir.

Varsayılan olarak, en uygun boyutun% 0,1'ini alacak 10 ikili arama adımı gerçekleştirilir. Bunun yerine en uygun boyutun 1/2 ^ N'sine ulaşmak için numIter değerini N değerine ayarlayabilirsiniz.

Bir CSS seçici ile çağırın, örneğin: 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);
        }
    });
};

Bu seçeneği seviyorum. Ben parametrelerini eklemek için modifiye vAlignve padding. vAlign == trueseçili öğenin çizgi yüksekliğini ebeveyn yüksekliğine ayarlar. Dolgu, nihai boyutu geçirilen değer kadar azaltır. Varsayılan 5'tir. Bence gerçekten güzel görünüyor.
Şeytan'ın Avukatı

6

AngularJS için bir direktif oluşturdum - GeekyMonkey'in cevabından çok esinlenerek ama jQuery bağımlılığı olmadan.

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

Biçimlendirme

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

Direktif

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

Bununla ilgili yaşadığım bir sorun resizeText, ng-bindaslında öğeye metin atamadan önce çağrılıyor gibi görünüyor , bu da geçerli metinden ziyade önceki metne göre boyutlandırılıyor. Bu, kullanıcı türleri olarak tekrar tekrar çağrıldığı yukarıdaki demoda çok kötü değil, ancak bir kez boş değerden gerçek değere (tek yönlü bir bağlamada olduğu gibi) geçilirse maksimum boyutta kalır.
Miral

5

Yukarıdaki senaryoyu Marcus Ekwall'dan çatalladım: https://gist.github.com/3945316 ve tercihlerime göre ayarladım , şimdi pencere yeniden boyutlandırıldığında patlıyor, böylece çocuk her zaman kabına uyuyor. Referans için aşağıdaki komut dosyasını yapıştırdım.

(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
Askerlere yardım etmeye çalışmanız harika. Bununla birlikte, sadece bir bağlantı ile bir cevap bırakmak bazı durumlarda zararlı olabilir. Cevabınız şimdi iyi olsa da, bağlantı hiç ölmeseydi, cevabınız değerini kaybederdi. Bu nedenle, cevabınızdaki makaledeki içeriği özetlemeniz yararlı olacaktır. Açıklama için bu soruya bakın .
Cody Guldner

5

İşte OP'nin cevabını değiştirmem.

Kısacası, bunu optimize etmeye çalışan birçok kişi bir döngü kullanıldığından şikayet etti. Evet, döngüler yavaş olsa da, diğer yaklaşımlar yanlış olabilir.

Bu nedenle, yaklaşımım en iyi Font Boyutunu bulmak için İkili Arama'yı kullanır :

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

Bu, öğenin minimum ve maksimum yazı tipini belirtmesine de izin verir:

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

Ayrıca, bu algoritma birimsizdir. Sen belirtebilirsiniz em, rem, %vb ve onun nihai sonuç için kullanacaktır.

İşte Keman: https://jsfiddle.net/fkhqhnqe/1/


2

Web sitemle aynı sorunu yaşadım. Projektörde, duvarlarda, büyük ekranlarda görüntülenen bir sayfam var.

Yazı tipimin maksimum boyutunu bilmediğim için, @GeekMonkey'in üstündeki eklentiyi tekrar kullandım, ancak yazı tipini artırıyorum:

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

Bu sayfada benim için gerçekten işe yarayan tek eklenti olduğu için +1!
skybondsor

2
Bu eklenti benim için sayfayı kilitliyor.
Jezen Thomas

1

Kabul edilen cevabın bir minFontSize parametresini de alabilecek bir sürümü.

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

teşekkürler, kodun üstünde orada olmaması gereken noktalı virgül olduğunu düşünüyorum
Patrick Moore

1

Sen kullanabilirsiniz FitText.js ( github sayfasınıBu sorunu çözmek ) kullanabilirsiniz. TextFill ile karşılaştırıldığında gerçekten küçük ve verimlidir. TextFill pahalı bir loop kullanır ve FitText kullanmaz.

Ayrıca FitText daha esnektir (çok özel gereksinimleri olan bir şampiyonda kullanıyorum ve şampiyon gibi çalışıyor!).

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>

Ayrıca seçenekler de ayarlayabilirsiniz:

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

CSS:

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

Ve ihtiyacınız varsa, FitText'in ayrıca jQuery sürümüne değildir .


Fittext yüksekliği dikkate alır mı?
Manish Sapariya

1
@ManishSapariya hayır değil. Yalnızca kap genişliğini 10'a böler ve bunu yazı tipi boyutu olarak kullanır.
Dan H

1

DÜZENLE: Bu kod, bir HTML5 videosunun üstünde notlar göstermek için kullanıldı. Video yeniden boyutlandırıldığında (tarayıcı penceresi yeniden boyutlandırıldığında) yazı tipi boyutunu değiştirir. Notlar videoya (tıpkı YouTube'daki notlar gibi) bağlanmıştır, bu nedenle kod DOM tutamacı yerine örnekleri kullanır direkt olarak.

İsteğe bağlı olarak bunu başarmak için kullandığım bazı kodları atacağım. (HTML5 video üzerinden metin kutuları.) Kod uzun zaman önce yazılmıştı ve açıkçası oldukça dağınık olduğunu düşünüyorum. Soru zaten cevaplandığından ve bir cevap çok uzun zaman önce kabul edildiğinden, bunu yeniden yazmaktan rahatsız etmiyorum. Ama eğer birisi bunu biraz basitleştirmek isterse, hoş geldiniz demektir!

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

Muhtemelen bu sayıları yazı tipi ailesinden yazı tipi ailesine ayarlamanız gerekir. Bunu yapmanın iyi bir yolu GeoGebra adlı ücretsiz bir grafik görselleştirici indirmektir. Metnin uzunluğunu ve kutunun boyutunu değiştirin. Ardından boyutu manuel olarak ayarlarsınız. Manuel sonuçları koordinat sistemine çizin. Daha sonra buraya gönderdiğim iki denklemi giriyorsunuz ve "my" grafiğiniz kendi elle çizilen noktalarınıza uyuncaya kadar sayıları düzeltiyorsunuz.


1

Önerilen yinelemeli çözümler iki cephede önemli ölçüde hızlandırılabilir:

1) Yazı tipi boyutunu 1 eklemek veya çıkarmak yerine bir miktar sabitle çarpın.

2) İlk olarak, bir rota sabiti kullanılırken sıfır, örneğin her bir döngünün boyutunu iki katına çıkarın. Daha sonra, nereden başlayacağınıza dair kaba bir fikirle, aynı şeyi daha ince bir ayarlama ile yapın, örneğin 1.1 ile çarpın. Mükemmeliyetçi ideal yazı tipinin tamsayı piksel boyutunu isteyebilir, ancak çoğu gözlemci 100 ile 110 piksel arasındaki farkı fark etmez. Mükemmeliyetçiyseniz, daha ince bir ayarlama ile üçüncü kez tekrarlayın.

Kesin soruyu cevaplayan belirli bir rutin veya eklenti yazmak yerine, sadece temel fikirlere güveniyorum ve div, spans, görüntüler dahil olmak üzere sadece metin değil, her türlü düzen sorununu ele almak için kodun varyasyonlarını yazıyorum. .. genişlik, yükseklik, alan vb.

İşte bir örnek:

  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

Bu yarattığım en zarif çözüm. 10 yineleme yaparak ikili arama kullanır. Naif yol bir while döngüsü yapmak ve eleman taşmaya başlayana kadar yazı tipi boyutunu 1 arttırmaktı. Element.offsetHeight ve element.scrollHeight öğesini kullanarak bir öğenin ne zaman taşmaya başlayacağını belirleyebilirsiniz. . ScrollHeight ofsetHeight'tan büyükse, çok büyük bir yazı tipi boyutunuz vardır.

İkili arama bunun için çok daha iyi bir algoritmadır. Ayrıca, gerçekleştirmek istediğiniz yineleme sayısı ile sınırlıdır. Sadece flexFont'u arayın ve div kimliğini girin ve yazı tipi boyutunu 8px ile 96px arasında ayarlar .

Bu konuyu araştırmak ve farklı kütüphaneleri denemek için biraz zaman harcadım, ama sonuçta bunun gerçekten işe yarayacak en kolay ve en basit çözüm olduğunu düşünüyorum.

Kullanmak değiştirebilir isterseniz Not offsetWidthve scrollWidthveya bu fonksiyona hem ekleyin.

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

Teşekkürler, bu harika görünüyor! Sadece alıyorum ReferenceError: lastSizeTooSmall is not defined. Belki bunun bir yerde tanımlanması gerekir?
ndbroadbent

0

Aynı sorunu var ve çözüm temelde yazı tipi boyutunu denetlemek için javascript kullanmaktır. Kod örneğinde bu örneği kontrol edin:

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

Bu örnek sadece yükseklik içindir, belki genişlikle ilgili ise biraz koymanız gerekir.

yeniden boyutlandırmaya çalış

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

Beğendim

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

Sadece içerikler için sürümümü eklemek istedim.

$.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

Metni küçültmek için döngülerin kullanılmasını önlemenin bir yolunu buldum. Yazı tipi boyutunu, kabın genişliği ile içerik genişliği arasındaki oranı çarparak ayarlar. Bu nedenle, kabın genişliği içeriğin 1 / 3'ü ise, yazı tipi boyutu 1/3 oranında küçültülecek ve kabın genişliği olacaktır. Ölçeklendirmek için, içerik kaptan daha büyük olana kadar bir while döngüsü kullandım.

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

Bu kod, Github'a yüklediğim bir testin parçası https://github.com/ricardobrg/fitText/


0

GeekMonkey çözümü ile gittim, ama çok yavaş. Yaptığı, yazı tipi boyutunu maksimuma (maxFontPixels) ayarlaması ve ardından kabın içine sığıp sığmadığını kontrol etmesi. aksi takdirde font boyutunu 1 piksel azaltır ve tekrar kontrol eder. Neden önceki konteyneri yükseklik için kontrol edip bu değeri göndermiyorsunuz? (evet, nedenini biliyorum, ama şimdi sadece yükseklikte çalışan ve aynı zamanda min / max seçeneği olan bir çözüm yaptım)

İşte çok daha hızlı bir çözüm:

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

ve bu HTML:

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

Tekrar: bu çözüm SADECE kabın yüksekliğini kontrol eder. Bu nedenle, eleman içeriye uyup uymadığını kontrol etmek zorunda değildir. Ama aynı zamanda bir min / maks değeri (40min, 150max) uyguladım, bu yüzden benim için bu gayet iyi çalışıyor (ve aynı zamanda pencere yeniden boyutlandırma üzerinde çalışıyor).


-1

İşte bu çözümün başka bir sürümü:

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";
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.