JQuery not getting correct width - javascript

I've used this script to get a width and then apply it to the same element:
$(document).ready(function(){
$(".equal-height").each(function(){
var slideSize = $(this).outerWidth();
console.log(slideSize);
$(this).css({ "height" : slideSize + "px" });
});
});
However, for some reason, there are elements that sometimes don't get a matching width and height. As you can see in this fiddle: https://jsfiddle.net/cpfgtuzo/5/ the last element has the correct dimensions, but the rest are all higher than their width. I'm trying to get them all to be square and I need to support old browsers too.
This only seems to be an issue when the size of the window is smaller and the four items stack in into a 2 column.

After your comments on other answer,
I've got numerous elements on the page that use this script and not all are the same size (there are smaller sets of squares too)
And
but the resulting box isn't coming out square. If you inspect your fiddle, the boxes are ~10px too tall
This solution seems to overcome those problems, Let me know if this helps, Working Fiddle
$(document).ready(function () {
$(".equal-height").each(function () {
var slideSize = $(this).outerWidth();
console.log(slideSize);
$(this).css({ "height": slideSize + "px", "width": slideSize + "px" });
//setting the width along with height
});
});

Hmm I think there is a bug with jQuery, when it is calculating the width of each element.
Take this jsfiddle as a workaround.
// Height = Width
$(document).ready(function() {
var width = $('.wide-content').width();
// prevent jQuery from calculating the width of children
$('.wide-content').hide();
// $(".equal-height").width() is now 50
var slideSize = $(".equal-height").width() * width / 100;
$(".equal-height").each(function() {
$(this).css({
"height": slideSize + "px"
});
});
$('.wide-content').show();
});

Same height on all elements
I'd just use the first box to calculate the height for the other elements - atleast this would ensure the same height. Also it would get rid of that loop..
$(".equal-height").css({"height" : $(".equal-height").eq(0).outerWidth()});
One line to rule them all
But, since this did not fit the scope..
Making squares of differently sized elements
After some messing about it's clear that the widths are returned wrong only after you start tampering with the height. This can easily be tested by commenting out the css-command that sets the height and observing the output.
The solution seems to be to set a predefined height:
.link-quarters {
width: 25%;
height: 100px;
float: left;
...
This will return the exact same width on all elements (the important part) and you can then set the corresponding height programtically without issues.
There's still an issue with rounding though, as the percentage-width might result in decimal numbers that gets rounded by the browser (or js).
https://jsfiddle.net/cpfgtuzo/17/

Related

JS function - Math optimization, off by 1 in some cases

I'm still wet behind the ears with web dev, not the best at math, and have problems moving on when something is still broken. Hopefully you guys can help.
Quick: I'm using Jquery to make some (dynamic in number) divs in my header overlap by 30%, filling the entire width of the container. My current iteration rounds up one too many times, so my last element goes beneath the rest.
I have X elements filling the full width of my header container. Each element overlaps by 30% on either side. In an equation, I can work out the math no problem. Ensuring pixel precision with these numbers has proven more difficult. This is what I'm using to determine the width of each element.
width of element = [container width] / ((.7 * ([# of elements] - 1)) + 1)
left margin of element = [width of element] * .3
I make variables I call extraWidth and extraMargin which are the width and margin % 1 respectively. The default element width I use now is width-(width%1). For every element, I add the extraWidth and extraMargin to running total variables. Any time the total of either of these variables exceeds .5, that particular element has its width or margin set 1 higher than the default.
So I don't run on any longer, here's a JSFiddle with everything necessary to see what I'm dealing with. It runs fine most of the time, but at certain widths I'm 1 pixel too wide.
p.s.
Ran the JSFiddle, didn't work the same way as my live sandbox site, so check that out here. I feel like I included all the necessary bits, but I can't say for sure. On my Chrome, when window size is 575px (among many other widths) it's messed up.
EDIT
It should be noted that I'm making changes to my live site without updating this post. I'm not deleting any functions just yet though, just making new ones/minor alterations to existing ones.
Recursion! Recursion was the most elegant answer (which appears to work in ALL cases) I could come up with.
Iterating through my jQuery object one element at a time and calculating the width and margin based on the remaining container width rather than the whole container width makes this much easier to calculate.
function circleWidth(circles, containerWidth) {
var width = containerWidth / ((.7 * (circles.length - 1)) + 1);
var pxWidth = Math.round(width);
var margin = width * .3;
var pxMargin = Math.round(margin);
$(circles[0]).css({
'width': pxWidth + "px",
'margin-left': "-" + pxMargin + "px"
});
containerWidth -= (pxWidth - pxMargin);
if (circles.length > 1) {
circleWidth(circles.slice(1), containerWidth);
}
}
function circleSize(circles, containerWidth) {
var height = Math.ceil(containerWidth / ((.7 * (circles.length - 1)) + 1));
circles.each(function() {
$(this).css({
'height': height + "px"
});
});
circleWidth(circles, containerWidth);
$(circles[circles.length]).css({
'margin-left': $(circles[0]).css('margin-left')
});
$(circles[0]).css({
'margin-left': 0
});
}
Here's the fiddle with my final result. I'm sure I still have some optimization to do, but at least it's working now.
You have 2 choices:
Calculate pixelMargin as next integer. like:
var pixelMargin = Math.ceil(circleMargin);
or you can use pixelMargin in %.
1st one worked for me.

jquery returning different height everytime I reload

I am trying to create a light box kind of thing in jQuery. For vertically aligning my lightbox,I am using jQuery. Here is my plugin code:
(function($){
$.fn.lightbox = function(){
return this.each(function(){
/*plugin code starts here*/
var self = this;
console.log(self);
/*
* Now we will vertically align the lightbox
* To do that we will calculate the body's height,lightboxes height
* and then subtract later from earlier one.This will give us the total empty space
* So the margin from the top of lightbox will be half of the result we got from subtraction
*/
//calculating body's height
var doc_body_height = $('body').height();
var lightbox_height = $(self).height();
var margin_top = (doc_body_height - lightbox_height)/2;
$(self).css('margin-top',margin_top);
console.log($(self).height());
/*plugin code ends here*/
});
}
})(jQuery);
But the problem is, I am getting either 18 or 300 as height. 300 is the actual height of the div#lightbox,I don't know why the same function is returning different heights randomly.
See Image:
Clearly the div#lightbox is not 18px in height.
You are calculating the height using the $('body').height(). This is the computed value for the height of the body element. That means that for a page with just one visible element that is 50px high on it, the body will return 50px. Conversely, a long page that requires lots of scrolling will return the entire body height, not just the portion that is visible in the viewport.
You need to use $(window).height(); in your calculation instead.
But the problem is, I am getting either 18 or 300 as height. 300 is
the actual height of the div#lightbox,I don't know why the same
function is returning different heights randomly -Rajat Saxena
At original post
var self = this;
console.log(self);
var lightbox_height = $(self).height();
window.innerHeight appear to return viewport of window . See Window.innerHeight .
Try, at console , this page , while periodically adjusting console "height" , and within piece at original post
console.log($(window).height()
, $(self).height()
, $(window)[0].innerHeight
, $(window).height() === $(self).height()
, $(this).height());
If you're only supporting modern browsers then you could use CSS and take advantage of a flexbox http://css-tricks.com/snippets/css/a-guide-to-flexbox/

jQuery ui size effect is not resizing to the specified width/height

jQuery UI v1.8.17 (testing in FF 10.0 on Ubuntu)
Update: I've put my script and html on jsFiddle: http://jsfiddle.net/JhqrX/3/
We are trying to fit large data tables into a fixed width design, and have opted for initially displaying a scaled down version of the table which can be clicked on to view at 100%.
I have found the jQuery UI size effect method, and it has a nice effect where it also scales everything inside the tables (cells, padding, text/font).
However, one problem is that we have to specify the new height and width (it would be great if we could just pass a width and it maintained aspect ratios) - but the other, much larger, problem is that it is not actually sizing to the specified dimensions.
For example - I have a table that is 502x60 and want that to fit into 300x36. Passing this height and width as parameters into the size method gets me a table that is about 354x40. When I reset to 502px in a subsequent size request, it actually is set to about 492px. Subsequent resizing seems to bounce between a width of 334 (when I want 300) and 492 (when I want 502).
$(document).ready(function() {
/* create a selector for all tables over the width limit */
$.expr[':'].wideTable = function(obj) {
return $(obj).width() > 300;
}
/* create an array of width table dimensions */
var wideTableWidths = [];
$('table:wideTable').each(function() {
wideTableWidths[$(this).attr('id')] = {
width: $(this).width(),
height: $(this).height(),
ratio: $(this).height() / $(this).width(),
scaled: false,
};
});
/* set up the click event to resize the tables */
$('table:wideTable').click(function() {
if (wideTableWidths[$(this).attr('id')].scaled) {
/* if the table is currently scaled, we can reset to original height and width as stored */
$(this).effect("size", {to: {width: wideTableWidths[$(this).attr('id')].width, height: wideTableWidths[$(this).attr('id')].height} }, 0);
wideTableWidths[$(this).attr('id')].scaled = false;
} else {
/* if the table requires scaling, we know we want a width of 300px and the height should be set to match the original aspect ratio */
$(this).effect("size", {to: {width: 300, height: 300 * wideTableWidths[$(this).attr('id')].ratio} }, 0);
wideTableWidths[$(this).attr('id')].scaled = true;
}
});
/* initialise the page so that all wide tables are scaled to fit */
$('table:wideTable').click();
});
Reviewing the jsFiddle you have provided, I found the solution to the problem.
The initial ratio calculation doesn't take into account the padding and border values of table td.
You need to subtract these from the height and width.
This updated jsFiddle demonstrates the solution.
Hope that helps.
I'm not sure this is related, but what is your doc type? I had issues with height/width calculations and not having a doctype defined with jqueryui. Try <!DOCTYPE html> if you dont already have one.
I noticed that you have not set the scale argument within your .effect call.
The default value for scale is both which means that the resize affects both border and padding values.
In obtaining your original height and width values, you have used:
width: $(this).width()
height: $(this).height()
which return the content width of the elements (ie, not including the border, padding, or margin).
You can try using the .outerWidth() and .outerHeight() methods which include the border and padding, or specify scale: 'content' in your call to the .effect method. For example:
$(this).effect("size", {to: {width: 300, height: 300 * wideTableWidths[$(this).attr('id')].ratio, scale: 'content'} }, 0);

Animate DIV to full height and toggle back to defined height

I am trying to animate the div to its full height when a button is pressed and come back to its original height if the button is clicked again. The full height of the div is auto as it contains text with different word counts. I tried doing the below codes but it does not work properly.
The CSS :
.category_brief{
text-align:justify;
height:100px;
overflow:hidden;
}
Example 1 : This code does not animate the div when opening to full height , but animates while coming back to old height.
$(".slide").toggle(function(){
$('.category_brief').animate({height:'100%'},200);
},function(){
$('.category_brief').animate({height:100},200);
});
Example 2 : The output of this code is the same as of Example 1
var toggle = true, oldHeight = 0;
$('.slide').click(function(event) {
event.preventDefault();
var $ele = $('.category_brief');
var toHeight = ((toggle = !toggle) ? oldHeight : newHeight);
oldHeight = $ele.height();
var newHeight = $ele.height('auto').height();
$ele.animate({ height: toHeight });
});
Example 3 : This code animates the div to its full height but does not toggle.
var slide = $('.slide');
var slidepanel = $('.category_brief');
// On click, animate it to its full natural height
slide.click(function(event) {
event.preventDefault();
var oldHeight, newHeight;
// Measure before and after
oldHeight = slidepanel.height();
newHeight = slidepanel.height('auto').height();
// Put back the short height (you could grab this first
slidepanel.height(oldHeight);
slidepanel.animate({height: newHeight + "px"});
});
If possible please provide a bit explanation also as i am a newbie..
Update : Solved by the idea from #chazm..
#chazm : thanks for the idea. I got it working by combining 1st and 3rd example ... Here is the code in case anyone needs it .
var slidepanel = $('.category_brief');
$(".slide").toggle(function(){
var oldHeight, newHeight;
// Measure before and after
oldHeight = slidepanel.height();
newHeight = slidepanel.height('auto').height();
// Put back the short height (you could grab this first
slidepanel.height(oldHeight);
slidepanel.animate({height: newHeight + "px"})
},function(){
$('.category_brief').animate({height:100},300);
});
Working with 'auto' height it always quite tricky. I think there are different issues in your examples.
1) Browser can't define correct 100% height. Possible solutions - define height to all its parents. Either set it to 100% (till html tag) or set closest parent as relative (because height is calculated from closest relative parent). If you want to animate div to 100% of the entire page - think of the absolute positioning
2)The same as above i assume
3)When this code supposed to toggle back it can't determine that it should become lower that it is now. Not absolutely sure why though. Probably because 'auto' height from 100% is set to something wrong. You may check in firebug what value it has on the computed tab after that function is toggled back. Probably it will give you a clue
Try to combine 2) and 3). The idea - if toggle is true (it shoud be lowered) then set newHeight = slidepanel.height('100').
The solution depends on your implementation needs. If you know that at first the div should be 100px etc in height and when you click, it maximizes to an unknown height, the following solution would work. If you had a structure similar to
<div class="outer">
<div class="wrapper">Content of unknown length here</div>
</div>
and css
div.wrapper { position:relative; height:100px; overflow:hidden; }
div.outer { position:absolute; height:auto; }
then you'd get a div that is 100px in height, with the content that doesn't fit in 100px cut off. Now when you press the desired button, you could get the height of the wrapper div, since it is a long as it's content is (even though you only see the top 100px) and set the outer div's height according to it. Like so
var newHeight = $('div.wrapper').height();
$('div.outer').animate({height:newHeight},200);
Which would then animate the outer div to display the whole contents. When you click the button again, you could just do
$('div.outer').animate({height:'100px'},200);
And you would again have only the 100px height.

jQuery calculation doesn't add up as expected when toggling height

I have the following function for calculating the height of .node. It then takes away the height of a possible image, .node-image, from the height of the .node, and sets a column, .node-content-column to have a height that is the difference (i.e. 500 - 50 = 450; column becomes 450 in height).
function initColumnSizer() {
imageHeight = $('.node-image').outerHeight(true);
resizeHeight = ($('.node').outerHeight() + 75) - imageHeight;
$('.node-content-column').removeAttr('style');
$('.node-content-column').css('min-height', resizeHeight);
$('.node-content-column').css('height', 'auto !important');
$('.node-content-column').css('height', resizeHeight);
}
This function gets called on page load, and resizes .node-content-column as expected.
It also gets called when a div within .node is toggled using jQuery.toggle(), but this calculation returns a larger number everytime, instead of reverting back to the original once this toggle is reverted.
Can anyone see where I am going wrong with this calculation? Or if I am going about it the wrong way?
Thanks in advance!
Karl
1) Maybe the problem is in outerHeight() function (it takes into account padding and border). Try using just height or clientHeight:
var img = document.getElementById('imageid');
//or however you get a handle to the IMG
var width = img.clientWidth;
var height = img.clientHeight;
2) why do you need to cleanup the whole elements' style?
and then you try to assign height = auto, and after that: height = resizeHeight - what's the purpose for that ? check the logic of your code.
outerHeight(true) will return height + padding + border + margin. Possibly, you might want to use height() ?
Most possible is that "larger number everytime" have always constant difference -- for example 75.
May be you just have some dependecies between .node-content-column and .node?
If your nodes like .node-content-column, .node and .node-image are all singles, then it's better to use IDs for them -- not CSS classes.

Categories