Kevin Kevin - 6 months ago 14
jQuery Question

Identical elements have different scrollHeights when overflowed. What is the cause, and how can I fix it?

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?

Answer

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