tags:

views:

115

answers:

2

I've got a JS-generated fill-in-the-gap text/cloze and I'm having trouble adjusting the text boxes to the right size.

But unlike others I'm in the position of knowing exactly what the user will/should enter.

So, if I have a gap _______ like this, I want the input to be exactly 4 characters wide. However, maybe since I'm using a proportional font (and that won't change), the width is always too large (even for a succession of capital Ds which are pretty wide).

So, what do you suggest? I tried setting the width with size, CSS width in em (too big) and ex (too narrow even for xxes).

I could calculate the width of the actual word (the one that needs to be filled in) a hidden span element, but that seems inelegant.

Is there a way to make the browser have a more accurate guess at the width of the input when I'm using a proportional font?

+1  A: 

Monospaced Font

The best results I've seen came through using a monospace font:

<input type="text" size="4" style="font-family:monospace" />

Online Example: http://jsbin.com/epagi/edit Rendered neatly in Firefox, Chrome, Safari, and IE.

If you're using a variable-width font, you would have to use scripting to get a better guess as to what the expected width would be, but as you said, this isn't very elegant.

Variable-Width Font

I tried to work up a reasonable-simple solution for variable-width fonts, but ultimately you will need to see if it fits your project or not.

Basically what I did was set the text-transform of particular inputs to uppercase to get a semi-consistent expectation for how wide something will be when filled out with text. I then applied a classname that indicated the field should be auto-sized, and how many chars we're expecting: sizeMe-4. Using jQuery, I collected all of these inputs, and split this classname to get the number of chars expected.

I extended the String object to include a repeat method which allows me to easily create a string of the expected size, and add it to an ad-hoc span element to get the width. This width was then retroactively applied to the initial input element. The span is then discarded.

Online Demo: http://jsbin.com/epagi/2/edit

For convenience, here's the code:

<input type="text" name="pin" maxlength="4" class="sizeMe-4" 
       style="text-transform:uppercase" />

--

String.prototype.repeat = function(num) {
    return new Array( num + 1 ).join( this );
}

$(function(){
  $(":input[class^='sizeMe']").each(function(){
    var size = Number($(this).attr("class").split("-").pop());
    var newW = $("<span>").text( "X".repeat(size) ).appendTo("body");
    $(this).width( $(newW).width() );
    $(newW).remove();
  });
});​
Jonathan Sampson
Thank you Jonathan.I might have to choose the inelegant way then, but I'm probably better off calculating the cross-browser computed width in a different way, right? I mostly saw it being done with clientX stuff in similar applications. Or does Jquery do this automatically? I use Mootools, maybe it can do that too.You just appended the span to the body an then discarded it, so I take it, that I need not worry about hiding it from the viewport because of speed?
Ruben
I also just now noticed, that my problem might actually be somewhere else, because the width in your example wasn't _quite_ as far off as it is in mine (still, now that I'm on it, I'll stay on it.)
Ruben
@Ruben: jQuery will figure the proper width of the element with `$.width()`. Keep in mind that my width-calculation is based on the assumption that you're using nearly-uniform-width uppercase characters.
Jonathan Sampson
A: 

Mootools

In case anybody stumbles upon this, in Mootools I just created a span containing the to-be-filled-in gap text and used these methods from Mootools More (they guarantee invisibility which is pretty important for a cloze.

$('gapsize').measure(function(){return this.getComputedSize()});
Ruben