I found this script on this site which helps to fadeIn/Out transparent .png's in IE without the transparent part being filled in with black during the fade effect:
var i;
for (i in document.images) {
if (document.images[i].src) {
var imgSrc = document.images[i].src;
if (imgSrc.substr(imgSrc.length-4) === '.png' || imgSrc.substr(imgSrc.length-4) === '.PNG') {
document.images[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true',sizingMethod='crop',src='" + imgSrc + "')";
}
}
}
This script was created by this stackoverflow user and it works perfectly well on my site. However, I want to modify it a little bit. This script finds ALL .png files on my page and applies the filter. However, this may be causing performance issues because I have many transparent .png files on my site, yet I only need to apply this filter to one of them. It's a fixed position menu DIV background image that fades in and fades out using jQuery while the page is scrolling.
Can someone help me to modify this script so that I can just provide it with one image or use getElementById("menu") and have it apply this filter. Nothing I have tried seems to work and putting the filter in my CSS didn't work either, so the javascript way seems to be the way to go. I just need to use it on one .png, not all of them.
Remember this is the background image of the div #menu, so the image itself has no ID, though of course the div does. Any help would be greatly appreciated.
According to the spec, document.images returns a collection of the img elements, so if it's background-image, that wouldn't work. However, if it's an img that being used in the background it will work. If you're just going to apply it to one image whose ID you know, then it'd be
function applyFilterToImageById(id) {
var i,
parentElement = document.getElementById(id);
for (i in parentElement.images) {
if (document.images[i].src) {
var imgSrc = document.images[i].src;
if (imgSrc.substr(imgSrc.length-4) === '.png' || imgSrc.substr(imgSrc.length-4) === '.PNG') {
document.images[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true',sizingMethod='crop',src='" + imgSrc + "')";
}
}
}
Related
UPDATE:
I just found some more info. It seems that in Chrome, the currentSrc of the image will often be empty, whereas in Firefox, the URL is always correct. Is the JS trying to access currentSrc before it's available? Is there a way to prevent this?
I am creating a Drupal 8 website, and in order to use the responsive images module with a background-image, I came up with the following workaround. The JS function below, setParallaxImage(), takes the currentSrc from the img in the picture element and sets it as the background-image for the outermost div. The img itself is not displayed (display: none in CSS) and is given a dummy image, as I only need it to get the currentSrc. The function is called with onload and onresize.
The code seems to work well in Firefox. When resizing the browser past a breakpoint, the image goes grey for a split second, then loads the image from the proper source. However, with Chrome, when quickly resizing past a breakpoint, the image may become grey and not get displayed at all, that is, background-image: url(). Usually if I resize the window a couple more times, the image will finally appear. Does anyone know why this might be happening? Thank you for reading.
JS
function setParallaxImage() {
const parallaxContainer = document.getElementsByClassName('paragraph--type--parallax-banner-with-text');
for(var i = 0; i < parallaxContainer.length; i++) {
console.log('in setparallax');
var x = parallaxContainer[i];
var parallax = x.getElementsByClassName('field--name-field-parallax-image-top-')[0];
var picture = parallax.getElementsByTagName("picture")[0];
var sourceURL = picture.querySelector('img').currentSrc;
x.setAttribute('style', 'background-image: url(' + sourceURL +')');
var img = picture.getElementsByTagName("img")[0].setAttribute('src', '/sites/default/files/src_images/dummy_image.gif');
}
}
window.onload = setParallaxImage
window.onresize = setParallaxImage;
HTML
<div class='paragraph--type--parallax-banner-with-text'>
<div class='field--name-field-parallax-image-top-'>
<picture>
<!-- several source tags here -->
<img src="will-be-given-dummy-image-in-JS">
</picture>
</div>
</div>
You can use the property "complete" to check, if the image was already loaded. If not, u can use the onload-Event to fire, when the image is available.
if (img.complete) {
console.log(img.currentSrc);
} else {
img.onload = function() {
console.log(img.currentSrc);
}
}
How can you cancel the loading of an image defined by a background-image attribute?
There a few questions that show how to cancel the loading of an <img> tag by setting the src to '' or to a different image (such as this one, answered by Luca Fagioli). But this does not work for background images.
Luca provided a jsfiddle ( jsfiddle.net/nw34gLgt/ ) to demonstrate the <img src="" /> approach to canceling an image load.
But modifying that jsfiddle to use background-image instead clearly shows that the image continues loading, even if:
you do background-image: none (as suggested here)
or background-image: url("web.site/other_image.jpg")
or background-image: url('').
In fact, in my testing on Firefox 54, the background image continues loading even if you do window.stop() or close the tab.
So, is there any way at all to stop loading a background image once it starts?
My use-case for this is client-side, so I can't change the site to not use background images. I am viewing a gallery of many thumbnail images, but the thumbnails are much larger than they need to be. Smaller versions are available so I wanted to replace the large thumbnails with the smaller versions via Greasemonkey to ease the network load on my poor, slow connection. Each entry in the gallery is a <div> with a background-image inside an <a> linking to the full-size image. (using Fotorama).
If you need to target inline styles on the elements, then I think you can run a script near the bottom of the page to do that.
Testing this locally, the original images do not show as loading in the network tab.
var allDivs = document.getElementsByTagName('DIV');
for (var i = 0; i < allDivs.length; i++) {
// check for inline style
var inlineStyle = allDivs[i].getAttribute('style');
// check if background-image is applied inline
if (inlineStyle && inlineStyle.indexOf('background-image') != 1 ) {
allDivs[i].style.backgroundImage = 'url("newImg.jpg")'; // assign new value?
}
}
That is going to grab every div, so hopefully these elements have a class you can use to query first. Then you have a smaller collection to run the above on.
Classes, not inline styles:
If you could target classes, it would look a bit cleaner. You could create a new class and use it.
var els = document.querySelectorAll('.bg-img');
for (var i = 0; i < els.length; i++) {
els[i].classList.remove('bg-img');
els[i].classList.add('no-bg-img');
}
Not happy with existing lazy loading plugins (they are so complex that I can't even understand the codes in them), I thought I can create a simple, easy to understand script that lazy loads images.
My idea was simple. Start out with a following (deformed) img tag.
<img lazy="http://lorempixel.com/400/200"/>
Using javascript, swap out the word "lazy" with "src" when the page is being scrolled up or down.
function hackyaFunction_lazy() {
[].forEach.call(document.querySelectorAll('img[lazy]'), function(img) {
img.setAttribute('src', img.getAttribute('lazy'));
img.onload = function() {
var imgs = document.querySelectorAll('[lazy]');
for (i = 0; i < imgs.length; i++) {
var o = imgs[i],
lazy = o.getAttribute('lazy');
if (o.y <= (window.screen.height + window.scrollY + 50) && o.y >= (window.scrollY - 50)) {
o.setAttribute('src', lazy);
o.removeAttribute('lazy');
}
}
}
window.onload = window.onscroll = hackyaFunction_lazy;
});
}
I know enough of javascript to hack together bits & pieces to make something that works. And the above code kinda works.
On my console, I see that the word "lazy" has been successfully replaced with "src" for images that are in viewport.
However, images that are outside of the viewport, this is what I see.
<img lazy="http://lorempixel.com/400/200/sports/Dummy-Text" src="http://lorempixel.com/400/200/sports/Dummy-Text">
So I have half working code & this is the best that I can do.
I should have just used any one of the plugins that are available out there; just wanted to see if I can create something simple & easy.
Now that I am so close to making this thing work, I am reluctant to give it up.
Any help will be greatly appreciated.
I wanted to put together the whole thing (html & js) on jsfiddle but images fail to show on jsfiddle. Don't know why.
The code works (as described) on local environment.
The first line within the .forEach() changes the src of the current image without removing lazy and without testing whether it is in view or not, so after the .forEach() has run that line for every image they will all have been updated. That's why when you inspect the elements with the dev tools many of the images have both a src and lazy attribute.
If the idea is to only set the src once the image scrolls into view, and for any images that are already in view on page load, you can do it by keeping just the inner for loop of your function:
function hackyaFunction_lazy() {
var imgs = document.querySelectorAll('[lazy]');
for (i = 0; i < imgs.length; i++) {
var o = imgs[i];
if (o.y <= (window.screen.height + window.scrollY + 50) && o.y >= (window.scrollY - 50)) {
o.src = o.getAttribute('lazy');
o.removeAttribute('lazy');
}
}
}
window.onload = window.onscroll = hackyaFunction_lazy;
This works because on each scroll it first selects whatever elements still have the lazy attribute, then for those elements it tests whether they're in view and if so it sets their src and removes the lazy. Elements that have not yet been scrolled into view are not updated.
See it working here: https://jsfiddle.net/vb779g7v/2/
Edit/P. S. Note that your if test checking if the element is in view isn't right, because screen.height gives, as the name suggests, the height of the whole screen, not the height of the client area within the browser. But that's not really central to your question, so I'll leave fixing that as an exercise for the reader...
I have a div that contains text next to a b&w image. The entire div is set to 50% opacity. Upon hover over this div, I want to change the opacity to 100%, while also changing the source of the image (from the b&w one to the color). The functionality is fine; however, when it's hovered over, the opacity changes slightly before the image source changes, and it definitely looks a little funky. I've tried preloading the images, but that doesn't seem to change anything - still a slight delay in changing the img source.
Here is what my code looks like (the images have the almost same source, just the suffix is different, thus the strange looking code):
$('.character').on('mouseenter', function() {
var full_src = $(this).find('img').attr('src');
var half_src = full_src.split("-");
$(this).find('img').attr('src', half_src[0] + '-color.png');
$(this).css('opacity', 1);
});
$('.character').on('mouseleave', function() {
var full_src = $(this).find('img').attr('src');
var half_src = full_src.split("-");
$(this).find('img').attr('src', half_src[0] + '-bw.png');
$(this).css('opacity', .5);
});
Any ideas? Thanks in advance.
EDIT: Threw together a fiddle: http://jsfiddle.net/3WZ7J/ - does seem to work correctly most of the time, my images might be too large or not preloading correctly.
You can wait for the image to load before changing the opacity of the div
$('.character').on('mouseenter', function() {
var $this = $(this);
var full_src = $this.find('img').attr('src');
var half_src = full_src.split("-");
$this.find('img').load(function(){
$this.css('opacity', 1);
}).attr('src', half_src[0] + '-color.png');
});
FIDDLE
One thing you could try is .promise() to force the order in which the operations take place, so that the opacity won't change until the image has swapped out. Some info here: http://api.jquery.com/promise/
i have a div element, with very big size background image. so, is it possible, to set a little size image as backgrount, untill the big size image loads.
thanks
I guess you could put another div element underneath it (using the z-index property) and give that the faster loading background image.
Whether that is practical to do, depends on your Layout, you'd have to give more information about that.
There's also the ages-old lowsrc HTML 4 property that still seems to be pretty well supported (I have not tried it myself since Netscape 4), but that won't work for background images.
CSS:
.that-div {
background-image:url(/path/to/small-image.png);
}
jQuery:
$(function () {
var bigImg = new Image(),
bigImgSrc = '/path/to/big-image.png';
bigImg.src = bigImgSrc;
$(bigImg).load(function(){
$('.that-div').css('background-image':'url('+bigImgSrc+')');
});
});