I just ran into the weirdest of bugs today. I'm not sure if it's a bug in Chrome or something that I can work around but here goes.
I built a JQuery function to resize a set of images that are posted on a forum:
$(".post-message img.post-image").load(function(){
$(this).each(function() {
var maxWidth = 200;
if($(this).width() > maxWidth)
{
var factor = $(this).width() / maxWidth;
var width = $(this).width();
var height = $(this).height();
$(this).css('width', width / factor);
$(this).css('height', height / factor);
}
});
});
The problem is that this only seems to work when I refresh the page. It doesn't work when you press previous or when you get linked to the page.
In chrome the $(img).width() property returns 0 in both cases when the function doesn't work.
This function performs as expected in IE9 and FF3
What can I do to fix this odd behavior?
Most probably because the images are being pulled up from the browser cache, and the load event is not triggering. The way around this is to manually trigger load if the images's complete properties have been set:
$(".post-message img.post-image").one("load", function(){
$(this).each(function() {
var maxWidth = 200;
if($(this).width() > maxWidth)
{
var factor = $(this).width() / maxWidth;
var width = $(this).width();
var height = $(this).height();
$(this).css('width', width / factor);
$(this).css('height', height / factor);
}
});
}).each(function() {
if(this.complete) $(this).trigger("load");
});
Karmin is correct here. I ran into this problem a few years ago and ended up just not relying on img.load. His workaround for manually triggering the load event should work.
However...
Developers should do max-width or height in CSS in this scenario. In fact, it is good programming practice to do what one can in CSS before doing them in javascript.
Additionally, if one were to keep going with this solution, var width and var height should be placed outside of the if statement next to var maxWidth, and used wherever $(this).width() is called (including the initial check on line 4). Right now the code is unnecessarily creating a new jQuery object to get the height each time when it should have stored and used the value from the first check.
Thanks for the contributions guys. A previous answer given on stack - that I apparently couldn't find this afternoon jQuery && Google Chrome - solved my problem!
$(window).load(function() {
$(".post-message img.post-image").one("load", function(){
$(this).each(function() {
var maxWidth = 200;
if($(this).width() > maxWidth)
{
var factor = $(this).width() / maxWidth;
var width = $(this).width();
var height = $(this).height();
$(this).css('width', width / factor);
$(this).css('height', height / factor);
}
console.log($(this).width())
});
}).each(function() {
if(this.complete) $(this).trigger("load");
});
});
The code has to be executed on $(window).load() together with the provided code by karim79.
Related
I am trying to convert this small script to a pure vanilla JS.
The plain JS values are not calculated correctly.
What do I need to get to calculate the same value as in the jQuery version?
Pleaset scroll down in the jQuery fiddle to see what l mean.
$(document).scroll(function() {
var progressBar = $('progress'),
docHeight = $(this).height(),
winHeight = $(window).height(),
max = docHeight - winHeight,
value = $(window).scrollTop();
progressBar.attr('max', max);
progressBar.attr('value', value);
});
DEMO jQuery
And below, my pure JS which doesn't work :
var progressBar = function() {
var myBar = document.querySelector('progress'),
docHeight = document.clientHeight,
winHeight = window.clientHeight,
max = docHeight - winHeight,
value = window.scrollY;
myBar.setAttribute('data-max', myBar.getAttribute('max'));
myBar.setAttribute('max', max);
myBar.setAttribute('data-value', myBar.getAttribute('value'));
myBar.setAttribute('value', value);
};
document.addEventListener('scroll', progressBar);
window.addEventListener('resize', progressBar);
My attempt in vanilla
Thank you!!
You'll need to use different properties to access the document and window heights.
document.clientHeight should be document.body.clientHeight. The clientHeight property is designed to return the calculated heights of HTML elements. Using the body element fits within that design.
window.clientHeight should be window.innerHeight. Since window isn't an HTML element, it has its own height properties.
I also simplified the progress bar attribute-setting logic. Unless you have some external requirement to set the data-max and data-value attributes, you can remove those lines. If you do need to set those attributes, you can use the dataset property.
var progressBar = function() {
var myBar = document.querySelector('progress'),
docHeight = document.body.clientHeight,
winHeight = window.innerHeight,
max = docHeight - winHeight,
value = window.scrollY;
myBar.setAttribute('max', max);
myBar.setAttribute('value', value);
};
document.addEventListener('scroll', progressBar);
window.addEventListener('resize', progressBar);
See JSFiddle.
The clientHeight property doesn't exist on window or document. If you have a look at the JQuery docs:
$(window).height() returns height of browser viewport
$(document).height() returns the height of HTML document
There already a great answer on StackOverflow explaining the different ways to get the height. Looking at the JQuery source, the height of the window uses window.innerHeight. For the document it's using the max of:
document.body.scrollHeight
document.body.offsetHeight
document.documentElement.clientHeight
Putting it all together, it works AOK: https://jsfiddle.net/pd3dtvxn/7/
I am working on a project, here: https://github.com/erinreiss/spaceship1/tree/ministory1
And I am looking to make a div#landing to go from opacity:1 to opacity:0 within 200 pixels of scrolling, based on scroll position. I was able to do it successfully like this:
var target = $('#landing');
var targetHeight = 200;
$(document).scroll(function(e){
var scrollPercent = (targetHeight - window.scrollY) / targetHeight;
if(scrollPercent >= 0){
target.css('opacity', scrollPercent);
}
});
Now, I want to use waypoints to trigger this same effect but at a different time. I want instead of it firing as the div#landing moves out of the viewport, it instead fires as a defined Waypoint (in this case, a different div#intro1) is scrolled past.
This is my attempt:
var target = $('#landing');
var targetHeight = 200;
var intro1 = $('#intro1').waypoint(function (direction) {
console.log('bam!');
$(document).scroll(function(e){
var scrollPercent = (targetHeight - window.scrollY) / targetHeight;
if(scrollPercent >= 0){
target.css('opacity', scrollPercent);
}
})
}, {offset: 200});
The waypoint fires, but (alas) the scrolling opacity changer does not work...
Any advice? Thank you!!
ps - The other thread with this question is answered with code no longer available :(
How do I animate on scroll inside a waypoint function?
I didn't solve this problem, but I did hack something together close to what I wanted... It allows me to use the scroll position of an overflow element to trigger and define the level of opacity on another element.
See solution here:
https://github.com/erinreiss/spaceship1/tree/ministory1
var target = $('#intro1inner');
$('#intro1inner').scroll(function(){
//define a variable that will be how much the target has scrolled from its original position
var changeA = target.scrollTop()
console.log('changeA:' + changeA)
// I want my change in opacity (from 0-1 to take place over 250px)
var scrollPercent = changeA / 250;
console.log('scrollPercent:' + scrollPercent)
});
I wrote a jQuery Script which checks the window size and increases the outer wrapper to fit perfectly into the users window.
function reSize($target){
$target.css('width', $(window).width()+'px');
}
$(document).ready(function(){
setTimeout(function() {
$(window).bind('resize', reSize($('#blocker')));
$(window).trigger('resize');
while($(window).height() < $('.newcontainer').height()+30){
$('.newcontainer').css('width', $('.newcontainer').width() - 10 +'px');
}
$('#chatfenster').css('height', $('.newcontainer').height() - 260 +'px');
$('#userlist').css('height', $('.newcontainer').height() - 350 +'px');
}, 100);
});
It works very smooth in Chrome and Safari but in Firefox it's freezing and I don't know why. Sometimes I feel like Firefox is the new IE.
http://design.maxxcoon.com/bestlife/webinar_chat/ (don't open this link in firefox because it crashes the browser)
Can anybody help me please?
Thanks in advance
This part is very unreliable:
while($(window).height() < $('.newcontainer').height()+30){
$('.newcontainer').css('width', $('.newcontainer').width() - 10 +'px');
}
You are checking the height of the window against the height of the first element found with a class of newcontainer. As long as the height of the window is smaller than that height plus 30 pixels, you set the width of all elements with class="newcontainer" to 10 less than the width of the first one of them.
If your condition is for one dimension (height) and the changes you make is to another dimension (width), the loop will run either never, or probably forever, or possibly randomly...
If there is a maximum height or a maximum width for your .newcontainer elements, you should instead calculate the allowed values for height or width and set them once, not in a loop! Something like this, maybe:
var windowHeight = $(window).height();
var maximumContainerHeight = windowHeight - 30;
$('.newcontainer').css('height', maximumContainerHeight + 'px');
However, I do not know if you want to set width or height, so I'm guessing.
If what you are doing is really setting the width of something, hoping that the layout engine will affect the height as a side-effect, you are going at this the very wrong way.
Another, better, solution is to use modern CSS solutions, like flexbox, to let the browser automatically handle all layout issues.
Figured it out without a loop.
May be helpful for others.
<script type="text/javascript">
function reSize($target){
$target.css('width', $(window).width()+'px');
}
$(document).ready(function(){
setTimeout(function() {
$(window).bind('resize', reSize($('#blocker')));
$(window).trigger('resize');
var windowSize = $(window).height();
var containerHeight = $('.newcontainer').height();
var containerWidth = $('.newcontainer').width();
if(containerHeight > windowSize){
var pixelToMuch = containerHeight - windowSize;
var divFactor = pixelToMuch * 1.67;
var newWidth = containerWidth - divFactor;
$('.newcontainer').css('width',newWidth+'px');
}
$('#chatfenster').css('height', $('.newcontainer').height() - 260 +'px');
$('#userlist').css('height', $('.newcontainer').height() - 350 +'px');
}, 100);
});
</script>
Hey I have this really annoying issue thats probably got a simple solution but for the life of me i cant find away to fix it.
Basically i have two images both 50% with of it's container now the goal is the both images to slide in (left/right) on the basis of the scroll position and once it get to the top of the container both images will sit is place.
Now i got that working to that point the only issue is when i resize the page the position of both images are wrong. I obviously did a resize() function with the same logic as the scroll() function but still i got nowhere. Here's my code
var page_width = $(document).outerWidth(),
page_height = $(document).outerHeight(),
left_image = $('.split-screen.youth'),
right_image = $('.split-screen.elite'),
offset = (page_width) / page_height;
left_image.css({'left':'0px'});
right_image.css({'right':'0px'});
$(window).on('scroll', null, function(){
var scrollTop = $(window).scrollTop(),
calc = -(scrollTop*offset);
left_image.css({
'margin-left': 'calc(100% + '+calc+'px)'
});
right_image.css({
'margin-right': 'calc(100% + '+calc+'px)'
});
});
$(window).resize(function(){
// something ???
});
Here is a jsFiddle of the issue although it doesn't look entirely accurate but you get the picture. When you resize the scroll position changes and i need the margin-left/margin-right values to be correct.
I think your problem is that you're still using the old offset value. Just update your global values first, than it works for me (see: https://jsfiddle.net/a7tfmp37/2/):
$(window).resize(function(){
page_width = $(document).outerWidth(),
page_height = $(document).outerHeight(),
offset = (page_width) / page_height;
var scrollTop = $(window).scrollTop(),
calc = -(scrollTop*offset);
left_image.css({
'margin-left': 'calc(100% + '+calc+'px)'
});
right_image.css({
'margin-right': 'calc(100% + '+calc+'px)'
});
});
I am trying to have a container div resize based on the dimensions of the window. The height to width ratio is the most important aspect here and I want to maximize the size of the container in whichever direction (height or width) that is most constraining given the ratio. I have tried a few things unsuccessfully with this being the most recent:
$(window).load(function() {
var h = $(window).height();
var w = $(window).width();
If((h/w)>0.61){
$('#container').css({'height': h, 'width':h*1.64}); }
else{ $('#container').css({'height': w/1.64, 'width':w}); }
})
What do I need to change to get the window to resize? Is there a better way to approach this?
Thanks in advance for any assistance. I am not at all familiar with javascript/JQuery and have been unable to find any useful info... this thing is driving me nuts...
You want to capture the resize event, so assuming your current code works to your likings
$(document).ready(function() {
$(window).resize(function() {
var h = $(window).height();
var w = $(window).width();
if((h/w)>0.61) {
$('#container').css({'height': h, 'width':h*1.64});
}
else {
$('#container').css({'height': w/1.64, 'width':w});
}
});
});
And let's avoid the capital I on the if
I typically use this:
function resize () {
var w = $(window);
var containerWrap = $('#container-wrap');
containerWrap.css({ width:w.width(), height:w.height()});
}
I'm not sure if that answers your ratio question.
EDIT:
This may be more helpful:
$(document).ready(function () {
var missionWrap = $('#mission-wrap');
var w = $(window);
w.on('load resize',function() {
missionWrap.css({ width:w.width(), height:w.height()});
});
});