I know this sounds a bit weird but I have function that changes the height and width of images
and I execute it on document ready. But every time I refresh the page I get different results for the same images (it gets them right every 4th or 5th time). Here is my code:
$("img").each(function(){
$(this).width(
parseInt($(this).width()) / (parseInt($(this).width())/parseInt($(".container").css("height")))
);
$(this).height(parseInt($(".container").css("height")));
});
The images are in a container and I want them to have the same height as the container and the width changed equally as the height. The height of the container is changed dynamically and every time I change the size of the container I also change the size of the image (I don't have the problem here). I don't quite understand how can this work differently every time I load my page.
You should wait for all images to load using $(window).load() function, or use some other way to controll your images loading. Choose your way but the problem is simply that your function gets fired before images are loaded.
You don't need to wait for images to load.
But you do at least need to wait for them to start loading.
What's the difference? Well, in all image formats that I'm aware of, one of the first pieces of metadata is the image's dimensions. This is why with bigger images you can see the browser reserve the space as soon as the image has started loading, and then fills it in with the image as it loads.
So! With this in mind, let's get your page looking as sharp as possible, shall we?
Forget all that, I've just realised, you're setting the height to the height of the container? In that case...
$("img").each(function(){
this.style.width = "auto";
this.style.height = "100%";
});
There you go. Using auto for the width will keep the aspect ratio.
Related
I am currently building a portfolio website for myself. I have an array of projects that are flex and change size as the window changes size, once they get to a min-width they wrap over to the next line. My problem is that when the website is loaded for the first time without a cache, the images haven't loaded yet and the height of their container doesn't fit them. This causes a lot of overlap, but when the page is refreshed and there is a cache it fixes itself. An example is shown here:
The cache problem.
My idea to fix this was to make a min-height, but since its responsive and the size of the container changes, I don't know how to set the min-height. I was thinking of setting it to a mathematical relation to the width of the view port window, but wasn't sure if I had the skills to make that work. I will happily attach the code if needed.
If you want to preserve space for an existing image you can wrap it into a div and adjust this div's dimensions any way you like. For example, you can set min-height. Or if the image height varies you can use loading indicators (gif loading animations) with their own dimensions, and when your images finally load, you can replace the gifs with the actual images using js onload event
To make space for images before they load you need to give each image a corresponding value(*) of its height and width.
( * - in good coding practices, this is actually a requirement ! )
For example ::
<img src=[url] width=180px height=300px>
If you want a fast, stable, responsive, robust and absolutely solid page - Never leave images, tables and table-cell columns without a 1. width and 2.height specs.
Even if they are flexy, you are highly encouraged to at least use relative size (%).
<img src=[url] width=60% height=100%> /*relative::Let's say this set of images is in a
div who's css height is 300px. The images width given as 60% matches exactly its pixel
width, which is 180px.*/
You will immediately notice a tremendous improvement of your page performance and have away better experience working with them. Depending on the complexity of elements a ten fold improvement of the render speed may be achieved.
I'm trying to 'lazy load' dynamic images. Their height/width ratio matters in the layout of the webpage. I have four options to prevent them from messing up the DOM when they load or render.
I can get the height and width of the image using Javascript, set an element in the DOM to place-hold for the image until I want to load it later. I would use...
var image = new Image();
var width = image.width;
var height = image.height;
I can simply not lazy load them and use an img tag with a src immediately. If #1 is just as slow as this method then there's no point even trying to load them later and I may as well do it in an HTML tag.
<img src='source' />
I can store the image dimensions in my database. This would mean I would continuously have the necessary dimensions of the image and could pretty easily set a placeholder. I don't know if this is common practice though. Edit: it should be noted, I'm accessing the database to retrieve the image url anyways.
<div>this elements width and height is set</div>
I could get the dimensions of the image through PHP. This is the same as the Javascript method, just at a different point in the process.
$size = getimagesize($filename);
My question is essentially which of the above is the most well established way of getting a pictures width and height to store a place for it in the DOM?
I'd say a combination of method 2 and 3 are your best bets. You should store the image size and other metadata in your tables describing the image. You can then either do some form of dynamic loading, or just place a bunch of <img> tags, with width and height already set to the sizes from the DB and decoding=async so the browser doesn't block the rest of the page on loading these images.
The end state is to send a document to the browser, which contains the clear list of images you wish to display, and as much info about them as you can (sizes, loading modes, various srcs for various screen densities etc).
Method 1 seems like a lot of work, most of which would duplicate what the browser would already be doing.
Method 4 would be a performance nightmare. getimagesize would need to access the disk and read some part of each image you're trying to display. If there's a set of well known images, you'd be saved by disk caches, but otherwise, if you're doing something like instagram/facebook/flickr where every user has their own images you'd be looking at O(n) random disk reads atop whatever I/O the database does.
I'm trying to load in some decently large images into a web application. The largest of these images can be 2800x2800. I load them in, display, and everything works fine.
My problem is, once they are loaded using:
var img = new Image();
img.src = 'myImageURL';
img.onload = function(){
//display image
}
The large images display on the page progressively, from top to bottom as if they are being loaded.
I want to remove this visually, and only display them once fully loaded and rendered in the browser.
I cannot change the image sizes either, because this web app is intended for the user to scale the images, all the way up to 100% of original size, so I must load the full 2800x2800 and resize it small.
Does anyone know how I could hide the image until it's rendered? I can hide it until loaded, but that's basically what I'm doing and it's the progressive render display I want to remove.
Thanks
Use the onload attribute on the <img> tag, something like this:
<img src="huge.jpg" style="display:none" onload="this.style.display='block'">
Substitute whatever you want for effects, but onload is your hook.
Demo: http://jsfiddle.net/DfCUQ/1/ (note: update the ?nocache=X in the demo for each time you load it)
You could make the css visibility to 'hidden' and have some text (or loading spinner, etc) in the place of the image until the onload event gets called.
I'm trying to show 1000 quite small images on a page (rather a lot indeed but out of my control).
When loading them all at once, the performance obviously suffers drastically rendering 1000 images at once.
I tried implementing applying the image src upon scroll (at numerous amounts - 250px scroll, 25 images load etc.), then tried loading the images on a timer.
These methods did help to increase performance but what would be the most efficient way to do this? They seemed to still have an irritating amount of lag - I understand there is a fundamental problem with rendering that many images on one page, but is there a better solution?
EDIT:
Pagination of course would help but isn't an option here. Also, the images are pulled from an API so it's not convenient to make 1 large image / use sprites.
If all the images are unique files then you are feeling the big hit from making multiple connections to retrieve them. You could create 1 "master" image of all the items and then create 1000 divs each with a different class or id then in css define background offsets for each. This method is often refered to as css sprites.
http://css-tricks.com/158-css-sprites/
Couldn't you make an AJAX pagination, that dynamicly loads the images based on page number? For example, 25 images per page. On requesting the first page, you dynamicly load the next page and so on. That way, the user won't notice the delay.. That's all you can do to improve the performance even further!
Here's an answer from another angle:
Could you combine the images on the server-side and render them in lines perhaps?
Though this will probably only work in certain circumstances.
Well, I think the best solution would be to render them as the user sees them. i.e. Your scrolling approach. This would mean only loading as many images as the user has seen and not all of them at once. If, as you say, it is out of your control; then using pages is out of the question? That would be a better approach on the whole.
That many images is bound to cause a lot of lag anyway, as it will use a high amount of bandwidth and likely memory as well.
Since sprites/pagination weren't an option in this situation, I found the following the best solution:
Adapting the 'load images on scroll' method, with some tweaks and cruically setting the parent element for each image (so there are 1000 elements, each with images) to display:none.
With the parent elements defaulted to display:none & also making the first 25 display:block:
var scrollPos = 0;
var endEle = 0;
$(window).scroll(function(){
scrollPos = $(window).scrollTop();
if ($(window).scrollTop() < scrollPos + 250) {
//load 15 images.
$('.myDiv img').slice(endEle,endEle+50).each(function(obj){
var self = $(this);
var url = self.attr("role");
self.attr("src", url);
self.parent().css("display","block");
});
endEle = endEle + 50;
}
});
This sets the next 50 elements to display:block and switches the <img role> into <src> (the image urls were put into role when the page is rendered) every time the user scrolls 250px.
The design I've been given to work with is 960px wide by around 7000px tall, cut into five vertically-stacked segments at arbitrary points. There's a fixed-placed sidebar that scrolls to each segment, depending on which navigation link is clicked. Atop this are a bunch of sliders, transparent PNGs, headlines and paragraphs, predominantly positioned in a relative fashion.
I need to ultimately do two things:
Hide the corresponding quick-nav links in the sidebar until its related segment's background image has loaded
Load (and ideally fade in) the transparent PNGs in each section as needed -- the user scrolls between two vertical scroll values and stops for a second, causing that section's transparent PNGs to then load and fade in.
I'm currently using softscroll.js to achieve a smooth scrolling effect for when the sidebar links are clicked (thus scrolling to the related anchors). Thus, lazy loading techniques that begin to load images as you scroll by won't work -- if I click the last link in the sidebar nav and it scrolls me to the bottom, I don't want every image between the bottom segment and the top loading as a result.
While I'll need to figure out point 1 sooner rather than later, I'm more interested in the second question.
How would one use jQuery to load images inside a certain element if and only if the user has paused between two specific vertical scroll values?
Thank you!
(BTW, please don't respond with appelsiini's lazyload jQuery plugin. It's unsupported by the developer and doesn't appear to work in modern browsers. Thanks!)
A slightly more full fat solution to the already great one suggested by Justin is to use jQuery Waypoints to manage the in viewport events.
You may run into issues if you're rewritting the scroll mechanism on mobile browsers using something like iScroll or scrollability. In which case you'll need to use their APIs to investigate a fix.
Check the user's position using scrollTop(). You should be able to do this inside a setInterval() callback.
function loadBackground() {
var userTop = $(window).scrollTop();
var userBtm = userTop + $(window).height();
var elemTop = $('#element').scrollTop();
var elemBtm = elemTop + $('#element').height();
if ((userBtm >= elemTop) && (userTop <= elemBtm))
{
// Load images
}
}
$('document').ready(function(){
setInterval(loadBackground,500);
}
(This is untested code, but you get the idea.)
Edit: Adjusted the conditional so that if any part of the element is in the window it will fire.
Hide the corresponding quick-nav links in the sidebar until its related segment's background image has loaded
Haven't tested it but you should be able to just do this by sticking a couple of <img>s in with the same src as the background (with display: none; of course) and testing the .complete property of each image, on a short setInterval loop, until they're all loaded. Don't use onload, it tends to be unreliable on images.
Load (and ideally fade in) the transparent PNGs in each section as needed -- the user scrolls between two vertical scroll values and stops for a second, causing that section's transparent PNGs to then load and fade in.
Justin's solution should work for detecting when you're in a given section. Just set a flag to false before you do the softscroll, and true once it stops- and then only mark a section as active when the flag is true.
I would "disable" the images by pointing their src attribute to a 1x1 blank gif, and setting their data-src attribute to the real src. Then just do something like:
$('.selected-section img').each(function () {
$(this).attr('src', $(this).data('src'));
});
You'll have to be sure to set the size of the "disabled" images to the size that they'll be once their image has loaded, or else the page will jump around a lot.
You could use the window.onscroll event handler to detect when you're scrolling, but this is generally a bad idea. For discussion on this see: http://ejohn.org/blog/learning-from-twitter/