Réduire la taille de la police à un utilisateur pour s'adapter à une entrée en utilisant Javascript

Le MobileMe d'Apple utilise javascript pour modifier la taille de la police dans la connexion par courrier électronique sur sa page d'accueil à mesure que l'utilisateur tape pour que le texte corresponde toujours à l'espace disponible sans défilement de débordement.

Bien que je puisse voir comment exécuter une fonction sur chaque pression de touche, je suis curieux de savoir comment on peut calculer la taille de la police à chaque fois afin qu'elle corresponde toujours au champ de saisie. Existe-t-il un moyen de mesurer la longueur d'un morceau de texte avec une police à largeur variable? Comment accomplissent cet effet?

Essayez-le pour voir ce que je veux dire: http://www.me.com/

Je l'ai fait dans le passé en utilisant jQuery. Vous pouvez mesurer la taille d'un morceau de texte comme ceci:

// txt is the text to measure, font is the full CSS font declaration, // eg "bold 12px Verdana" function measureText(txt, font) { var id = 'text-width-tester', $tag = $('#' + id); if (!$tag.length) { $tag = $('<span id="' + id + '" style="display:none;font:' + font + ';">' + txt + '</span>'); $('body').append($tag); } else { $tag.css({font:font}).html(txt); } return { width: $tag.width(), height: $tag.height() } } var size = measureText("spam", "bold 12px Verdana"); console.log(size.width + ' x ' + size.height); // 35 x 12.6 

Pour s'adapter à un espace donné, c'est un peu plus délicat – vous devez séparer la déclaration de la font-size la font-size et l'étaler de manière appropriée. Selon la façon dont vous faites les choses, cela pourrait être plus facile si vous gérez les différentes parties de la déclaration de la font . Une fonction de redimensionnement pourrait ressembler à ceci (encore une fois, évidemment, cela dépend de jQuery):

 function shrinkToFill(input, fontSize, fontWeight, fontFamily) { var $input = $(input), txt = $input.val(), maxWidth = $input.width() + 5, // add some padding font = fontWeight + " " + fontSize + "px " + fontFamily; // see how big the text is at the default size var textWidth = measureText(txt, font).width; if (textWidth > maxWidth) { // if it's too big, calculate a new font size // the extra .9 here makes up for some over-measures fontSize = fontSize * maxWidth / textWidth * .9; font = fontWeight + " " + fontSize + "px " + fontFamily; // and set the style on the input $input.css({font:font}); } else { // in case the font size has been set small and // the text was then deleted $input.css({font:font}); } 

Vous pouvez voir ceci en action ici: http://jsfiddle.net/nrabinowitz/9BFQ8/5/

Les tests semblent montrer que c'est un peu nerveux, du moins dans Google Chrome, car seules les tailles de police entières sont utilisées. Vous pourriez être en mesure de faire mieux avec une déclaration de police basée sur em , mais cela pourrait être un peu délicat – vous devriez vous assurer que la taille 1em pour le testeur de largeur de texte est identique à celle de l'entrée.

J'ai fait un autre d'un mélange d'autres réponses. Je pense que cela fournit la solution la plus simple de changement d'une propriété.

Il est probablement trop détaillé ou pourrait être refacturé pour plus de clarté à certains égards, toutes les suggestions sont bienvenues!

 $(document).ready(function(){ // get the current styles size, in px integer. var maxSize = parseInt($('.fields').css("font-size")); function isOverflowed (element){ if ( $(element)[0].scrollWidth > $(element).innerWidth() ) { return true; } else { return false; } }; function decreaseSize (element){ var fontSize = parseInt($(element).css("font-size")); fontSize = fontSize - 1 + "px"; $(element).css({'font-size':fontSize}); } function maximizeSize (element){ var fontSize = parseInt($(element).css("font-size")); while (!isOverflowed(element) && fontSize < maxSize){ fontSize = fontSize + 1 + "px"; $(element).css({'font-size':fontSize}); // if this loop increases beyond the width, decrease again. // hacky. if (isOverflowed(element)){ while (isOverflowed(element)) { decreaseSize(element); } } } } function fixSize (element){ if (isOverflowed(element)){ while (isOverflowed(element)) { decreaseSize(element); } } else { maximizeSize(element); } } // execute it onready. $('.fields').each(function(){ fixSize(this); }); // bind to it. $(function() { $('.fields').keyup(function() { fixSize(this); }) }); });