I have a ruby on rails web app, and in some views i have many heavy images( <img> ) to render .The <img> are generated in a Helper.
The problem is that the css is loaded first, then the js, then the heavy images , and then finally the css refereneced background images.
It takes quite a while for all of the heavy images to load, which therefore holds the whole site up.
I want to load first the css background images then load the other images, as they obviously hold visual structure of the page.
rails version: 2.3.8
EDIT:
Thank you guys, I apologize for not having shared the code earlier.
I have two models : Categories and Images, each Category has many images.
In the view i have a list of categories, which is generated by a helper :
categories.each do |cat|
html << "<a href='##{cat.id}' class='mapcat' >#{cat.libelle}</a>"
end
and when I click on the category the images are displayed
categories_images.each do |i|
html << "<div id='#{i.id}' class='#{css}'><img src='/images_moi/categories/#{cat.libelle}/#{i.path_file_name}' />"
end
I have css background image associated to the list of category
The problem is that the images (<img>) is displayed before the css background images of the list of categories.
We need to assume things because you haven't shared your code.
Coming to your query, for now you can preload images using jQuery:
function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
$('<img/>')[0].src = this;
// Alternatively you could use:
// (new Image()).src = this;
});
}
// Usage:
preload([
'img/imageName.jpg',
'img/anotherOne.jpg',
'img/blahblahblah.jpg'
]);
This saves the loading time of loading images.
Use a base64 string.
Example:
background-image: url(data:image/png;base64,*CONVERTED IMAGE DATA HERE*);
without: **
online converter: http://webcodertools.com/imagetobase64converter
note: I only would suggest this if the image size is not too heavy.
Solution: Do not use the img tag.
Create a sprite containing all your images. Load the sprite in your application.html layout once.
Use data uris to transmit the data directly in the html. See http://css-tricks.com/data-uris/
My approach is to lazy load the images using jquery and data- tags. This approach also allows me to choose different images based on device width and spare tablet/mobile users.
<img src="" data-src="/img/graphic-desktop.jpg" data-smallsrc="/img/graphic-smaller.jpg" alt="Graphics" class="lazy" />
<!-- the following would be in your js file -->
$lazy = $('img.lazy');
$(window).load(function(){
// window load will wait for all page elements to load, including css backgrounds
$lazy.each(function(){
// run thru each img.lazy on the page. spare the jquery calls by making $this a variable
$this = $(this);
// if the window is greater then 800px wide, use data-src, otherwise, use the smaller graphic
($(window).width() >= 800) ? $this.attr('src', $this.attr('data-src')) : $this.attr('src', $this.attr('data-smallsrc'));
});
});
Related
Currently I have thumbnails, when I click the them a large version of the pic appears in the div directly to the right of the thumbnails. What I now want to be able to do is click the larger pic in the div and then trigger a lightbox that shows an even larger version of the pic.
I'm not quite sure how to do what I'm thinking is the solution so I'm gonna try and explain. I'm thinking that when i click the div to trigger the lightbox I want to take the src of the pic being click and then somehow redirect it to another src in my images folder.
Example:
When I click image in div I get the src of pic lets say that the source is:
src="redpic.jpg"
Then lets say in my images folder I have a larger version of the pic selected with the source:
src="redpic_large.jpg"
Would it be possible to manipulate the the src of an first image img src="redpic.jpg" by adding _large to the end and then appending this to my
lightbox???
Everytime I try to do things with my images I always seem to be running into problems.
say the src="redpic.jpg" when I check in the console the src goes to something like //139.0.0.1:56328/img/dotted.jpg and it seems to cause me a lot of problems
Sure, you can get the source of the image like this :
$("img").on("click", function(){
var source = $(this).attr("src");
});
This will give you the complete path (redpic.jpg).
You can use split() to get an array of both parts (the name and the extension)
var parts = source.split(".");
Now, all that you have to do is append the "_large" to the first part of the source, combine them back together and set your other image's source as the newly assembled one.
parts[0] += "_large";
var newSource = parts.join(".");
You pass the period . to the join function so that it puts a period in betwen your elements, instead of the default comma , .
All that's left to do is to use newSource as the source attribute of your other image.
$(".other-image").attr("src", newSource);
Need advice on what's the best solution to this.
I'm doing a RWD Photo Gallery page. Basically, i'm using pretty photo if accessed through a desktop and photoswipe when accessed in mobile devices.
What i did is this:
<img src="sample_image" />
<img src="sample_image" />
I hide (display:none) one of them depending of the screen size using media queries.
Is this a right approach, i read that using display:none will not reduce the load time. I have hundreds of photos in my gallery and i'm worried this might greatly affect the load time. Is there any good solution to this?
Why do you need two tags for this?
<img src="sample_image" />
<img src="sample_image" />
You can achieve the same with a single tag.
<img src="sample_image" />
Now with media query you can have the same desktop_and_mobile class on both media query and define the css property accordingly in each.
This has the advantage that you will be loading only one image, instead of two.
I think that what you want is to have the anchor tag to call the correct lightbox when clicked, because styling the sample_img with responsive css will work as expected, no need for fancy stuff, but if i'm correct then you have 3 choices in my opinion, you can do it like you said and hide the .desktop links using media queries, since the images are exactly the same the user wont have to load again that image, and being set to display:none the user browser won't render that element, so the only downside is that you will have a cluttered html and it will feel muddy, but no other concern in my opinion.
Another option is to use a js code like this one, but since usually lightbox codes will have a method to add event handlers to every link they find with (with the proper formating, lets say its rel), you will have to manually trigger that event after you changed the links rel attr, or execute adaptLinks() before that happens, in that case, on windows resize it won't work, unless you do what i said before. For that you can check how to do it on the lightbox page, they propably have that method listed.
Here is the code
var adaptLinks = (function(){
var $winHeight = $(window).height();
var $lightBoxLinks = $('a.lightBox');
return function() {
var isPrettyPhoto = false;
if($winHeight < 1000){
$lightBoxLinks
.removeClass('desktop')
.addClass('mobile')
.attr('rel','external');
} else {
$lightBoxLinks
.removeClass('mobile')
.addClass('desktop')
.attr('rel','prettyPhoto');
isPrettyPhoto = true;
}
// Call the link processing method of the lightbox
if(isPrettyPhoto) {
$lightBoxLinks.prettyPhoto();
} else {
// photoSwipe method
}
}
})();
$(window).resize(adaptLinks());
And the thir option, is use a lightbox that works both for desktop and mobiles, i think that is the right way to do it.
Good luck.
I am doing a website, in the header of that website I want a "slideshow" that shows RANDOM images - this I already have with javascript.
I want to have the images to FADE in/out in instead of just changing them.
Other than that, I really want to know if there is any way I can make the script load pictures from a directory itself instead of I have to manually update the script each time I upload a picture.
Can this even be done with javascript, php, css or jquery?
Any alternatives? div change background random with fade? anything?
Here is the code I am using now.. its changing pictures with no problem.
<script language="javascript">
var delay=1000 //set delay in miliseconds
var curindex=0
var randomimages=new Array()
randomimages[0]="1.jpg"
randomimages[1]="5.jpg"
randomimages[2]="2.jpg"
randomimages[3]="4.jpg"
randomimages[4]="3.jpg"
randomimages[5]="6.jpg"
var preload=new Array()
for (n=0;n<randomimages.length;n++)
{
preload[n]=new Image()
preload[n].src=randomimages[n]
}
document.write('<img name="defaultimage" src="'+randomimages[Math.floor(Math.random()*(randomimages.length))]+'">')
function rotateimage()
{
if (curindex==(tempindex=Math.floor(Math.random()*(randomimages.length)))){
curindex=curindex==0? 1 : curindex-1
}
else
curindex=tempindex
document.images.defaultimage.src=randomimages[curindex]
}
setInterval("rotateimage()",delay)
</script>
Yes all of this can be done with javascript (almost), javascript itself can't scan folder contents for that you need some kind of server language, most likely you would use PHP to scan folder contents and return them to the client.
So basically you would need one of jquery ajax function, i would highly recommend post
So now with ajax you can get all of your needed data about the folder.
Now about fade effect, you would need to use something like this or this
As for randomness i'm pretty sure you can figure that out, just get a full list of images put them into array and use javascript random function to take random image from that array.
I want the browser (mobile webkit especially) to NOT download images that are inside display:none divs. Right now, they get downloaded and not rendered.
Is there a jquery plugin to do this?
you can use data-* attributes. that way, you can have jQuery load them on demand:
<img data-source="image_path">
//this one gets all images and loads them
$('img').each(function(){
//loads the source from data-source
this.src = this.getAttribute('data-source');
});
<img data-source="image_path" class="foo">
<img data-source="image_path" class="foo">
//this one gets all images that have class foo and loads them
$('img.foo').each(function(){
//loads the source from data-source
this.src = this.getAttribute('data-source');
});
ofcourse you need to wrap this in a function so that you can call which images on demand. like:
function loadImg(selector){
$(selector).each(function(){
this.src = this.getAttribute('data-source');
});
}
//load images with class foo:
loadImg('.foo');
I don't think so. To be sure, you would need your original HTML DOM to exclude the hidden images, which you could do with server-side programming based on user agent sniffing (although that is not recommended). Modifying the DOM after document.ready or document.load will mean that the browser has already had a chance to request assets from the server even if they might not be displayed.
It would be unusual but if you still want to use jQuery you could follow #Pointy's advice and make all images placeholders in your markup. Then replace the :visible placeholders with the images you want using an attribute as the data source. No plugin is needed, just use something like replaceWith() or attr() to swap out the placeholder node for the image you want downloaded or change the src attribute.
I would use a 1x1 transparent gif as the placeholder with the correct height and width attributes rather than no source <img> for a placeholder. That way the page flow will be determined correctly when the page renders so it won't jump around as your images lazily load.
My markup is a simple div element with id 'load'. Using jQuery I then load a list of image elements into this div:
$('#load').load('images.html', { }, function() {
$(this).onImagesLoad({
selectorCallback: function() {
....do something....
}
});
});
where images.html is a list like this:
<img src='1.jpg' caption='img 1'>
<img src='2.jpg' caption='img 2'>
...
To ensure that all images are loaded completely, I use the onImagesLoad plugin. This, so far, works just fine on all browsers.
However, on IE8 (and I assume other versions of IE also) when I then iterate over the img elements, I am unable to determine the width/height of the images loaded. The image.context.naturalWidth and naturalHeight attributes don't seem to work.
How do I get a hold of the images' dimension?
Thanks heaps :)
Update
#Simon: That didn't work on IE, and broke the other browsers as well.
#Jenechka: If "imageDomElement" is just another name for the "image" variable in my example above, then it doesn't work. Or what do you mean by that DomElement?
If you haven't resized the image, you could use:
image.width()
and
image.height()
It's been a while but I finally found some time to tinker with this again. The above problems are still there, but here is what I think is going on.
When I load the initial images then yes, the file is loaded and image objects are generated. But it seems that the attributes are not correct yet, and they won't be until the image is actually added to the DOM of the site and rendered. A div/image on hide() on IE has no dimension information whatsoever, on Safari there is some information available. For example, without adding the following div anywhere
var test = $("<div><img src='test.jpg'></div>")
the image contained there has the following information:
width() = 0,
attr("width") = 600,
css("width") = "", and
img[0].clientWidth = 0.
That's on Safari; on IE it's the same except attr("width") = 0 and css("width") = "auto". Now I can't use this, and that's what broke my script and why I posted my initial question. However, the moment I append this div and have it rendered, all the correct values show up in the image object.
I'm writing a little gallery thinghie, which shows whatever images I have in that second .html file that I load; that gallery, however, computes and places the thumbnails, and prepares the images it shows in full resolution. To make this look ok, I basically wanted to create the entire thing hidden, and then fade it in. Alas, it seems that this whole idea won't pan out. A friend suggested to load everything into a tiny iframe off to the left where it's not visible, and work with that. Perhaps that's the way to go.
Another thing I noticed, and that seems to be very closely related to the aforementioned load issue is clone(). It seems that if an image is rendered, a
var newimg = img.clone()
generates the same "empty" image object that I have to deal above. Even when the original image is visible and contains all the right attributes, its clone does not.
Right now I don't see any other way than to rethink and rewrite parts of my gallery.
This is quite similar to the other answers, but I have tested it in IE7, so it might be closer to what you want:
$(document).onImagesLoad({
selectorCallback: function() {
$('img').each(function(){
alert($(this).width()+', '+$(this).height());
});
}
});
See here, this may not be exactly how you were using it, but I'm not familiar with this onImagesLoad thing.
imageDomElement.width
imageDomElement.height
or try
imageDomElement.clientWidth
imageDomElement.clientHeight
If you play with jquery, then image.attr(width) should do the trick
But why not using the document.ready instead, could give you less headeache. .
Use the following code instead
$(document).onImagesLoad({
selectorCallback: function() {
$('img').each(function(){
alert($(this)[0].clientWidth +', '+$(this)[0].clientHeight);
});
}
});
What about?
$("#load img").each(function() {
var img = new Image();
img.src = this.src;
alert(img.height + " x " + img.width);
});