Уменьшение размера шрифта для пользовательских типов, чтобы соответствовать вводу с использованием Javascript

Apple MobileMe использует javascript для изменения размера шрифта при входе в электронную почту на своей домашней странице, когда пользователь вводит текст, чтобы текст всегда помещался в доступное пространство без прокрутки переполнения.

Хотя я вижу, как выполнять функцию при каждом нажатии клавиши, мне любопытно, как каждый раз рассчитывать размер шрифта, чтобы он всегда вписывался в поле ввода. Есть ли способ измерить длину фрагмента текста шрифтом переменной ширины? Как они достигают этого эффекта?

Попробуйте, чтобы понять, что я имею в виду: http://www.me.com/

2 ответа

Решение

Я делал это в прошлом, используя jQuery. Вы можете измерить размер фрагмента текста следующим образом:

// txt is the text to measure, font is the full CSS font declaration,
// e.g. "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

Для того, чтобы подогнать это под данное пространство, это немного сложнее - вам нужно выделить font-size декларация и масштабировать его соответствующим образом. В зависимости от того, как вы делаете вещи, это может быть проще, если вы разбиваете различные части font декларация. Функция изменения размера может выглядеть так (опять же, очевидно, это зависит от 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});
}

Вы можете увидеть это в действии здесь: http://jsfiddle.net/nrabinowitz/9BFQ8/5/

Тестирование, кажется, показывает, что это немного нервно, по крайней мере, в Google Chrome, потому что используются только целочисленные размеры шрифта. Вы могли бы быть в состоянии сделать лучше с emна основе объявления шрифта, хотя это может быть немного сложно - вам нужно убедиться, что 1em Размер тестера ширины текста такой же, как и для ввода.

Я сделал еще один из мешанины других ответов. Я думаю, что это обеспечивает самое простое решение с одним изменением свойства.

Это, вероятно, слишком многословно или может быть реорганизовано для ясности, любые предложения приветствуются!

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

});
Другие вопросы по тегам