web-dev-qa-db-fra.com

Texte de l'échelle JavaScript pour s'adapter à une division fixe

Dans JavaScript/jQuery, comment puis-je mettre à l'échelle une ligne de texte de longueur variable à l'intérieur d'une div à largeur fixe de manière à ce que la ligne s'adapte toujours à l'intérieur de la div (en une seule ligne)?

Merci.

51
Stephen Watkins

C'est un peu un bidouillage, mais fera ce que vous voulez.

<div id="hidden-resizer" style="visibility: hidden"></div>

Placez ceci au bas de votre page, où il ne sera pas déplacer d'autres éléments sur la page.

Alors fais ceci:

var size;
var desired_width = 50;
var resizer = $("#hidden-resizer");

resizer.html("This is the text I want to resize.");

while(resizer.width() > desired_width) {
  size = parseInt(resizer.css("font-size"), 10);
  resizer.css("font-size", size - 1);
}

$("#target-location").css("font-size", size).html(resizer.html());
69
sworoc

HTML:

<div class="box" style="width:700px">This is a sentence</div>
<div class="box" style="width:600px">This is a sentence</div>
<div class="box" style="width:500px">This is a sentence</div>
<div class="box" style="width:400px">This is a sentence</div>

JavaScript:

$( '.box' ).each(function ( i, box ) {

    var width = $( box ).width(),
        html = '<span style="white-space:nowrap"></span>',
        line = $( box ).wrapInner( html ).children()[ 0 ],
        n = 100;

    $( box ).css( 'font-size', n );

    while ( $( line ).width() > width ) {
        $( box ).css( 'font-size', --n );
    }

    $( box ).text( $( line ).text() );

});

Démo en direct:http://jsfiddle.net/e8B9j/2/show/

Supprimer "/ show /" de l'URL pour afficher le code.

28
Šime Vidas

J'ai écrit un plugin jQuery pour faire ceci:

http://michikono.github.com/boxfit

Le plugin redimensionnera le texte horizontalement et verticalement jusqu'à la taille maximale disponible à l'intérieur de la zone, puis le centrera.

La seule chose à faire est de définir une div contenant du texte:

<div id="scale">some text</div>

Et puis appelez:

$('#scale').boxfit()

La méthode acceptera certains arguments pour désactiver/activer le retour à la ligne et l'alignement centré.

13
Michi Kono

Pour les nouveaux navigateurs, vous pouvez utiliser Inline-SVG. Cela peut être redimensionné comme une image via CSS ..! (width: 100%;)

6
Benjamin

La plupart des autres réponses utilisent une boucle pour réduire la taille de la police jusqu'à ce qu'elle tienne sur la div. Cette opération est TRES lente, car la page doit restituer l'élément à chaque changement de taille de la police. J'ai finalement dû écrire mon propre algorithme pour le rendre performant de manière à pouvoir mettre à jour périodiquement son contenu sans geler le navigateur de l'utilisateur. J'ai ajouté d'autres fonctionnalités (rotation de texte, ajout de rembourrage) et je l'ai empaqueté comme un plugin jQuery. Vous pouvez l'obtenir à l'adresse suivante:

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

simplement appeler

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

et il ira bien sur votre conteneur.

Voir en action ici:

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

Pour l'instant, il a certaines limites, la div doit avoir une hauteur et une largeur fixes et ne prend pas en charge le texte enveloppant sur plusieurs lignes.

Edit2: J'ai maintenant corrigé ces problèmes et limitations et ajouté plus d'options. Vous pouvez définir une taille de police maximale et vous pouvez également choisir de limiter la taille de la police à l'aide de la largeur, de la hauteur ou des deux (par défaut, les deux). Je vais travailler à accepter les valeurs max-width et max-height dans l'élément wrapper.

5
Hoffmann

Je ne connais pas de manière exacte, mais voici une approximation:

var factor = 1/3;  // approximate width-to-height ratio
var div = $('#mydiv');
div.css('font-size', div.width() / (div.text().length * factor) + 'px');

Vous devrez ajuster factor en fonction de la police que vous utilisez. 1/3 semble bien fonctionner pour Times New Roman.

3
casablanca
2
testere

Dans votre div, placez le texte dans une étendue sans remplissage. La largeur de la plage correspondra alors à la longueur du texte.
Code non testé pour trouver la taille de police correcte à utiliser:

var objSpan = $('.spanThatHoldsText');  
var intDivWidth = $('.divThatHasAFixedWidth').width();  
var intResultSize;  

for (var intFontSize = 1; intFontSize < 100; intFontSize++)  

  objSpan.css('font-size', intFontSize);  

  if (objSpan.width() > intDivWidth) {  
    intResultSize = intFontSize - 1;  
    break;  
  }  

}

objSpan.css('font-size', intResultSize);
2
EmKay

Version modifiée de @sworoc avec le support de la classe cible

function resizeText(text, size, target) {

    var fontSize = 0;
    var resizer = $('<span>');

    resizer.html(text).hide();
    resizer.attr('class', target.attr('class'));
    $('body').append(resizer);

    while(resizer.width() < size) {
        fontSize++
        resizer.css("font-size", fontSize);
    }

    target.css('font-size', fontSize).html(text);
    resizer.remove();
}

Usage

resizeText("@arunoda", 350, $('#username'));
2

Voici une solution coffeescript que je suis venu avec. Je clone l'élément qui nécessite le redimensionnement de la police, puis le retire à la fin du calcul. Pour augmenter les performances, j'ai un code qui exécute le calcul uniquement après que le redimensionnement se soit arrêté pendant 200 ms.

Marquez les éléments avec la classe autofont pour que cela se fasse de manière non dissimulée. 

# 
# Automagically resize fonts to fit the width of the 
# container they are in as much as possible. 
#
fixfonts = ->

  scaler = 1.2

  for element in $('.autofont')

    size =  1
    element = $(element)
    desired_width = $(element).width()

    resizer = $(element.clone())
    resizer.css
      'font-size': "#{size}em"
      'max-width': desired_width
      'display': 'inline'
      'width': 'auto'
    resizer.insertAfter(element)

    while resizer.width() < desired_width
      size = size * scaler
      resizer.css
        'font-size':  "#{size}em"

    $(element).css
        'font-size': "#{size / scaler }em"

    resizer.remove()

$(document).ready =>
  fixfonts()

  timeout = 0
  doresize = ->
    timeout--
    if timeout == 0
      fixfonts()

  $(window).resize ->
    timeout++
    window.setTimeout doresize, 200
2
bradgonesurfing

J'ai eu un problème similaire, ce qui m'a fait écrire mon propre plugin pour cela. Une solution consiste à utiliser la méthode du retrait sur ajustement décrite ci-dessus. Cependant, si vous devez adapter plusieurs éléments ou si vous êtes préoccupé par les performances, par exemple, lors du redimensionnement d’une fenêtre, consultez jquery-quickfit .

Il mesure et calcule une taille invariante par taille pour chaque lettre du texte à adapter et l'utilise pour calculer la taille de police optimale suivante qui s'adapte au texte dans le conteneur.

Les calculs sont mis en cache, ce qui le rend très rapide (il n’ya pratiquement aucune perte de performance dès le 2e redimensionnement par la suite) lorsqu’il faut traiter plusieurs textes ou qu’il faut ajuster un texte plusieurs fois, comme par exemple lors du redimensionnement d’une fenêtre.

Exemple de production, adaptant des textes 14x16x2

1
chunks_n_bits

Voici ma modification à la suggestion de @ teambob (dans commentaires ci-dessus ) qui prend également en compte la hauteur du conteneur: 

<div class="box" style="width:700px; height:200px">This is a sentence</div>
<div class="box" style="width:600px; height:100px">This is a sentence</div>
<div class="box" style="width:500px; height:50px">This is a sentence</div>
<div class="box" style="width:400px; height:20px">This is a sentence</div>

Et alors..

$('.box').each(function(i, box) {

    var width = $(box).width(),
        height = $(box).height(),
        html = '<span style="white-space:nowrap">',
        line = $(box).wrapInner(html).children()[0],
        maxSizePX = 2000;

    $(box).css('font-size', maxSizePX);
    var widthFontSize = Math.floor(width/$(line).width()*maxSizePX),
        heightFontSize = Math.floor(height/$(line).height()*maxSizePX),
        maximalFontSize = Math.min(widthFontSize, heightFontSize, maxSizePX);

    $(box).css('font-size', maximalFontSize);
    $(box).text($(line).text());

});

Voir Fiddle

1
Ville

J'ai fait (encore) un autre plugin pour résoudre ce problème:

https://github.com/jeremiahrose/perfectFit.js

Il génère des fichiers SVG, il est donc très rapide - il ne s'exécute qu'une fois au chargement de la page. Capable d'emballer et de redimensionner automatiquement des mots individuels pour qu'ils correspondent exactement à une div.

1
Jeremiah Rose

Je ne comprenais pas comment ajouter ceci au message de sworoc mais je pensais partager quoi qu'il en soit: La solution de Lonesomeday est foirée si vous utilisez une sorte de navigation AJAX. Je l'ai légèrement modifié pour:

if ($('#hidden-resizer').length == 0){ 
    $('<div />', {id: 'hidden-resizer'}).hide().appendTo(document.body); 
}
1
deweydb

Voici ma solution: je mesure le texte dans une nouvelle div au sein de la div fournie, de sorte que le style doit être hérité. Ensuite, j'insère le texte dans la div avec une étendue pour définir la taille de la police. La taille de police par défaut sera au maximum, mais la taille sera réduite.

Il ne boucle pas: il dessine le texte une seule fois dans un div jetable avant de dessiner directement vers le div fourni. Voir la réponse de @Hoffmann - Je n'ai simplement pas aimé qu'un "plugin" complet réponde à la question.

nécessite jquery.

var txt = txt || {}
txt.pad_factor = 1.1;
txt.insertText_shrinkToFit = function(div,text)
{
  var d = txt.cache || $('<div></div>');
  txt.cache = d;

  d.css('white-space','nowrap');
  d.css('position','absolute');
  d.css('top','-10000px');
  d.css('font-size','1000px');

  var p = $(div);
  var max_w = parseInt(p.css('max-width')) || p.width();
  var max_h = parseInt(p.css('font-size'));

  p.append(d);
  d.html(text);
  var w = d.width() * txt.pad_factor; 
  d.remove();

  var h = Math.floor(max_w*1000/w);
  var s = ( max_h < h ? max_h : h ) + "px";

  p.html('<SPAN style="font-size:' + s + '">' + text + '</SPAN>');
}

Par exemple:

<html><head><script src=http://code.jquery.com/jquery-latest.min.js></script>
<script>/*insert code, from above, here.*/</script></head><body>

<div id=mysmalldiv style="max-width:300px;font-size:50px"></div>
<script>
  txt.insertText_shrinkToFit("#mysmalldiv","My super long text for this div.");
</script>

</body></html>

Pour tester: voici comment j'ai découvert que j'avais besoin du pad_factor 1.1; que vous pouvez accorder à vos besoins.

<div id=mytestdiv style="max-width:300px;font-size:50px"></div>
<script>
  var t = "my text ";
  var i = 0;
  var f = function() {
    t += i + " ";
    txt.insertText_shrinkToFit("#mytestdiv",t);
    i++;
    if(i < 100) 
      setTimeout(f,1000);
  }
  f();
</script>

Remarque: ceci suppose une taille de police px. Je n'ai pas testé avec em ou pt.

0
JJ Stiff

vous pouvez faire plusieurs choses comme

overflow:hidden

cela coupe la ligne supplémentaire

overflow:auto // affiche la barre de défilement

regarde ça

http://www.w3schools.com/Css/pr_pos_overflow.asp

essayez de le faire//cochez la longueur du texte

if($('#idfortext').length>sometthing)
{
var fontsize=10;
}
$('#yourid').css('font-size',fontsize)
0
kobe

Il existe un excellent moyen de faire cela pour les textes simples, comme les en-têtes et autres, en CSS pur:

h1{
    font-size: 4.5vw;
    margin: 0 0 0 0;
    line-height: 1em;
    height: 1em;
}

h1:after{
    content:"";
    display: inline-block;
    width: 100%;
}

Assurez-vous que votre taille de police reste suffisamment petite pour que l'en-tête conserve 1 ligne. L'utilisation de 'vw' (largeur de la fenêtre d'affichage) au lieu de 'px' facilite grandement la tâche et la mise à l'échelle en même temps. La largeur de la fenêtre d'affichage a tendance à être désagréable lorsque la fenêtre de votre navigateur est très grande. De nombreux sites l'utilisent pour conserver le site sous une certaine largeur sur des écrans très larges:

body{
   max-width: 820px;
   margin: 0 auto;
}

Pour vous assurer que votre police n'est pas basée sur la taille de la fenêtre de visualisation une fois que le reste de votre site a cessé de fonctionner, utilisez ceci:

@media(min-width:820px){
   h1{
      font-size: 30px; 
   }
}
0
patrick

Je ne suis pas sûr qu'il existe un moyen précis de mesurer la largeur du texte en pixels (ce que vous recherchez réellement à la racine de votre problème), car chaque navigateur peut afficher les polices différemment. Vous voudrez peut-être essayer d’utiliser ce code CSS, en plus de procéder à un redimensionnement "flou" en fonction du nombre de lettres de la phrase. Vous pouvez essayer d’utiliser une police (ou un style) à largeur fixe pour afficher le texte de sorte que chaque caractère occupe la même quantité d’espace. De cette façon, vous pouvez deviner, et le CSS vous donnera au moins un joli "..." avant de recadrer le texte, si nécessaire.

.truncate 
{ 
    overflow: hidden; 
    white-space: nowrap; 
    text-overflow: Ellipsis; 
} 
0
Dutchie432

plugin pour s'adapter à la largeur et à la hauteur d'un conteneur

http://blissitec.github.io/scaletextjs/

0
Stevanicus

Voici ce que j'ai trouvé aujourd'hui:

  1. Définir une taille de police (f) très grande sur le texte cible
  2. mesurez la largeur (w) hauteur (h) du conteneur de texte et divisez-la par la taille de la police (f): 

    • iw = w/f
    • ih = h/f
  3. Divisez la largeur du conteneur principal (W) par iw et la hauteur du conteneur principal (H) par ih:

    • kw = W/iw
    • kh = H/ih
  4. Choisissez le plus bas entre kw et kh: il s’agit de la taille de police souhaitée.

https://jsfiddle.net/pinkynrg/44ua56dv/

function maximizeFontSize($target) {

  var testingFont = 1000;
    $target.find(".text-wrapper").css("font-size", testingFont+"px");

  var textWidth = $(".text-wrapper").width()/1000;
  var textHeight = $(".text-wrapper").height()/1000;
  var width = $(".container").width();
  var height = $(".container").height();

  var kWidth = width/textWidth;
  var kHeight = height/textHeight;
  var fontSize = kWidth < kHeight ? kWidth : kHeight;

  // finally
  $(".text-wrapper")
    .css("font-size", fontSize+"px")
    .css("line-height", height+"px");
}
0
pnknrg

J'ai travaillé sur quelques posts ici et en ai fait un plugin jQuery. J’ai trouvé que partir du bas vers le haut et monter n’était pas très performant, j’imagine donc que la taille de la police actuelle est proche et qu’elle fonctionne à partir de là.

  $.fn.fitTextToWidth = function(desiredWidth) {
    // In this method, we want to start at the current width and grow from there, assuming that we are close to the desired size already.
    var $el = $(this);
    var resizer = $('<'+$el.get(0).tagName+' />').css({'vsibility':'hidden','position':'absolute','left':'-9999px','display':'inline'}).html($el.html());
    resizer.appendTo(document.body);

    var size = parseInt($el.css('font-size'));
    resizer.css('font-size',size+'px');

    var growing = desiredWidth > resizer.width() ? true : false;
    var adder = growing ? 1 : -1;
    do {
        size += adder;
        resizer.css('font-size',size+'px');
    } while(((growing && resizer.width()<desiredWidth) || (!growing && resizer.width()>desiredWidth)) && size>10 && size<100);
    if (growing)
        size -= 2; //we never want to go over
    resizer.remove();

    $el.css('font-size',size+'px'); 
  }

  // Example use:
  $('#main h1').fitTextToWidth(350);

Le seul inconvénient avec cela est qu'il suppose que le code CSS de l'élément est global et ne s'applique qu'au type d'élément. En d'autres termes, il crée une balise du même nom et suppose qu'il aura les mêmes attributs CSS que l'élément à modifier. Si ce n'est pas le cas, modifiez simplement la ligne où resizer est créé.

0
Cory Gagliardi