5

I want to create a textarea which highlights the text beyond a character limit (like the twitter one).

My attempt is here: http://jsfiddle.net/X7d8H/1/

HTML

<div class="wrapper">
    <div class="highlighter" id="overflowText"></div>
    <textarea id="textarea1" maxlength="200"></textarea>
</div>
<div id="counter">Letters remaining: 140</div>
<input type="Button" value="Done" id="doneButton"></input>

CSS

* {
    font-family: sans-serif;
    font-size: 10pt;
    font-weight: normal;
}
.wrapper {
    position: relative;
    width: 400px;
    height: 100px;
}
.wrapper > * {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    padding: 0;
    margin: 0;
    border: 0;
    overflow: hidden;
    resize: none;
    white-space: pre-wrap;          /* CSS3 */   
    white-space: -moz-pre-wrap;     /* Firefox */    
    white-space: -pre-wrap;         /* Opera below 7 */   
    white-space: -o-pre-wrap;       /* Opera 7 */    
    word-wrap: break-word;          /* IE */
}
.highlighter {
    background-color: #eee;
    color: #f0f;
}
.highlight {
    background-color: #fd8;
    color: #f0f;
}
textarea {
    background-color: transparent;
    color:#000;
}

JAVASCRIPT

function limitTextSize(e) {
    var max = 140
    var txt = $("#textarea1").val();
    var left = txt.substring(0, max);
    var right = txt.substring(max);
    var html = left + '<span class="highlight">' + right + "</span>";
    $("#overflowText").html(html);
    $("#counter").html("Letters remaining: " + (max - txt.length));
    $("#doneButton").attr("disabled", txt.length > max);
}

function maxLength(el) {    
    if (!('maxLength' in el)) {
        var max = el.attributes.maxLength.value;
        el.onkeypress = function () {
            if (this.value.length >= max) return false;
        };
    }
}
$(document).ready(function() {
    $("#textarea1").bind('input propertychange', limitTextSize)
    maxLength($("#textarea1"));
});

It uses JQuery

It works except on firefox. To see the bug, paste this into the textarea:

fjdf hkj hfj hdfkjsd hfllll sdfl sdlflldsf lsdlf flsdlf lsdf lsdf llsdfls dlfs ldflsd f

Which exposes the small difference in formatting between div and textarea (in firefox only). I've made the 'hidden' text purple so you can see the word wrap difference.

I've looked here: How to force Firefox to render textarea padding the same as in a div?

And here: Wrapping the text the same way in a div as in a textarea

And here: Firefox textarea sizing bug?

But none of those seem to apply...

I thought about trying to make it a contenteditable div but getting the change events looks like a minefield.

Has anyone here done this successfully?

Community
  • 1
  • 1
Charlie Skilbeck
  • 1,081
  • 2
  • 15
  • 38

3 Answers3

4

I think you are running into an issue where Firefox adds 1.5px of padding inside textarea elements.

Firefox has had quite some issues with paddings in combination with textareas in the past, I think you might not be able to get rid of these additional 1.5px of padding.

I was able to fix your wrapping issue by setting some vendor specific prefixed CSS properties on div.highlighter. Here's a jsFiddle.

.highlighter {
  background-color: #eee;
  color: #f0f;
  -moz-box-sizing: border-box;
  -moz-padding-end: 1.5px;  
  -moz-padding-start: 1.5px;      
}

Setting these properties ensures that

  1. In Firefox, the padding set on the div does not increase the width of the div, and
  2. that, in Firefox, 1.5px of padding will be set on both the right and the left hand side of the div.

Update

After some time of using 2px and still very occasionally experiencing some wrapping inconsistencies, I decided to give 1.5px a go, and for now that seems to have ironed out the occasional inconsistencies.

Community
  • 1
  • 1
Mathijs Flietstra
  • 12,900
  • 3
  • 38
  • 67
  • I think it might be a real magic number, it doesn't seem to change with altering the `font-size` or the `font-family`, and it only ever happens in Firefox. I think it might be a Firefox bug. – Mathijs Flietstra May 14 '13 at 00:11
  • well, it seems you're right dude, it's a moz bug and people out there are fixing it with this – coma May 14 '13 at 00:19
  • You did it! Thanks so much, I can sleep again. It won't let me award the bounty yet, I'll do it when it's available. – Charlie Skilbeck May 14 '13 at 05:31
  • The [Firefox bug](https://bugzilla.mozilla.org/show_bug.cgi?id=157846) just got resolved and it looks like the issue will be fixed in Firefox 29. – mkurz Jan 16 '14 at 20:42
0

This has to do with the font size being used. Since the unit used is point (pt), the size calculated is different enough in the browsers to cause the incorrect line wrap.

Try these styles instead:

* {
    font-family: sans-serif;
    font-size: 12px;
    font-weight: normal;
}

body {
    font-size: 1em;
}

JSFiddle

You might have to make changes in the container sizes to accomodate the change in font-size.

Vimal Stan
  • 2,007
  • 1
  • 12
  • 14
  • Sadly the issue persists - the wrapping difference still manifests for this text: jdf dlf lsdf lsdf llsdfls dlfs ldflsd f kjsdhf ksdjhfdlf lsdf lsdf llsdfls dlfs ldflsd f kj – Charlie Skilbeck May 13 '13 at 10:42
0

Okay, couple of things going on here. Generally, the safest cross-browser displayed element you'll find is the pre tag. It assumes that what you're feeding it is "pre-formatted," hence the name. This will benefit us in a couple ways:

  1. As far as I know, there is no default styling done by any major browser done on the pre element.
  2. The pre element will retain leading/trailing whitespace, tabs and other special characters in a box.

Replace the span.highlighter with pre.highlighter

That'll get us started. The second thing we'll want to look at is the overlaid colors creating some rather bizarre stacking effects in Firefox. The text looks out of focus in FF20, and I can only imagine that letting a browser decide how that looks would be a catastrophe going forward.

Set the color of the textarea to transparent.

Now we're there. I'm seeing consistent wrapping in IE10/9, FF20, and Chrome 26.

Here's an example jsFiddle

Josh Burgess
  • 9,327
  • 33
  • 46
  • Thanks for trying! I still see different wrapping when I paste in: a fkgs fkhs ga fskj fjah gkywae gawgf ekfb sakjyfb ksafb esbsekfbkfb k Also, what's the point of the empty element followed by the
    ?
    – Charlie Skilbeck May 14 '13 at 05:25