CSS transition depends on order of style assignments - javascript

Trying to make a container with text gradually expand upon adding new text to it, I used css transition property. Precisely, I fix current width, add text and then release the width. JS code is following:
footer.style['max-width'] = footer.offsetWidth + 'px'
footer.innerHTML += ' additional text'
footer.style['max-width'] = '500px'
with this css for footer:
overflow: hidden;
text-overflow: clip;
white-space: nowrap;
This did't work. Trying to find a workaround I added another line of code:
footer.style['height'] = footer.offsetHeight + 'px'
Now, with this line being put before assignment of max-width (so in the beginning of the snippet), it doesn't work. But putting it after that line (making it second line) — does. The question is why? and what is the proper way to work with transitions? (but mainly, why?)
Fiddle tested in firefox 40.0 and chrome 39.0: http://jsfiddle.net/53dbm6vz/

It's likely that the problem is that both of your footer.style['max-width'] assignments occur inside the same synchronous operation. The browser(s) probably ignore the intermediate value completely.
It can be resolved if you split the operation to 2 parts:
Set the initialization width and...
Use a setTimeout to trigger the actual assignment.
Try like this:
footer.style['max-width'] = footer.offsetWidth + 'px'
window.setTimeout(function() {
footer.innerHTML += ' additional text'
footer.style['max-width'] = '500px'
}, 0)

Related

max-height of a div cannot be set programatically

I am trying to create a dynamic layout of divs (100% wide top to bottom) that can be opened and closed and I don't want the content to extend beyond the bottom of the page so when the open/closed state changes I run code like this:
// BUG: maxHeight exists in the DOM but apparently cannot be programatically set
e.style.maxHeight = h;
alert('Element ' + e.id + ' was set to have a maxHeight of ' + h + ' but actually has a maxHeight of ' + e.style.maxHeight + '.');
The alert always shows no change to the max-height regardless of its initial value. This happens to be on divs. All elements have a display style of block. The debugger is showing no exceptions. Happens on Chrome, IE and Firefox. Setting max-height via a style string is no problem.
I am not doing any fancy CSS such as float, position, or border-box stuff either.
Other related answers I have seen here would seem to say this should work.
Like all dimension values in JS (height,width,top,bottom,etc.), the value(h in this case) must have a unit defined for this to work:
e.style.maxHeight = h + "px";
JSFiddle Demo

How to apply the offset .top to the height of a div?

On this blog I want to edit the height of the #content div and make it height: x.top px (of the article:last-child) so that the background which is repeating itself vertically.
http://manutdstream.tumblr.com/
I tried to do this:
$(document).ready(function(){
x=$("article:last-child").offset();
$('#content').css('height' : 'x.top px');
});
I think the problem is in the .css() as when I ran it to alert the x.top it went fine.
Your variable is being treated as a string, place it outside the quotes and add it to the string with a +:
$(document).ready(function(){
var x = $("article:last-child").offset();
$('#content').css('height' : x.top + 'px');
});
If you're just setting the height, no need to bother with css. Pixels is the default unit for the height function:
$(document).ready(function(){
var lastArticle = $("article:last-child");
$('#content').height(lastArticle.offset().top);
});
Not to nit-pick, but I'd recommend against using variables named something like x even for simple things -- unless you actually mean x (for example, coordinate spaces). Code is already hard to read, but good names can make it easier.
The syntax for .css() is incorrect, should be
$('#content').css('height', x.top + 'px');
Fiddle example:
http://jsfiddle.net/jessikwa/5vnbLr91/

How do I get the height of a textarea

I need to get the height of a textarea. Seemingly so simple but it's driving me mad.
I have been researching for ages on stackoverflow with no luck: textarea-value-height and jquery-js-get-the-scrollbar-height-of-an-textarea and javascript-how-to-get-the-height-of-text-inside-of-a-textarea, among many others.
This is how it looks currently:
This is how I want it to look, open a full height:
.
Here is my html:
<textarea id="history" class="input-xxlarge" placeholder="Enter the content ..." rows="13"></textarea>
CSS:
.input-xxlarge {
display: inline-block;
height: auto;
font-size: 12px;
width: 530px;
resize: none;
overflow: auto;
}
jQuery:
var textarea = $('#history');
I've tried (inter alia):
1. textarea.height() --> always returns 0
2. textarea.ready(function() { // wait for DOM to load
textarea.height();
}
3. getting scrollheight from textarea as an HTMLTextareaElement (i.e. DOM Element) --> returns 0
4. var contentSpan = textarea.wrapInner('<span>');
var height = contentSpan.height(); --> always returns 0
Please help, I'm at my wit's end!
Ok, I've found a solution. Whether it's the best solution, I don't know, but it works and that, frankly, is all I care about, having spent almost a day on this issue.
Here it is for anyone who faces the same problem:
Select the textarea:
var textarea = $('#history');
Get the textarea's text:
var text = textarea.text();
Create a temporary div:
var div = $('<div id="temp"></div>');
Set the temp div's width to be the same as the textarea. Very important else the text will be all on one line in the new temp div!:
div.css({
"width":"530px"
});
Insert the text into the new temp div:
div.text(text);
Append it to the DOM:
$('body').append(div);
Get the height of the div:
var divHeight = $('#temp').height();
Remove the temp div from the DOM:
div.remove();
Had a similar issue, in my case I wanted to have an expand button, that would toggle between two states (expanded/collapsed). After searching also for hours I finally came up with this solution:
Use the .prop to get the content height - works with dynamically filled textareas and then on a load command set it to your textarea.
Get the inner height:
var innerHeight = $('#MyTextarea').prop('scrollHeight');
Set it to your element
$('#MyTextarea').height(innerHeight);
Complete code with my expand button(I had min-height set on my textarea):
$(document).on("click", '.expand-textarea', function () {
$(this).toggleClass('Expanded');
if($(this).hasClass('Expanded'))
$($(this).data('target')).height(1);
else
$($(this).data('target')).height($($(this).data('target')).prop('scrollHeight'));
});
Modern answer: textarea sizing is a few lines of ES6 implementable two primary ways. It does not require (or benefit from) jQuery, nor does it require duplication of the content being sized.
As this is most often required to implement the functionality of auto-sizing, the code given below implements this feature. If your modal dialog containing the text area is not artificially constrained, but can adapt to the inner content size, this can be a perfect solution. E.g. don't specify the modal body's height and remove overflow-y directives. (Then no JS will be required to adjust the modal height at all.)
See the final section for additional details if you really, truly only actually need to fetch the height, not adapt the height of the textarea itself.
Line–Based
Pro: almost trivial. Pro: exploits existing user-agent behavior which does the heavy lifting (font metric calculations) for you. Con: impossible to animate. Con: extended to support constraints as per my codepen used to explore this problem, constraints are encoded into the HTML, not part of the CSS, as data attributes.
/* Lines must not wrap using this technique. */
textarea { overflow-x: auto; white-space: nowrap; resize: none }
for ( let elem of document.getElementsByTagName('textarea') ) {
// Prevent "jagged flashes" as lines are added.
elem.addEventListener('keydown', e => if ( e.which === 13 ) e.target.rows = e.target.rows + 1)
// React to the finalization of keyboard entry.
elem.addEventListener('keyup', e => e.target.rows = (elem.value.match(/\n/g) || "").length + 1)
}
Scrollable Region–Based
Pro: still almost trivial. Pro: animatable in CSS (i.e. using transition), though with some mild difficulty relating to collapsing back down. Pro: constraints defined in CSS through min-height and max-height. Con: unless carefully calculated, constraints may crop lines.
for ( let elem of document.getElementsByTagName('textarea') )
elem.addEventListener('keyup', e => {
e.target.style.height = 0 // SEE NOTE
e.target.style.height = e.target.scrollHeight + 'px'
})
A shocking percentage of the search results utilizing scrollHeight never consider the case of reducing size; for details, see below. Or they utilize events "in the wrong order" resulting in an apparent delay between entry and update, e.g. pressing enter… then any other key in order to update. Example.
Solution to Initial Question
The initial question specifically related to fetching the height of a textarea. The second approach to auto-sizing, there, demonstrates the solution to that specific question in relation to the actual content. scrollHeight contains the height of the element regardless of constraint, e.g. its inner content size.
Note: scrollHeight is technically the Math.max() of the element's outer height or the inner height, whichever is larger. Thus the initial assignment of zero height. Without this, the textarea would expand, but never collapse. Initial assignment of zero ensures you retrieve the actual inner content height. For sampling without alteration, remove the height override (assign '') or preserve (prior to) then restore after retrieval of scrolllHeight.
To calculate just the height of the element as-is, utilize getComputedStyle and parse the result:
parseInt(getComputedStyle(elem).height, 10)
But really, please consider just adjusting the CSS to permit the modal to expand naturally rather than involving JavaScript at all.
Place this BEFORE any HTML elements.
<script src="/path/to/jquery.js"></script>
<script>
$(document).ready(function(){
var textarea = $('#history');
alert(textarea.height()); //returns correct height
});
</script>
You obviously do not have to alert it. I was just using an easily visible example.
Given a textarea with an id of "history", this jQuery will return it's height:
$('#history').height()
Please see a working example at http://jsfiddle.net/jhfrench/JcGGR/
You can also retrieve the height in pixels by using $('#history').css('height'); if you're not planning on doing any calculations.
for current height in px:
height = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('height')
for current width in px:
width = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('width')
change 'textarea' to '#history' or like a css selector. or textarea, since a variable is declared to select element.

change css on scroll event w/ requestAnimation Frame

I want to change the background color of in-viewport elements (using overflow: scroll)
So here was my first attempt:
http://jsfiddle.net/2YeZG/
As you see, there is a brief flicker of the previous color before the new color is painted. Others have had similar problems.
Following the HTML5 rocks instructions, I tried to introduce requestAnimationFrame to fix this problem to no avail:
http://jsfiddle.net/RETbF/
What am I doing wrong here?
Here is a simpler example showing the same problem: http://jsfiddle.net/HJ9ng/
Filed bug with Chromium here: http://code.google.com/p/chromium/issues/detail?id=151880
if it is only the background color, well why don't you just change the parent background color to red and once it scroll just change it to pink?
I change your CSS to that
#dad
{
overflow-y: scroll;
overflow-x: hidden;
width: 100px;
height: 600px;
background-color:red;
}​
I remove some of you Jquery and change it to this
dad.bind('scroll', function() {
dad.css('background-color', 'pink');
});
And I remove this line
iChild.css('backgroundColor', 'red');
But is the Red color it is important that won't work for sure http://jsfiddle.net/2YeZG/5/
I like Manuel's Solution.
But even though I don't get what you're exactly trying to do, I want to point out a few things.
In your fiddle code, I saw that you included Paul Irish's Shim for requestAnimationFrame.
But you never use it.
(It's basically a reliable setTimeOut, nothing else) it's from frame based animations.)
So since you just want to change some CSS properties, I don't see why you would need it. Even if you want transitions, you should rely on CSS transitions.
Other than that your code could look something like
dad.bind('scroll', function() {
dad.css('background-color', 'pink');
eachElemNameHere.css('background-color','randomColor');
});
Also you should ideally not use something like that if you can help it. You should just add and remove class names and add all these properties in your CSS. Makes it work faster.
Also, again I don't quite get it, but you could use the jQuery function to find out each elements' position from the top to have better control.
Your problem seems to be that you only change the background color of the elements which have already been scrolled into view. Your code expects that the browser waits for your code to handle the scroll event before the browser redraws its view. This is most probably not a guarantee given by the HTML spec. That's why it flickers.
What you should do instead is to change the elements which are going to be scrolled into view. This is related to off screen rendering or double buffering as it is called in computer games programming. You build your scene off screen and copy the finished scene to the visible frame buffer.
I modified your first JSFiddle to include a multiplier for the height of the scroll area: http://jsfiddle.net/2YeZG/13/.
dad.bind('scroll', function() {
// new: query multiplier from input field (for demonstration only) and print message
var multiplier = +($("#multiplier")[0].value);
$("#message")[0].innerHTML=(multiplier*100)-100 + "% of screen rendering";
// your original code
var newScrollY = newScrollY = dad.scrollTop();
var isForward = newScrollY > oldScrollY;
var minVal = bSearch(bots, newScrollY, true);
// new: expand covered height by the given multiplier
// multiplier = 1 is similar to your code
// multiplier = 2 would be complete off screen rendering
var newScrollYHt = newScrollY + multiplier * dadHeight;
// your original code (continued)
var maxVal;
for (maxVal = minVal; maxVal < botsLen; maxVal++) {
var nxtTopSide = tops[maxVal];
if (nxtTopSide >= newScrollYHt) {
break;
}
}
maxVal = Math.min(maxVal, botsLen);
$(dadKids.slice(minVal, maxVal)).css('background', 'pink');
});
Your code had a multiplier of 1, meaning that you update the elements which are currently visible (100% of scroll area height). If you set the multiplier to 2, you get complete off screen updates for all your elements. The browser updates enough elements to the new background color so that even a 100% scroll would show updated elements. Since the browser seldom scrolls 100% of the area in one step (depends of the operating system and the scroll method!), it may be sufficient to reduce the multiplier to e.g. 1.5 (meaning 50% off screen rendering). On my machine (Google Chrome, Mac OS X with touch pad) I cannot produce any flicker if the multiplier is 1.7 or above.
BTW: If you do something more complicated than just changing the background color, you should not do it again and again. Instead you should check whether the element has already been updated and perform the change only afterwards.

define css properties with jquery before using css transition issue

I've found that there seems to be a problem using css transitions properties when they are initially set to auto. To circumvent this I've set the initial css properties using jquery, before adding the css transition property.
The issue I'm having is that when I define the transitional properties immediately after setting the initial css properties, I get weird behaviour. EXAMPLE: http://jsfiddle.net/3zUDc/10/
However, when I delay setting the transitional properties by a few milliseconds, I get the intended behaviour, but the code seems uglier. EXAMPLE: http://jsfiddle.net/3zUDc/9/
Is there a way to accomplish the behaviour seen in the second example without putting the css transitions and destination parameters in the setTimeout block?
Thanks for any help!
.show() is an answer...
$('a:first').click(function(){
$(this).css({'width': $(this).width() / $(this).parent().width() * 100 + '%', 'height': $(this).height()});
$('a:first').show().css({
'-webkit-transition': 'all 3s',
'-moz-transition': 'all 3s',
width: '100%',
height: '100px',
backgroundColor: 'black'
});
});
Here is the jsfiddle demo
You can add .css('left') to the end of your css declaration: http://jsfiddle.net/YDt7G/
The reason this works (or doesn't work) is because the browser's javascript engine optimises code that changes the DOM. So it doesn't update the DOM instantly after every line of code and is basically putting all the code into one DOM update.
Adding the .css('left') forces browser's javascript engine to look at the DOM and in-turn update the DOM beforehand.

Categories