How to convert pixels to em in a easy way - javascript

I am looking for a easy way to add a line of code to a plugin of mine, to convert a couple of pixel values into em values, because the layout of my project needs to be in ems. Is there an easy way to do this, because I don't want to add a third-party plugin to the site.
Won't post the code here, as it has nothing to do with the plugin it self.
Example: 13px -> ??em

I think your question is very important. Since the classes of display resolutions are rapidly increasing, using em positioning to support wide range of screen resolutions is a really appealing approach. But no matter how hard you try to keep everything in em -- sometimes you get a pixel value maybe from JQuery drag and drop or from another library, and you would want to convert this value to em before sending it back to server for persistence. That way next time user looks at the page, item would be in correct position -- regardless of screen resolution of the device they are using.
JQuery plugins are not very scary when you can review the code, specially if they are short and sweet like this plugin to convert pixel values to em as you want. In fact it is so short I will paste the whole thing here. For copyright notice see the link.
$.fn.toEm = function(settings){
settings = jQuery.extend({
scope: 'body'
}, settings);
var that = parseInt(this[0],10),
scopeTest = jQuery('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;"> </div>').appendTo(settings.scope),
scopeVal = scopeTest.height();
scopeTest.remove();
return (that / scopeVal).toFixed(8) + 'em';
};
$.fn.toPx = function(settings){
settings = jQuery.extend({
scope: 'body'
}, settings);
var that = parseFloat(this[0]),
scopeTest = jQuery('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;"> </div>').appendTo(settings.scope),
scopeVal = scopeTest.height();
scopeTest.remove();
return Math.round(that * scopeVal) + 'px';
};
Usage Example: $(myPixelValue).toEm(); or $(myEmValue).toPx();.
I just tested this in my application, it works great. So I thought I share.

The following seems to do as you require, though it's based on the font-size of the parent, and of the element itself, being returned in px:
function px2em(elem) {
var W = window,
D = document;
if (!elem || elem.parentNode.tagName.toLowerCase() == 'body') {
return false;
}
else {
var parentFontSize = parseInt(W.getComputedStyle(elem.parentNode, null).fontSize, 10),
elemFontSize = parseInt(W.getComputedStyle(elem, null).fontSize, 10);
var pxInEms = Math.floor((elemFontSize / parentFontSize) * 100) / 100;
elem.style.fontSize = pxInEms + 'em';
}
}
JS Fiddle proof of concept.
Notes:
The function returns false, if the element you're trying to convert to em is the body, though that's because I couldn't work out whether it was sensible to set the value to 1em or simply leave it alone.
It uses window.getComputedStyle(), so it's not going to work with IE, without some adjustments.
References:
Math.floor().
parentNode.
parseInt().
tagName.
toLowerCase().
window.getComputedStyle().

Pixels and ems are fundamentally different types of unit. You can't simply convert between them.
For instance, a user with a default font size of 16px on a site where top-level headings are styled at 200% font size, 1em may be equal to 32px. Move the heading elsewhere in the document, it could be 64px or 16px. Give the same document to a different user, it might be 30/60/15px. Start talking about a different element, and it can change again.
The closest you can come to what you want is to convert from pixels to ems+document+context+settings. But if somebody has asked you to lay out your project with ems, they will probably not be pleased that you are trying to do it in pixels then "converting".

Usually when you want to convert px to em, the conversion happens on the element itself. getComputedStyle returns value in px which break their responsiveness. The code below can be used to help with this issue:
/**
* Get the equivalent EM value on a given element with a given pixel value.
*
* Normally the number of pixel specified should come from the element itself (e.g. element.style.height) since EM is
* relative.
*
* #param {Object} element - The HTML element.
* #param {Number} pixelValue - The number of pixel to convert in EM on this specific element.
*
* #returns {Boolean|Number} The EM value, or false if unable to convert.
*/
window.getEmValueFromElement = function (element, pixelValue) {
if (element.parentNode) {
var parentFontSize = parseFloat(window.getComputedStyle(element.parentNode).fontSize);
var elementFontSize = parseFloat(window.getComputedStyle(element).fontSize);
var pixelValueOfOneEm = (elementFontSize / parentFontSize) * elementFontSize;
return (pixelValue / pixelValueOfOneEm);
}
return false;
};
Using it would be as simple as:
var element = document.getElementById('someDiv');
var computedHeightInEm = window.getEmValueFromElement(element, element.offsetHeight);

Old question, but for reference, here is something I cobbled together, scope and suffix are optional. Pass it a rem or em value as string, eg. '4em' [ you can use spaces and upper/lowercase ] and it will return the px value. Unless you give it a scope, which would be the target element for finding the local EM value, it will default to body, effectively giving you the rem value. Lastly, the optional suffix parameter [ boolean ] will add 'px' to the returned value such that 48 becomes 48px for example.
ex: emRemToPx( '3em', '#content' )
return 48 on a font-size 16px / 100% document
/**
* emRemToPx.js | #whatsnewsisyphus
* To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
* see CC0 Public Domain Dedication <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
var emRemToPx = function( value, scope, suffix ) {
if (!scope || value.toLowerCase().indexOf("rem") >= 0) {
scope = 'body';
}
if (suffix === true) {
suffix = 'px';
} else {
suffix = null;
}
var multiplier = parseFloat(value);
var scopeTest = $('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;"> </div>').appendTo(scope);
var scopeVal = scopeTest.height();
scopeTest.remove();
return Math.round(multiplier * scopeVal) + suffix;
};

I've packaged this functionality into a library, complete with parameter type checking: px-to-em
Given this HTML:
<p id="message" style="font-size: 16px;">Hello World!</p>
You can expect these outputs:
pxToEm(16, message) === 1
pxToEm(24, message) === 1.5
pxToEm(32, message) === 2
Since the OP requested a way to do this without a library, I've copied the source code of px-to-em to a live demo:
function pxToEm (px, element) {
element = element === null || element === undefined ? document.documentElement : element;
var temporaryElement = document.createElement('div');
temporaryElement.style.setProperty('position', 'absolute', 'important');
temporaryElement.style.setProperty('visibility', 'hidden', 'important');
temporaryElement.style.setProperty('font-size', '1em', 'important');
element.appendChild(temporaryElement);
var baseFontSize = parseFloat(getComputedStyle(temporaryElement).fontSize);
temporaryElement.parentNode.removeChild(temporaryElement);
return px / baseFontSize;
}
console.log(pxToEm(16, message), 'Should be 1');
console.log(pxToEm(24, message), 'Should be 1.5');
console.log(pxToEm(32, message), 'Should be 2');
<p id="message" style="font-size: 16px;">Hello World!</p>
I learned from this answer that with getComputedStyle we can reliably obtain the divisor px value with the decimal point, which improves the accuracy of the calculation. I found that the answer by Aras could be off by over 0.5px, which caused rounding errors for us.

Try using this:
parseInt(myPixelValue) / parseFloat($("body").css("font-size"));

Ems don't equal pixels in anyway. They are a relative measurement.
<span style="font-size: 1em;">This is 1em font size, which means the text is the same size as the parent</span>
<span style="font-size: 1.5em;">This is 1.5em font size, which means the text is 150% the size as the parent</span>
The base size is determined by the user-agent (browser).

Related

How to convert the result of externalHeight() to REM?

I could adjust the font size of the root HTML to fit the HTML window, for example:
var inputFont = parseFloat($("html").css("font-size"));
if (inputFont)
$("html").css("font-size", inputFont * 0.9);
Prior to this adjustment, I could make some elements fit to each other, for example:
buttonElem.outerHeight( $(labelElem).outerHeight() );
So, I would need to repeat this again, or to set the height in REM for buttonElem from the beginning, right?
Do you know how to quickly convert the result of externalHeight() to REM?
Will this conversion help?
Thanks.
calcREM() function is added:
function calcREM(px)
{
if( !isNaN(px) )
{
var remInPx = parseFloat($("html").css("font-size"));
return (parseFloat(px) / remInPx).toString() + "rem";
}
}
The code above has been updated to:
buttonElem.outerHeight( calcREM($(labelElem).outerHeight()) );
Here is the test.
The buttonElem before.
The buttonElem after converting pixels to REM using the calcREM () function.
Note: my CSS includes the definition:
html {
font-size: 16px;
}

JS - check if element's declared style property is set in vh

Say we have an element
<div class="vh-100">
Content
</div>
.vh-100 { height: 100vh }
How can I get to read that exact value 100vh, because
var computedHeight = window.getComputedStyle(element).height; // will simply return the `window.clientHeight` value in pixels in this case.
var styleAttributeHeight = element.style.height // will return '', which is empty
To put it simply, I need to find a way to determine if the value is set in vh because the child elements of the example <div class="vh-100"> have the box model broken and return incorrect offsetTop and offsetLeft for some reason.
I need a simple solution excluding checking the rules in the CSS file.
Here is a link to hopefully explain why I need this.
Directly no way, but i convert pixels to vh(1vh is 1/100 browser height). Here is code snippet, i hope it will help you.
/*var z = getComputedStyle(document.getElementsByClassName('deneme')[0],null).height.replace('px','');*/
/*var b = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);*/
//deactive variables for detailed usings.
var a = document.getElementsByClassName('sample')[0].clientHeight;
var b = window.innerHeight;
var c = Math.round((a / b) * 100) + "vh";
console.log(a)
console.log(b)
console.log(c)//it's your "vh"
.sample{
width: 10vw;
height: 1vh;
background:dodgerblue;
}
<div class="sample"></div>
if what you want is the unit of the height
yourElement.style.height
Normally it will return a string of height in it unit that you settled for the element (so '100vh' in your case).

How to detect number of characters that can exactly fit on a pre defined length of text box?

Lets say I add a text box of length of 50px, And I want to count the exact number of characters (including whitespace) that perfectly fits inside that text box, I mean no character should be allowed to be typed inside the textbox that require the sliding of whole line toward left; I mean, in another other-words, we need to disallow the typist to further insert any letter as the line reaches up to the length of the text box. Can we anyhow solve this by JavaScrip? Thanks for the help in advance, any help would be appreciated.
The whole logic is flawed as it would depend also on the size of the text inside the input. I'd put instead a limit of chars to be entered that don't go beyond. Using maxlength input attribute.
Anyways if you really wanna go this route, which I think is an overkill and not needed, then you can:
Make use of CanvasRenderingContext2D.measureText, docs here
In order to do that you'd have to create a hidden canvas element where to mimic your input text.
After that you will need to check on input if the text goes beyond the input width and avoid any further keystrokes but still allow for deletion.
Find attached an example snippet, not optimised, of what I am talking about.
const form = document.querySelector('#form'),
input = form.querySelector('input')
const createAppendCanvas = form => {
const canvas = document.createElement('Canvas')
form.appendChild(canvas)
}
createAppendCanvas(form)
const getTextMetrics = inputText => {
const canvas = document.querySelector('canvas'),
textWidth = Math.ceil(canvas.getContext('2d').measureText(inputText).width) + 10
return textWidth
}
const disableTyping = (event, input) => {
const inputText = event.target.value,
inputWidth = input.clientWidth
if (getTextMetrics(inputText) >= inputWidth) {
event.preventDefault()
return false
}
}
input.addEventListener('keypress', event => disableTyping(event, input))
input {
width: 50px;
}
canvas {
display: none;
}
<form id="form">
<input type="text" />
</form>
As #mel-macaluso rightly points out, this is a very big rabbit hole to go down, and the standard practice is to use the maxlength attribute to limit the number of characters.
*Edit: You can also set the width of the input using em, which is proportional to the font size. (The name em was originally a reference to the width of the capital M in the typeface and size being used, which was often the same as the point size ref) A combination of width in em and maxlength will give a very rough approximation of what you may be trying to achieve.
However if you really want to be able to limit input based text length, this would serve as a very simplistic example of how you might get started.
Edit: I recommend #mel-macaluso's answer: he added an example using CanvasRenderingContext2D.measureText(), which I suspect is much more efficient than getBoundingClientRect.
First some disclaimers:
This example doesn't take into account clipboard actions. That's a pretty big problem, and you'd be talking a lot more code to try to account for it (way beyond the scope of what can reasonably be done here).
It's also rather resource intensive. The process doing a getBoundingClientRect, forces the browser to reflow the document contents an extra time. Depending on the size of the page this can be a big deal, and it's not something to be done lightly.
var inp = document.getElementById('test');
// get font for input
var style = getComputedStyle(inp);
var maxWidth = inp.getBoundingClientRect().width;
var sizeTest = document.createElement('span');
// set font for span to match input
sizeTest.style.font = style.font;
inp.addEventListener('keydown', function(e){
if(e.ctrlKey || e.altKey) return;
if(e.key && e.key.length===1) {
sizeTest.textContent = inp.value;
document.body.append(sizeTest);
var w = sizeTest.getBoundingClientRect().width;
sizeTest.remove();
console.log(maxWidth, w, e.key, e.code);
if(w>maxWidth) e.preventDefault();
}
})
<input id='test'/>
So why is it so complex to do something like this? Fonts are tricky things. You have variable width (proportional) fonts, kerning, ligatures, etc. It's very complex, and browsers don't provide access to most of this information.
So if you want to know how long a segment of text is, you generally have to put it in a span with the same font settings and then request the bounding dimensions.
Here's neat solution using nested spans (with a contenteditable inner span) as a proxy input.
// Identifiers and dynamic styling
const innerSpan = document.querySelector("span.inner"),
outerSpan = document.querySelector("span.outer");
/* Threshold should be at least one character-width less than outerSpan.
(This formula was pretty close for my few tests;
for more precision and less flexibility, you can hard-code a value.) */
const estMaxCharWidth = innerSpan.offsetHeight / 1.7,
thresholdWidth = outerSpan.offsetWidth - estMaxCharWidth;
innerSpan.style.minWidth = `${Math.floor(thresholdWidth)-3}px`; // defaults to 0
innerSpan.style.minHeight = `${Math.floor(outerSpan.offsetHeight)-2}px`
// Listeners
innerSpan.addEventListener("focus", customOutline);
innerSpan.addEventListener("keydown", checkKeyAndWidth);
innerSpan.addEventListener("blur", removeOutlineAndHandleText);
// Functions
function checkKeyAndWidth(e){
// Runs when user presses a key, Conditionally prevents input
if(e.code == "Enter" || e.keyCode == 13){
e.preventDefault(); // Don't insert a new line
e.target.blur(); // (In production, set the focus to another element)
}
else{
// Some keys besides Enter are important, More could be added
const whitelistCodes = ["Backspace", "Tab", "Escape", "ArrowLeft", "ArrowRight", "Insert", "Delete"];
const whitelistKeyCodes = [8,9,27,37,39,45,46];
// If the inner span is wide enough, stop accepting characters
let acceptingCharacters = e.target.offsetWidth <= thresholdWidth;
if(!acceptingCharacters && !whitelistCodes.includes(e.code) && !whitelistKeyCodes.includes(e.keyCode) && !whitelistKeyCodes.includes(e.which)){
// Unauthorized incoming keystroke
e.preventDefault();
}
}
}
function customOutline(){
// Runs when span gets focus, Needed for accessibility due to CSS settings
outerSpan.style.borderColor = "DeepSkyBlue";
}
function removeOutlineAndHandleText(){
// Runs when focus is lost
outerSpan.style.borderColor = "Gray";
if(innerSpan.length < 1){ innerSpan.innerHTML = " "; } // force content
/* Since this is not a real input element, now might be the time to do something with the entered text */
}
.outer{
display: inline-block;
position: relative;
width: 100px; /* Defaults to 0 */
padding: 0;
border: 1px solid gray;
}
.inner{
display: inline-block;
position: relative;
top: 0;
height: 100%;
margin: 0;
outline: none; /* Don't do this without calling customOutline on focus */
}
<!-- requires that browser supports `contenteditable` -->
<span class="outer">
<!-- space character in innerSpan may improve cross-browser rendering -->
<span class="inner" contenteditable="true"> </span>
</span>

Decimal ignored when changing font size with JS

I'm trying to add some text resize functionality using this code:
$('#text-resize a').click(function(){
var currentValue = $('#page-body').css('fontSize');
var currentSize = parseFloat(currentValue, 10);
var fontUnit = currentValue.slice(-2);
var newSize = currentSize;
if ($(this).attr('rel') == 'decrease'){
if (currentSize > 13){
var newSize = currentSize / 1.2;
}
}
else if ($(this).attr('rel') == 'increase'){
if (currentSize < 19){
var newSize = currentSize * 1.2;
}
}
else {
newSize = 1;
fontUnit = 'em';
}
newSize += fontUnit;
$('#page-body').css('fontSize', newSize);
return false;
});
I know it's not the cleanest code, but my problem is that at some point (either getting or setting the font size for #page-body decimal points are being lost.
For example, I start with a value of 16px (from my CSS file) and when I increase it gets calculated to 19.2px. If I increase again, an alert of the currentValue (I have left out the alert) says it's 19px.
Can anyone tell me why decimal places are being ignored and how to prevent that?
If it helps, my starting CSS includes:
body { font-size: 16px; }
#page-body { font-size: 1em; }
Thanks
A font size can only be a whole number of pixels, so when you set the font-size the browser casts the invalid font size to something it can use. The next time you get it, it's an integer number.
Since you're setting the font size on an element identified by ID, you should store the size in a variable and only set (never get) the element css font size.
For example, see http://jsfiddle.net/Qfzpb/
Sub-pixel rendering is inconsistent between browsers.
Font size can be a <length>, and a <length> is a <number> (with or without a decimal point) immediately followed by a unit identifier (e.g., px, em, etc.).
http://www.w3.org/TR/CSS21/fonts.html#font-size-props
CSS 3 says " UAs should support reasonably useful ranges and precisions. " Open-to-interpretation wording as 'reasonable' and 'useful':
http://dev.w3.org/csswg/css3-values/#numeric-types
$('#page-body').css('fontSize')
This may return different values(depending on the used browser).
Usually (in modern browsers) jQuery gets the value by using getComputedStyle() .
The returned value here is the value used by the browser, not the value the style-property is set to.
You may use this instead:
var currentValue = document.getElementById('page-body').style.fontSize
||
$('#page-body').css('fontSize');
See the fiddle to determine the differences: http://jsfiddle.net/doktormolle/DMWhh/

How to autosize a textarea using Prototype?

I'm currently working on an internal sales application for the company I work for, and I've got a form that allows the user to change the delivery address.
Now I think it would look much nicer, if the textarea I'm using for the main address details would just take up the area of the text in it, and automatically resize if the text was changed.
Here's a screenshot of it currently.
Any ideas?
#Chris
A good point, but there are reasons I want it to resize. I want the area it takes up to be the area of the information contained in it. As you can see in the screen shot, if I have a fixed textarea, it takes up a fair wack of vertical space.
I can reduce the font, but I need address to be large and readable. Now I can reduce the size of the text area, but then I have problems with people who have an address line that takes 3 or 4 (one takes 5) lines. Needing to have the user use a scrollbar is a major no-no.
I guess I should be a bit more specific. I'm after vertical resizing, and the width doesn't matter as much. The only problem that happens with that, is the ISO number (the large "1") gets pushed under the address when the window width is too small (as you can see on the screenshot).
It's not about having a gimick; it's about having a text field the user can edit that won't take up unnecessary space, but will show all the text in it.
Though if someone comes up with another way to approach the problem I'm open to that too.
I've modified the code a little because it was acting a little odd. I changed it to activate on keyup, because it wouldn't take into consideration the character that was just typed.
resizeIt = function() {
var str = $('iso_address').value;
var cols = $('iso_address').cols;
var linecount = 0;
$A(str.split("\n")).each(function(l) {
linecount += 1 + Math.floor(l.length / cols); // Take into account long lines
})
$('iso_address').rows = linecount;
};
Facebook does it, when you write on people's walls, but only resizes vertically.
Horizontal resize strikes me as being a mess, due to word-wrap, long lines, and so on, but vertical resize seems to be pretty safe and nice.
None of the Facebook-using-newbies I know have ever mentioned anything about it or been confused. I'd use this as anecdotal evidence to say 'go ahead, implement it'.
Some JavaScript code to do it, using Prototype (because that's what I'm familiar with):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="http://www.google.com/jsapi"></script>
<script language="javascript">
google.load('prototype', '1.6.0.2');
</script>
</head>
<body>
<textarea id="text-area" rows="1" cols="50"></textarea>
<script type="text/javascript" language="javascript">
resizeIt = function() {
var str = $('text-area').value;
var cols = $('text-area').cols;
var linecount = 0;
$A(str.split("\n")).each( function(l) {
linecount += Math.ceil( l.length / cols ); // Take into account long lines
})
$('text-area').rows = linecount + 1;
};
// You could attach to keyUp, etc. if keydown doesn't work
Event.observe('text-area', 'keydown', resizeIt );
resizeIt(); //Initial on load
</script>
</body>
</html>
PS: Obviously this JavaScript code is very naive and not well tested, and you probably don't want to use it on textboxes with novels in them, but you get the general idea.
One refinement to some of these answers is to let CSS do more of the work.
The basic route seems to be:
Create a container element to hold the textarea and a hidden div
Using Javascript, keep the textarea’s contents synced with the div’s
Let the browser do the work of calculating the height of that div
Because the browser handles rendering / sizing the hidden div, we avoid
explicitly setting the textarea’s height.
document.addEventListener('DOMContentLoaded', () => {
textArea.addEventListener('change', autosize, false)
textArea.addEventListener('keydown', autosize, false)
textArea.addEventListener('keyup', autosize, false)
autosize()
}, false)
function autosize() {
// Copy textarea contents to div browser will calculate correct height
// of copy, which will make overall container taller, which will make
// textarea taller.
textCopy.innerHTML = textArea.value.replace(/\n/g, '<br/>')
}
html, body, textarea {
font-family: sans-serif;
font-size: 14px;
}
.textarea-container {
position: relative;
}
.textarea-container > div, .textarea-container > textarea {
word-wrap: break-word; /* make sure the div and the textarea wrap words in the same way */
box-sizing: border-box;
padding: 2px;
width: 100%;
}
.textarea-container > textarea {
overflow: hidden;
position: absolute;
height: 100%;
}
.textarea-container > div {
padding-bottom: 1.5em; /* A bit more than one additional line of text. */
visibility: hidden;
}
<div class="textarea-container">
<textarea id="textArea"></textarea>
<div id="textCopy"></div>
</div>
Here's another technique for autosizing a textarea.
Uses pixel height instead of line height: more accurate handling of line wrap if a proportional font is used.
Accepts either ID or element as input
Accepts an optional maximum height parameter - useful if you'd rather not let the text area grow beyond a certain size (keep it all on-screen, avoid breaking layout, etc.)
Tested on Firefox 3 and Internet Explorer 6
Code:
(plain vanilla JavaScript)
function FitToContent(id, maxHeight)
{
var text = id && id.style ? id : document.getElementById(id);
if (!text)
return;
/* Accounts for rows being deleted, pixel value may need adjusting */
if (text.clientHeight == text.scrollHeight) {
text.style.height = "30px";
}
var adjustedHeight = text.clientHeight;
if (!maxHeight || maxHeight > adjustedHeight)
{
adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
if (maxHeight)
adjustedHeight = Math.min(maxHeight, adjustedHeight);
if (adjustedHeight > text.clientHeight)
text.style.height = adjustedHeight + "px";
}
}
Demo:
(uses jQuery, targets on the textarea I'm typing into right now - if you have Firebug installed, paste both samples into the console and test on this page)
$("#post-text").keyup(function()
{
FitToContent(this, document.documentElement.clientHeight)
});
Probably the shortest solution:
jQuery(document).ready(function(){
jQuery("#textArea").on("keydown keyup", function(){
this.style.height = "1px";
this.style.height = (this.scrollHeight) + "px";
});
});
This way you don't need any hidden divs or anything like that.
Note: you might have to play with this.style.height = (this.scrollHeight) + "px"; depending on how you style the textarea (line-height, padding and that kind of stuff).
Here's a Prototype version of resizing a text area that is not dependent on the number of columns in the textarea. This is a superior technique because it allows you to control the text area via CSS as well as have variable width textarea. Additionally, this version displays the number of characters remaining. While not requested, it's a pretty useful feature and is easily removed if unwanted.
//inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
if (window.Widget == undefined) window.Widget = {};
Widget.Textarea = Class.create({
initialize: function(textarea, options)
{
this.textarea = $(textarea);
this.options = $H({
'min_height' : 30,
'max_length' : 400
}).update(options);
this.textarea.observe('keyup', this.refresh.bind(this));
this._shadow = new Element('div').setStyle({
lineHeight : this.textarea.getStyle('lineHeight'),
fontSize : this.textarea.getStyle('fontSize'),
fontFamily : this.textarea.getStyle('fontFamily'),
position : 'absolute',
top: '-10000px',
left: '-10000px',
width: this.textarea.getWidth() + 'px'
});
this.textarea.insert({ after: this._shadow });
this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
this.textarea.insert({after: this._remainingCharacters});
this.refresh();
},
refresh: function()
{
this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
this.textarea.setStyle({
height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
});
var remaining = this.options.get('max_length') - $F(this.textarea).length;
this._remainingCharacters.update(Math.abs(remaining) + ' characters ' + (remaining > 0 ? 'remaining' : 'over the limit'));
}
});
Create the widget by calling new Widget.Textarea('element_id'). The default options can be overridden by passing them as an object, e.g. new Widget.Textarea('element_id', { max_length: 600, min_height: 50}). If you want to create it for all textareas on the page, do something like:
Event.observe(window, 'load', function() {
$$('textarea').each(function(textarea) {
new Widget.Textarea(textarea);
});
});
Here is a solution with JQuery:
$(document).ready(function() {
var $abc = $("#abc");
$abc.css("height", $abc.attr("scrollHeight"));
})
abc is a teaxtarea.
Check the below link:
http://james.padolsey.com/javascript/jquery-plugin-autoresize/
$(document).ready(function () {
$('.ExpandableTextCSS').autoResize({
// On resize:
onResize: function () {
$(this).css({ opacity: 0.8 });
},
// After resize:
animateCallback: function () {
$(this).css({ opacity: 1 });
},
// Quite slow animation:
animateDuration: 300,
// More extra space:
extraSpace:20,
//Textarea height limit
limit:10
});
});
Just revisiting this, I've made it a little bit tidier (though someone who is full bottle on Prototype/JavaScript could suggest improvements?).
var TextAreaResize = Class.create();
TextAreaResize.prototype = {
initialize: function(element, options) {
element = $(element);
this.element = element;
this.options = Object.extend(
{},
options || {});
Event.observe(this.element, 'keyup',
this.onKeyUp.bindAsEventListener(this));
this.onKeyUp();
},
onKeyUp: function() {
// We need this variable because "this" changes in the scope of the
// function below.
var cols = this.element.cols;
var linecount = 0;
$A(this.element.value.split("\n")).each(function(l) {
// We take long lines into account via the cols divide.
linecount += 1 + Math.floor(l.length / cols);
})
this.element.rows = linecount;
}
}
Just it call with:
new TextAreaResize('textarea_id_name_here');
I've made something quite easy. First I put the TextArea into a DIV. Second, I've called on the ready function to this script.
<div id="divTable">
<textarea ID="txt" Rows="1" TextMode="MultiLine" />
</div>
$(document).ready(function () {
var heightTextArea = $('#txt').height();
var divTable = document.getElementById('divTable');
$('#txt').attr('rows', parseInt(parseInt(divTable .style.height) / parseInt(altoFila)));
});
Simple. It is the maximum height of the div once it is rendered, divided by the height of one TextArea of one row.
I needed this function for myself, but none of the ones from here worked as I needed them.
So I used Orion's code and changed it.
I added in a minimum height, so that on the destruct it does not get too small.
function resizeIt( id, maxHeight, minHeight ) {
var text = id && id.style ? id : document.getElementById(id);
var str = text.value;
var cols = text.cols;
var linecount = 0;
var arStr = str.split( "\n" );
$(arStr).each(function(s) {
linecount = linecount + 1 + Math.floor(arStr[s].length / cols); // take into account long lines
});
linecount++;
linecount = Math.max(minHeight, linecount);
linecount = Math.min(maxHeight, linecount);
text.rows = linecount;
};
Like the answer of #memical.
However I found some improvements. You can use the jQuery height() function. But be aware of padding-top and padding-bottom pixels. Otherwise your textarea will grow too fast.
$(document).ready(function() {
$textarea = $("#my-textarea");
// There is some diff between scrollheight and height:
// padding-top and padding-bottom
var diff = $textarea.prop("scrollHeight") - $textarea.height();
$textarea.live("keyup", function() {
var height = $textarea.prop("scrollHeight") - diff;
$textarea.height(height);
});
});
My solution not using jQuery (because sometimes they don't have to be the same thing) is below. Though it was only tested in Internet Explorer 7, so the community can point out all the reasons this is wrong:
textarea.onkeyup = function () { this.style.height = this.scrollHeight + 'px'; }
So far I really like how it's working, and I don't care about other browsers, so I'll probably apply it to all my textareas:
// Make all textareas auto-resize vertically
var textareas = document.getElementsByTagName('textarea');
for (i = 0; i<textareas.length; i++)
{
// Retain textarea's starting height as its minimum height
textareas[i].minHeight = textareas[i].offsetHeight;
textareas[i].onkeyup = function () {
this.style.height = Math.max(this.scrollHeight, this.minHeight) + 'px';
}
textareas[i].onkeyup(); // Trigger once to set initial height
}
Here is an extension to the Prototype widget that Jeremy posted on June 4th:
It stops the user from entering more characters if you're using limits in textareas. It checks if there are characters left. If the user copies text into the textarea, the text is cut off at the max. length:
/**
* Prototype Widget: Textarea
* Automatically resizes a textarea and displays the number of remaining chars
*
* From: http://stackoverflow.com/questions/7477/autosizing-textarea
* Inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
*/
if (window.Widget == undefined) window.Widget = {};
Widget.Textarea = Class.create({
initialize: function(textarea, options){
this.textarea = $(textarea);
this.options = $H({
'min_height' : 30,
'max_length' : 400
}).update(options);
this.textarea.observe('keyup', this.refresh.bind(this));
this._shadow = new Element('div').setStyle({
lineHeight : this.textarea.getStyle('lineHeight'),
fontSize : this.textarea.getStyle('fontSize'),
fontFamily : this.textarea.getStyle('fontFamily'),
position : 'absolute',
top: '-10000px',
left: '-10000px',
width: this.textarea.getWidth() + 'px'
});
this.textarea.insert({ after: this._shadow });
this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
this.textarea.insert({after: this._remainingCharacters});
this.refresh();
},
refresh: function(){
this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
this.textarea.setStyle({
height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
});
// Keep the text/character count inside the limits:
if($F(this.textarea).length > this.options.get('max_length')){
text = $F(this.textarea).substring(0, this.options.get('max_length'));
this.textarea.value = text;
return false;
}
var remaining = this.options.get('max_length') - $F(this.textarea).length;
this._remainingCharacters.update(Math.abs(remaining) + ' characters remaining'));
}
});
#memical had an awesome solution for setting the height of the textarea on pageload with jQuery, but for my application I wanted to be able to increase the height of the textarea as the user added more content. I built off memical's solution with the following:
$(document).ready(function() {
var $textarea = $("p.body textarea");
$textarea.css("height", ($textarea.attr("scrollHeight") + 20));
$textarea.keyup(function(){
var current_height = $textarea.css("height").replace("px", "")*1;
if (current_height + 5 <= $textarea.attr("scrollHeight")) {
$textarea.css("height", ($textarea.attr("scrollHeight") + 20));
}
});
});
It's not very smooth but it's also not a client-facing application, so smoothness doesn't really matter. (Had this been client-facing, I probably would have just used an auto-resize jQuery plugin.)
For those that are coding for IE and encounter this problem. IE has a little trick that makes it 100% CSS.
<TEXTAREA style="overflow: visible;" cols="100" ....></TEXTAREA>
You can even provide a value for rows="n" which IE will ignore, but other browsers will use. I really hate coding that implements IE hacks, but this one is very helpful. It is possible that it only works in Quirks mode.
Internet Explorer, Safari, Chrome and Opera users need to remember to explicidly set the line-height value in CSS. I do a stylesheet that sets the initial properites for all text boxes as follows.
<style>
TEXTAREA { line-height: 14px; font-size: 12px; font-family: arial }
</style>
Here is a function I just wrote in jQuery to do it - you can port it to Prototype, but they don't support the "liveness" of jQuery so elements added by Ajax requests will not respond.
This version not only expands, but it also contracts when delete or backspace is pressed.
This version relies on jQuery 1.4.2.
Enjoy ;)
http://pastebin.com/SUKeBtnx
Usage:
$("#sometextarea").textareacontrol();
or (any jQuery selector for example)
$("textarea").textareacontrol();
It was tested on Internet Explorer 7/Internet Explorer 8, Firefox 3.5, and Chrome. All works fine.
Using ASP.NET, just simply do this:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Automatic Resize TextBox</title>
<script type="text/javascript">
function setHeight(txtarea) {
txtarea.style.height = txtdesc.scrollHeight + "px";
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox ID="txtarea" runat= "server" TextMode="MultiLine" onkeyup="setHeight(this);" onkeydown="setHeight(this);" />
</form>
</body>
</html>

Categories