dynamic width of textarea with no-wrap - javascript

How can I make a textarea which does not force line wrapping and extends its size to match the contents instead of showing a scroll-bar?
I need a textarea with dynamic width. The width should be the widest line of the textarea. I mean there should be no wrapping and the width should be changed the long a line gets.

Assign an input listener function which compares the scroll width and height against the outer width and height of the element. If they are different then set them as necessary.
For CSS you need white-space:nowrap to stop the lines from wrapping and overflow:hidden to get rid of the scroll bars.
$('.demo').on('input', function(e){
this.style.width = '';
this.style.height = '';
if(this.scrollWidth > this.clientWidth) this.style.width = this.scrollWidth + 'px';
if(this.scrollHeight > this.clientHeight) this.style.height = this.scrollHeight + 'px';
})
.demo {
white-space: nowrap;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea class="demo"></textarea>

Related

Calculating width of scrollbar and using result in calc() css

I want to calculate the width of the scrollbar so that I use the result in a CSS calc() declaration.
At the moment, I assume that the width of the scrollbar is always 17px, like this:
body {
width:calc(100vw - 17px);
}
.container {
max-width:calc(100vw - 17px);
}
The problem with this is when you choose a different browser zoom %, the width of the scrollbar changes. So I want to use the result of the calculation to do something along these lines:
body {
width:calc(100vw - CALCULATED SCROLL-BAR WIDTH);
}
.container {
max-width:calc(100vw - CALCULATED SCROLL-BAR WIDTH);
}
EDIT: I've now solved the problem with the help of this question
The JavaScript used to calculate the scrollbar width (though, I have found you require an interval to get it to autoupdate):
function getScrollbarWidth() {
var outer = document.createElement("div");
outer.style.visibility = "hidden";
outer.style.width = "100px";
outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
document.body.appendChild(outer);
var widthNoScroll = outer.offsetWidth;
// force scrollbars
outer.style.overflow = "scroll";
// add innerdiv
var inner = document.createElement("div");
inner.style.width = "100%";
outer.appendChild(inner);
var widthWithScroll = inner.offsetWidth;
// remove divs
outer.parentNode.removeChild(outer);
return widthNoScroll - widthWithScroll;
}
My code (which is used to embed the result of the function into a CSS calc() declaration).
$('body').css({
'width':'calc(100vw - ' + getScrollbarWidth() + 'px)'
});
$('.container').css({
'max-width':'calc(100vw - ' + getScrollbarWidth() + 'px)'
});
Actually, you can get the scrollbar width just with css and custom properties (and completely without javascript):
body {
--scrollbar-width: calc(100vw - 100%);
}
Then you can use this variable in a child element like this:
.container {
max-width: calc(100vw - var(--scrollbar-width));
}
This is because 100vw is always the inner width of the view, but the 100% of the body does not include the scrollbar.
Expanding jonas_jonas's answer, it can work but if .container must have the same width as the body.
If that's not the case, even so you can make it work with vanilla JS, defining a CSS property like this
document.body.style.setProperty(
"--scrollbar-width",
`${window.innerWidth - document.body.clientWidth}px`
);
And then you can use it in CSS
.container {
max-width: calc(100vw - var(--scrollbar-width));
}
Why you need so much code to do that?
The easy way with plain javascript it's:
$('body').css({
'width':'calc(100vw - ' + (window.innerWidth - document.body.clientWidth) + 'px)'
});

What is offsetHeight, clientHeight, scrollHeight?

Thought of explaining what is the difference between offsetHeight, clientHeight and scrollHeight or offsetWidth, clientWidth and scrollWidth?
One must know this difference before working on the client side. Otherwise half of their life will be spent in fixing the UI.
Fiddle, or inline below:
function whatis(propType) {
var mainDiv = document.getElementById("MainDIV");
if (window.sampleDiv == null) {
var div = document.createElement("div");
window.sampleDiv = div;
}
div = window.sampleDiv;
var propTypeWidth = propType.toLowerCase() + "Width";
var propTypeHeight = propType + "Height";
var computedStyle = window.getComputedStyle(mainDiv, null);
var borderLeftWidth = computedStyle.getPropertyValue("border-left-width");
var borderTopWidth = computedStyle.getPropertyValue("border-top-width");
div.style.position = "absolute";
div.style.left = mainDiv.offsetLeft + Math.round(parseFloat((propType == "client") ? borderLeftWidth : 0)) + "px";
div.style.top = mainDiv.offsetTop + Math.round(parseFloat((propType == "client") ? borderTopWidth : 0)) + "px";
div.style.height = mainDiv[propTypeHeight] + "px";
div.style.lineHeight = mainDiv[propTypeHeight] + "px";
div.style.width = mainDiv[propTypeWidth] + "px";
div.style.textAlign = "center";
div.innerHTML = propTypeWidth + " X " + propTypeHeight + "( " +
mainDiv[propTypeWidth] + " x " + mainDiv[propTypeHeight] + " )";
div.style.background = "rgba(0,0,255,0.5)";
document.body.appendChild(div);
}
document.getElementById("offset").onclick = function() {
whatis('offset');
}
document.getElementById("client").onclick = function() {
whatis('client');
}
document.getElementById("scroll").onclick = function() {
whatis('scroll');
}
#MainDIV {
border: 5px solid red;
}
<button id="offset">offsetHeight & offsetWidth</button>
<button id="client">clientHeight & clientWidth</button>
<button id="scroll">scrollHeight & scrollWidth</button>
<div id="MainDIV" style="margin:auto; height:200px; width:400px; overflow:auto;">
<div style="height:400px; width:500px; overflow:hidden;">
</div>
</div>
To know the difference you have to understand the box model, but basically:
clientHeight:
returns the inner height of an element in pixels, including padding but not the horizontal scrollbar height, border, or margin
offsetHeight:
is a measurement which includes the element borders, the element vertical padding, the element horizontal scrollbar (if present, if rendered) and the element CSS height.
scrollHeight:
is a measurement of the height of an element's content including content not visible on the screen due to overflow
I will make it easier:
Consider:
<element>
<!-- *content*: child nodes: --> | content
A child node as text node | of
<div id="another_child_node"></div> | the
... and I am the 4th child node | element
</element>
scrollHeight: ENTIRE content & padding (visible or not)
Height of all content + paddings, despite of height of the element.
clientHeight: VISIBLE content & padding
Only visible height: content portion limited by explicitly defined height of the element.
offsetHeight: VISIBLE content & padding + border + scrollbar
Height occupied by the element on document.
* offsetHeight is a measurement in pixels of the element's CSS height, including border, padding and the element's horizontal scrollbar.
* clientHeight property returns the viewable height of an element in pixels, including padding, but not the border, scrollbar or margin.
* scrollHeight value is equal to the minimum height the element would require in order to fit all the content in the viewport without using a vertical scrollbar. The height is measured in the same way as clientHeight: it includes the element's padding, but not its border, margin or horizontal scrollbar.
Same is the case for all of these with width instead of height.
My descriptions for the three:
offsetHeight: How much of the parent's "relative positioning" space is taken up by the element. (ie. it ignores the element's position: absolute descendents)
clientHeight: Same as offset-height, except it excludes the element's own border, margin, and the height of its horizontal scroll-bar (if it has one).
scrollHeight: How much space is needed to see all of the element's content/descendents (including position: absolute ones) without scrolling.
Then there is also:
getBoundingClientRect().height: Same as scrollHeight, except that it's calculated after the element's css transforms are applied.
Offset Means "the amount or distance by which something is out of line". Margin or Borders are something which makes the actual height or width of an HTML element "out of line". It will help you to remember that :
offsetHeight is a measurement in pixels of the element's CSS
height, including border, padding and the element's horizontal
scrollbar.
On the other hand, clientHeight is something which is you can say kind of the opposite of OffsetHeight. It doesn't include the border or margins. It does include the padding because it is something that resides inside of the HTML container, so it doesn't count as extra measurements like margin or border. So :
clientHeight property returns the viewable height of an element in
pixels, including padding, but not the border, scrollbar or margin.
ScrollHeight is all the scrollable area, so your scroll will never run over your margin or border, so that's why scrollHeight doesn't include margin or borders but yeah padding does. So:
scrollHeight value is equal to the minimum height the element would require in order to fit all the content in the viewport without using
a vertical scrollbar. The height is measured in the same way as
clientHeight: it includes the element's padding, but not its border,
margin or horizontal scrollbar.

Resizing child DIV equal to parent DIV

I have a DIV with width 400px and height 200px. Inside this div is another div with some text at position 50,50 and font-size 14px;
When the parent DIV resizes (for example to 600px x 300px), i want that the text-size inside the child DIV resizes too (to a larger font-size), equal to the resized parent DIV.
How can i do that with jQuery and HTML?
make the child div width and height 100%
childDiv {
display:block;
width: 100%;
height: 100%;
position:relative //so you dont lose the positioning of your text
}
when the parent dives size becomes (600 / 300) from (400 / 200) for example, you should apply a javascript function to the child div like so
function resizeFont(parentElementId, childElementId, newWidth) {
currWidthParentElement = parseFloat( $(parentElementId).width() ); // get current width
currChildFontSize = parseInt( $(childElementId).css('font-size') ); // get font size for child
percentaRaise = (newWidth - ceil(currWidthParentElement)) * (100/ceil(currWidthParentElement)); // calculate how much parent increase
// calculate and apply new font size
newFontSize = currChildFontSize * percentaRaise/100 + currChildFontSize;
$(childElementId).css(newFontSize);
}
is seems tricky but is simple algebra. I hope thihs will help you
http://codepen.io/rafaelcastrocouto/pen/EiFIL
var div = $('div');
$(window).on('resize', function(){
var u = div.width() / 200;
div.css('font-size', u +'em');
});
There is an extension for jquery that allows resize to be fired on elements like it would on the window itself.
The extension: Jquery Resize Plugin
So something like this will do the trick:
$("#parent").resize(function(){
var newFontSize = $("#parent").height() * 0.07
$("#child").css("font-size",newFontSize +"px");
});
Check out this JsFiddle for an example: http://jsfiddle.net/Mm3jr/1/

scrollHeight not resetting after programmatically changing content

I am trying to learn a few things without jQuery. Here is one of the challenges I'm facing.
I have a fixed contenteditable div that when adding text to the div, if the scrollHeight exceeds the clientHeight I shrink the font until content fits the div.
Occasionally I "rebuild" the text which replaces the innerHTML programmatically. Or the user can delete text which should reduce the scrollHeight, but in both cases, the scrollHeight remains the maximum value. I need some way to increase the font size to "fit" the div again. (that ideally isn't super expensive)
Example:
My clientHeight = 142, and the scrollHeight = 158. A loop reduces the font size, until scrollHeight is 142.
Then, the user deletes a line of text, but the scrollHeight is still 142, no change.
code to reduce/increase height:
var textBox = document.getElementById('text');
var current, min = 6, max = 14;
current = textBox.style.fontSize.substr(0, textBox.style.fontSize.length - 2);
current = parseInt(current);
if (textBox.clientHeight < textBox.scrollHeight) {
while (textBox.clientHeight < textBox.scrollHeight) {
current--;
if (current < min) break;
textBox.style.fontSize = '' + current + 'pt';
}
} else if (textBox.clientHeight > textBox.scrollHeight) {
while (textBox.clientHeight > textBox.scrollHeight) {
current++;
if (current > max) break;
textBox.style.fontSize = '' + current + 'pt';
}
}
html (incase it matters):
<div id="text" contenteditable="true"></div>
css (incase it matters):
#text {
position: relative;
border: 1px solid blue;
top: 180px;
left: 31px;
width: 300px;
height: 132px;
padding: 5px;
font-family: 'mplantin';
font-size: 14pt;
font-weight: 200;
}
I was on the same boat, but with an iframe; I'm not sure if my solution suits your chat window because its for page transitioning, but after some testing this is my hack. "content" is the id of an iframe and this is executed inside a javascript function that is called when the page change is needed:
var c=document.getElementById("content");
c.width=0;
c.height=0;
c.src="page.html";
the `src' assignment method expands the values set to 0 right after, achieving the desired result; there may be a way for you to constantly re-size a text area like that; however, I had visual issues with you; I ended up using timers so that the change would take place while the transition between pages was transparent.
This seemed to fix my issue:
element.style.height = "auto";
both answers from #nixahn and #jeff are working for me (chrome,ff)
iframe.style.height ="0"; // or "auto"
iframe.contentWindow.document.open();
iframe.contentWindow.document.write('<style>'+css+'</style>');
iframe.contentWindow.document.write(html);
iframe.contentWindow.document.close();
I have used a div with a fixed height, and the problem with auto is that it resizes the element, I fixed that with the following code after my inner HTML was set:
element.style.height = "auto";
element.style.height = "400px";
now scrollHeight is resetted correctly and gives the real height of the inner HTML
I had this same issue -- A content editable div whose scrollHeight wouldn't shrink when lines were removed.
The accepted answer didn't fix the problem for me, however, removing the div's parent's display: flex; did.

Dynamically make a child container take available width inside variable width parent

I have a container which wraps around three floated containers, the wrapping container has a variable width and the left most inner container has a width of 100px and the right most inner container has a width of 500px. The center container does not have a set width, but should take up as much space as possible that remains.
<style type="text/css">
#outerContainer div:nth-child(1) {float: left; width: 100px}
#outerContainer div:nth-child(2) {float: left}
#outerContainer div:nth-child(3) {float: right; width: 500px}
</style>
<div id="outerContainer">
<div>left most inner container</div>
<div>center container</div>
<div>right most inner container</div>
</div>
The dynamic center container has a few styles applied to it which make it's content overflow: hidden and ellipsis for presentation purposes.
<style type="text/css">
#outerContainer div:nth-child(1) {
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
</style>
I'm not sure what the solution is to dynamically scale the width of this inner element using ONLY css. Here's my JavaScript solution which works, but I'd like to cut it out as it seems excessive.
NS.textWidth = function(sourceSel){
var sourceSel = sourceSel,
html_org = $(sourceSel).html(),
html_calc = '<span>' + html_org + '</span>';
//Wrap contents with a span.
$(sourceSel).html(html_calc).css({width:'100%'});
//Find width of contents within span.
var width = $(sourceSel).find('span:first').width();
//Replace with original contents.
$(sourceSel).html(html_org);
return width;
};
adjustContainerWidth();
$(window).bind('resize', function(e){
clearTimeout(c.resize_timeout);
c.resize_timeout = setTimeout(function() {
adjustContainerWidth();
}, 200);
});
function adjustContainerWidth() {
var winW = parseInt($(window).width());
var firstContainer = parseInt($('#outerContainer div:nth-child(1)').width());
var lastContainer = parseInt($('#outerContainer div:nth-child(3)').width());
var availW = winW - firstContainer - lastContainer;
var textW = NS.textWidth('#outerContainer div:nth-child(2)');
if (availW > 40 && availW < textW) {
$('#outerContainer div:nth-child(1)').css({ width : availW + 'px' });
} else {
$('#outerContainer div:nth-child(1)').css({ width : textW + 'px' });
}
}
pure css http://jsfiddle.net/Za8RF/
This is, currently, untested but I think the following should work. Effectively find the width of the parent, the width of the siblings and then subtract one from the other:
var that = $(this),
parentWidth = that.parent().width(),
siblingsWidth = 0;
that.siblings().each(
function(){
siblingsWidth += $(this).outerWidth();
});
that.width(parentWidth - siblingsWidth);
JS Fiddle demo.
I've made the #outerContainer element 1000px wide, just to ensure that all elements have space to fit side-by-side in the demo.
I've also corrected your CSS a little; CSS is one-based, not zero-based like programming languages. So #outerContainer div:nth-child(0) wasn't matching, or styling, any elements.

Categories

Resources