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?
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
In Firefox, the padding set on the div does not increase the width of the div, and
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.
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.
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:
As far as I know, there is no default styling done by any major browser done on the pre element.
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
Related
I have a plugin that creates and, on an interval, populates a <p> with the content of a <textarea>. The plugin positions the <p> underneath the <textarea>, and styles the elements so that their "boxes" are identical. Additionally, the background and text of the <textarea> are defined as transparent so that the content of the <p> can be seen.
Ideally, the elements and their contents will mirror one another at all times. And in most cases, they do. However, when both elements are made to be scrollable, the dynamic breaks; this is due to a difference in the scrollHeight of the two elements (the scrollHeight of <textArea> is larger than that of the <p>)
Here is the code:
var $shadowParagraphObj = $("#shadowParagraph");
var $contentTextAreaObj = $("#contentTextArea").scroll(scrollShadowParagraph);
function scrollShadowParagraph(event)
{
var textAreaScrollLeft = $contentTextAreaObj.scrollLeft();
var textAreaScrollTop = $contentTextAreaObj.scrollTop();
if($shadowParagraphObj.scrollLeft() != textAreaScrollLeft)
$shadowParagraphObj.scrollLeft(textAreaScrollLeft)
if($shadowParagraphObj.scrollTop() != textAreaScrollTop)
$shadowParagraphObj.scrollTop(textAreaScrollTop)
}
var intervalId = setInterval(function(){$shadowParagraphObj.html($contentTextAreaObj.val())}, 100);
#containerDiv {
position: relative;
left: 50%;
margin-left: -250px;
width: 510px;
height: 200px;
}
#shadowParagraph, #contentTextArea {
width: inherit;
height: inherit;
overflow: scroll !important;
padding: 4px;
border : none;
outline: none;
margin: 0px;
white-space: pre-wrap;
word-wrap: pre-wrap;
font: 1em Arial, sans-serif;
}
#shadowParagraph {
position: absolute;
z-index: 0;
background: white;
color: blue;
}
#contentTextArea {
position: relative;
z-index: 1;
background: transparent;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='containerDiv'>
<p id='shadowParagraph'></p>
<textarea id='contentTextArea'></textarea>
</div>
Overflowing the <textarea> should produce the issue (the text of the <textarea> has been given color to make the issue easy to see).
Have I forgot to declare some properties that are causing this discrepancy between scrollHeight values? If so, what are they and how should I declare them? If not, is there any way to ensure that the scrollHeight of the two elements is equal at all times?
Okay so using .replace(/\n\r?g, '<br />') to convert updated values, your line breaks will be converted into html line breaks. Additionally, html tends to ignore lone <br /> line breaks, so you will want to add an additional <br /> to the value to ensure the last line break is rendered.
Put together this would look something like:
var textAreaHTML = $myTextArea.val().replace(/\n\r?g, '<br />')+'<br />';
Additionally, I would recommend updating your textarea values AND scroll position on the .keyup() event, .keypress() event, or both events using .on('keyup keypress', function() {...}).
To see this in action check out this jsFiddle example
This issue is not very easy to explain so I apologize if this question seems confusing.
Basically, I have a <textarea> who's height changes based off its value. If there is any vertical overflow (which would normally produce a vertical scrollbar), I increase the height of the <textarea> to match its scrollHeight property. This seems to work just fine for the first two lines, but when more text is added, I noticed that the point at which the scrollHeight increases is different for each line of text.
Here is a fiddle that demonstrates the strange behavior: http://jsfiddle.net/2zpkf6fL/2/
Type about 5 or 6 lines of text and you will see what I'm talking about.
Can anyone shed some light on this issue? Why does the scrollHeight increase at different points for different lines of text?
Here is how i do what you are looking to do.
HTML:
<div class="textarea-container">
<textarea></textarea>
<div class="textarea-size"></div>
</div>
CSS:
.textarea-container {
position: relative;
/* you should change this*/
width: 50%;
}
textarea, .textarea-size {
min-height: 25px;
/* need to manually set font and font size */
font-family: sans-serif;
font-size: 14px;
box-sizing: border-box;
padding: 4px;
border: 1px solid;
overflow: hidden;
width: 100%;
}
textarea {
height: 100%;
position: absolute;
resize:none;
/*
"pre" or "preline" or "normal" fixes Chrome issue where
whitespace at end of lines does not trigger a line break.
However, it causes the text to exhibit the behavior seen with
"pre" that is described below.
*/
white-space: normal;
}
.textarea-size {
visibility: hidden;
/*
Pre-wrap: preserve spacing and newlines, but wrap text.
Pre: preserve spacing and newlines but don't wrap text.
"pre" does not wrap well on Firefox, even with word-wrap:break-word.
"pre" on Chrome works with word-wrap, but exhibits different behavior:
Instead of entire words being moved to the next line for wrapping,
the browser will cut words in the middle for wrapping.
"pre-line" has Firefox issues
*/
white-space: pre-wrap;
/* Required for wrapping lines in Webkit,
but not necessary in Firefox if you have white-space wrapping
(pre-wrap, normal, pre-line) already set */
word-wrap: break-word;
overflow-wrap: break-word;
}
SCRIPT:
var textContainer, textareaSize, input;
var autoSize = function () {
textareaSize.innerHTML = input.value + '\n';
};
document.addEventListener('DOMContentLoaded', function() {
textContainer = document.querySelector('.textarea-container');
textareaSize = textContainer.querySelector('.textarea-size');
input = textContainer.querySelector('textarea');
autoSize();
input.addEventListener('input', autoSize);
});
Here is jsfiddle
I have a text on my website that scrolls horizontal through the page. I’m trying to get around 8 characters highlighted in black, while the rest is grey. But those characters are meant to vary as you scroll though, the highlighted bit should remain in place.
In case this doesn’t make any sense, if grey was an x, it should look something like this:
xxxxx xpsum dolox xxx xxxx
xxxx xxsum dolox sxx xxxx
xxx xxxum dolox six xxxx x
xx xxxxm dolox sit xxxx xx
I’m trying to get this done in jQuery, but I can’t get it to work. I also like to say that I’m not at all an expert in webdesign, so I don’t know what I’m doing. Anyway, I’ve tried two different approaches, one is to say “change colour of text when going over an underlying div”. The other approach is to change the colour of the text depending on the scrolling position, but the problem here is that it takes the scrolling position of the whole div, instead of a fixed position on the page. Both don’t work at the moment, examples are here:
jsfiddle 9p29tz2f
jsfiddle 9p29tz2f/1
If anyone has any ideas how to approach this, or needs some more clarification, please let me know. Many thanks!
Clone the text and set it as a child of the overlay box then scroll them together:
$(function(){
var $bodytext = $('#bodytext'),
$clone = $bodytext.clone();
//copy the text and append it to #black:
$clone.attr("id","clone").prependTo("#black");
//scroll #clone with #bodytext:
$bodytext.scroll(function(){
$clone.scrollLeft($bodytext.scrollLeft());
});
});
http://jsfiddle.net/9p29tz2f/2/
I've taken Teemu's solution and modified it a bit: http://jsfiddle.net/9af91wcL/2/
The important bits: The code moves a white DIV (#grey-overlay) on top of the text and makes it transparent. By adding black and white pixels, you get grey. The grey level is determined by the alpha channel (0.7 in the rgba() function).
You need to assign a height or it will look odd. I use 1.5em to make sure it doesn't overlap with the scroll bar of the #bodytext div.
Also make sure that the top/left position of both div's is the same.
In your real code, you can make the horizontal scrollbar disappear and scroll with JavaScript.
HTML
<div id="grey-overlay"></div>
<div id="bodytext">text...</div>
CSS
body {
background: #ffffff;
color: #000000;
font-family: sans-serif;
font-size: 200%;
}
#bodytext {
top: 15%;
width:200px;
height: 2em;
padding: 0;
position:absolute;
overflow-x:scroll;
overflow-y:hidden;
white-space: nowrap;
}
#grey-overlay {
background-color: rgba(255, 255, 255, 0.7);
width:40px;
height: 1.5em;
top:15%;
position:fixed;
z-index: 10;
}
You need to show the same content within #black as in #bodytext, and synchronize its position relative to #bodytext scrolling. This can be achieved by using an extra wrapper around #black. Something like this:
CSS:
#cover {
top: 15%;
height:50%;
width: 120px;
padding: 0;
position:fixed;
overflow-x: hidden;
background-color: #D8D8D8;
}
#black {
color: #000000;
width:100%;
height:100%;
top:0px;
left: 0px;
position:absolute;
white-space: nowrap;
z-index: 10;
}
#bodytext {
top: 15%;
width:100%;
height:85%;
padding: 0;
position:absolute;
overflow-x:scroll;
white-space: nowrap;
color: #D8D8D8;
}
HTML:
<div id="cover">
<div id="black"></div>
</div>
JS:
$(document).ready(function () {
var black = $('#black'),
btext = $('#bodytext');
black.text(btext.text()); // Clone the content
btext.scroll(function () {
var pos = btext.scrollLeft();
black.css('left', -pos + 'px'); // Set the position to match #bodytext
});
});
A live demo at jsFiddle.
Notice, that if you need some left margin, it has also to be "calculated in" to pos.
I want to get the size of text inside a container. Let's consider general case when the container has padding and border.
The problem is that getBoundingClientRect returns the size of text PLUS left border and padding, in case the text overflows. Otherwise it returns just the size of border box of the container.
You can get the width if you create a placeholder div with all of the same text formatting options and find it's width.
For instance, I will create a div with the class .hidden that has the same attributes as the original div.
div.container
{
font-size: 16px;
}
div.hidden
{
font-size: 16px;
display: none;
}
Then, using jQuery, copy the contents of .container to .hidden and find the width of .hidden:
$(function(){
$("div.container").each(function(){
$("body").append("<div class='hidden'>"+$(this).html()+"</div>");
var width = $("div.hidden").width();
$("div.width").html("Actual width: "+width+"px");
$("div.hidden").remove();
});
});
JSFiddle
Interesting! You could use javascript to clone the text inside of an empty element offscreen that has 0 padding/margin/border. Then you could get the width of that element.
var txt = document.getElementById('fixed').innerHTML,
clone = document.getElementById('clone');
clone.innerHTML = txt;
var width = clone.offsetWidth;
document.getElementById('output').innerHTML = width;
#fixed {
width: 8em;
height: 8em;
border: .5em solid red;
}
#clone {
margin: 0;
padding: 0;
border: 0;
position: fixed;
left: -9999px;
}
<div id="fixed">asdfkjahsdflkahjsdflkjhasdljfhalsdkjfhalsdkjfhalsdkjfhalksdhjflasd</div>
<div id="clone"></div>
Width of text: <span id="output"></span>
People who had answered here came with a brilliant idea of wrapping the text into a <div> having zero margin, border and padding;
I just developed the idea further. I place the div inside the container, making the text have exactly the same style as it had without wrapper.
JsFiddle
This solution will work almost everywhere. It can be broken by not very encouraged way of writing CSS, like
.container div b {
padding: 5px; /* firing only when test is run */
}
If you do not code CSS in you project like that, you are the lucky one to use my snippet )
Need to implement functionality similar to what dotdotdot jQuery plugin does
but cannot use javascript frameworks (like jquery or ext).
Is there any easy way to add the dots to the content of div or span element if content takes more space then element should???
(similar to what css overflow: ellipsis setting does)
Can't use ellipsis beacause it doesn't work with many lines when height is limited.
Thank you :)
Why not using the CSS property text-overflow? It works great as long as you define a width in your tag.
Class in CSS:
.clipped {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
<div class="clipped" style="width: 100px;" title="This is a long text">This is a long text<div>
You can also add the text to the title attribute, so the user can see the whole text when hovering over the element.
Works for any number of lines and any width without any javascript - and is responsive. Simply set your max-height to a multiple of your line height: i.e. (22px line height) * (max 3 lines of text) = (max height 66px).
https://codepen.io/freer4/pen/prKLPy
html, body, p { margin: 0; padding: 0; font-family: sans-serif;line-height:22px;}
.ellipsis{
overflow:hidden;
margin-bottom:1em;
position:relative;
}
.ellipsis:before {
content: "\02026";
position: absolute;
bottom: 0;
right:0;
width: 1.8em;
height:22px;
margin-left: -1.8em;
padding-right: 5px;
text-align: right;
background-size: 100% 100%;
background: linear-gradient(to right, rgba(255, 255, 255, 0), white 40%, white);
z-index:2;
}
.ellipsis::after{
content:"";
position:relative;
display:block;
float:right;
background:#FFF;
width:3em;
height:22px;
margin-top:-22px;
z-index:3;
}
/*For testing*/
.ellipsis{
max-width:500px;
text-align:justify;
}
.ellipsis-3{
max-height:66px;
}
.ellipsis-5{
max-height:110px;
}
<div class="ellipsis ellipsis-3">
<p>Here we can have a great many lines of text and it works as we expect it to. Here we can have a great many lines of text and it works as we expect it to. Here we can have a great many lines of text and it works as we expect it to. Here we can have a great many lines of text and it works as we expect it to.</p>
</div>
<div class="ellipsis ellipsis-5">
<p>The number of lines shown is easily controlled by setting the max-height of the .ellipsis element. The downsides are the requirement of a wrapping element, and that if the text is precisely as long as your number of lines, you'll get a white area covering the very trailing end of your text. You've been warned. This is just some pushing text to make the element longer. See the ellipsis? Yay.</p>
</div>
You could try:
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
This will only work if your elements are not dynamically sized. They will have to have a width set or some other mechanism to keep them from growing to allow more content.
My solution to my problem can seem a little awkward, but it works for me:)
I used a little of CSS:
word-wrap: break-word;
and Javascript:
var spans = document.getElementsByTagName("span");
for (var i in spans) {
var span = spans[i];
if (/*some condition to filter spans*/) { // just
if (navigator.appName == 'Microsoft Internet Explorer') {
span.parentNode.style.display ='inline-block';
}
if (span.parentNode.clientHeight > 50 ) {
span.innerHTML = span.innerHTML.substr(0, 26) + ' ...';
}
}
}
FOR ALL Browser:
.dotdot{ white-space: nowrap; text-overflow: ellipsis; overflow: hidden; max-width:80px}
.dotdot:before { content: '';}
<div class="dotdot">[Button Text Goes here][1]</div>