How to defer background images without jQuery or lazy loading - javascript

Based on Patrick Sexton tutorial, I would like to defer background images in the same way I do here with img:
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="your-image-here">
<script>
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
} } }
window.onload = init;
</script>
How can I do the same using backgrounds?
<div style="background:url(your-image-here)"></div>

Changes needed are only how we select the element
document.querySelectorAll('div[data-src]');
and how we set the value (here instead of setting the src attribute, we need to set the style attribute).
EDIT: I would even avoid the attribute check (in the JavaScript) here since our selector would do it.
Mark-up (Edit code here: http://codepen.io/anon/pen/rryxoK)
function init() {
var imgDefer = document.querySelectorAll('div[data-src]');
var style = "background-image: url({url})";
for (var i = 0; i < imgDefer.length; i++) {
imgDefer[i].setAttribute('style', style.replace("{url}", imgDefer[i].getAttribute('data-src')));
}
}
window.onload = init;
.deferImage {
width: 800px;
height: 600px;
}
<div class="deferImage" data-src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/96/Domestic-crested-duck-CamdenME.jpg/800px-Domestic-crested-duck-CamdenME.jpg"></div>
EDIT: To select by class name

You can just do the same idea but instead of source you change the background in the init function
<div id='my-div' style="" data-src="your-image-here"></div>
<script>
function init() {
var backgroundDefer = document.getElementById('my-div');
if(backgroundDefer.getAttribute('data-src')) {
backgroundDefer.style.background="url("+backgroundDefer.getAttribute('data-src')+")";
}
}
window.onload = init;
</script>

I tried to use getElementsByClassName() and also ended up getting the backgroundDefer.getAttribute is not a function error. So I ended up inject id attribute, as well as the data-src attribute to be used as a placeholder for image URI and used the above code to defer background image.
I also have to first of all make an empty string in the background URI image.
<div id="my-div" class="parallax-background" data-stellar-background-ratio="0.7" data-src="https://d5y2y5rl4e57i.cloudfront.net/GWL_atl-108.jpg" style="background-image:url('')"></div>
<script>
function init() {
var backgroundDefer = document.getElementById('my-div');
//have to use document.getElementById in order to use getAttribute() function
if(backgroundDefer.getAttribute('data-src')) {
backgroundDefer.style="background-image:url("+backgroundDefer.getAttribute('data-src')+")";
}
}
window.onload = init;
</script>

If all You want to do is set background after page load in pure JS use:
window.onload="myFunction()";
Where myFunction do the loading.

Related

Javascript: Error in custom script for lazyload images

I am trying to write the following script to lazyload background images of sub-menu on a website. But this function returns the error
Missing ) after argument list
My requirement is to load the background images after the window loaded completely. What i am doing is , I have added some data attributes to get the background image url, position etc. and then on windows load call this function which adds the css for the sub-menu.
<script>
function menuImageLazyLoad() {
var imgDefer = document.getElementsByClassName('megamenu-content');
for (var i = 0; i < imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-background-image')) {
imgDefer[i].css(
"background-image":+imgDefer[i].getAttribute('data-background-image'),
"background-position":+imgDefer[i].getAttribute('data-background-position'),
"background-repeat":+imgDefer[i].getAttribute('data-background-repeat')
);
console.log(imgDefer[i].getAttribute('data-background-image'));
}
}
}
window.onload = menuImageLazyLoad;
</script>
console logs returns the url of image:
url(image/sub_menu_image.jpg)
How can i fix this problem?
Update:
This is the final solution for my problem. I hope it may help someone
<script>
function menuImageLazyLoad() {
var imgDefer = document.getElementsByClassName('megamenu-content');
for (var i = 0; i < imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-background-image')) {
$(imgDefer[i]).css("background-image",imgDefer[i].getAttribute('data-background-image'));
$(imgDefer[i]).css("background-position",imgDefer[i].getAttribute('data-background-position'));
$(imgDefer[i]).css("background-repeat",imgDefer[i].getAttribute('data-background-repeat'));
}
}
}
window.onload = menuImageLazyLoad;
</script>
I guess you miss {}
For multiple attribute css settings,
It should be set as an object https://www.w3schools.com/jquery/jquery_css.asp
imgDefer[i].css(
{"background-image":+imgDefer[i].getAttribute('data-background-image'),
"background-position":+imgDefer[i].getAttribute('data-background-position'),
"background-repeat":+imgDefer[i].getAttribute('data-background-repeat')
});

HTML JavaScript delay downloading img src until node in DOM

Hi I have markup sent to me from a server and I set it as the innerHTML of a div element for the purpose of traversing the tree, finding image nodes, and changing their src values. Is there a way to prevent the original src value from being downloaded?
Here is what I am doing
function replaceImageSrcsInMarkup(markup) {
var div = document.createElement('div');
div.innerHTML = markup;
var images = div.getElementsByTagName('img');
images.forEach(replaceSrc);
return div.innerHTML;
}
The problem is that in browsers as soon as you do:
var img = document.createElement('img'); img.src = 'someurl.com' the browser fires off a request to someurl.com. Is there a way to prevent this without resorting to parsing the markup myself? If there is in no other way does anyone know a good way of parsing the markup with as little code as possible to accomplish my goal?
I know you are already happy with your solution, but I think it would be worth sharing a safe method for future users.
You can now simply use the DOMParser object to generate an external document from your HTML string, instead of using a div created by your current document as container.
DOMParser specifically avoids the pitfalls mentioned in the question and other threats: no img src download, no JavaScript execution, even in elements attributes.
So in your case you can safely do:
function replaceImageSrcsInMarkup(markup) {
var parser = new DOMParser(),
doc = parser.parseFromString(markup, "text/html");
// Manipulate `doc` as a regular document
var images = doc.getElementsByTagName('img');
for (var i = 0; i < images.length; i += 1) {
replaceSrc(images[i]);
}
return doc.body.innerHTML;
}
Demo: http://jsfiddle.net/94b7gyg9/1/
Note: with your current code, browsers will still try downloading the resource initially specified in your img nodes src attribute, even if you change it before the end of JS execution. Trace network transactions in this demo: http://jsfiddle.net/94b7gyg9/
Rather than append the new markup to the DOM before you change the img sources, create an element, set it's inner HTML, change the source of the images and then finally, append the changed markup to the page.
Here's a fully-worked sample.
<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
//function allByClass(className,parent){return (parent == undefined ? document : parent).getElementsByClassName(className);}
function allByTag(tagName,parent){return (parent == undefined ? document : parent).getElementsByTagName(tagName);}
function newEl(tag){return document.createElement(tag);}
//function newTxt(txt){return document.createTextNode(txt);}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded()
{
byId('goBtn').addEventListener('click', onGoBtnClick, false);
}
var dummyString = "<img src='img/girl.png'/><img src='img/gfx07.jpg'/>";
function onGoBtnClick(evt)
{
var div = newEl('div');
div.innerHTML = dummyString;
var mImgs = allByTag('img', div);
for (var i=0, n=mImgs.length; i<n; i++)
{
mImgs[i].src = "img/murderface.jpg";
}
document.body.appendChild(div);
}
</script>
<style>
</style>
</head>
<body>
<button id='goBtn'>GO!</button>
</body>
</html>
You could directly parse the markup string using a regex to replace the img src. Searching for all the img src urls in the string and then replacing them with the new url.
var regex = /<img[^>]+src="?([^"\s]+)"?\s*\/>/g;
var imgUrls = [];
while ( m = regex.exec( markup ) ) {
imgUrls.push( m[1] );
}
imgUrls.forEach(function(url) {
markup = markup.replace(url,'new-url');
});
Another solution might be, if you have access to it, to set the all the img src to an empty string, and put the url in in a data-src attribute. Having your markup string look like something like this
markup = '
';
Then setting this markup to your div.innerHTML won't trigger any download from the browser. And you can still parse it using regular DOM selector.
div.innerHTML = markup;
var images = div.getElementsByTagName('img');
images.forEach(function(img){
var oldSrc = img.getAttribute('data-src');
img.setAttribute('src', 'new-url');
});

Toggle image src attribute using Javascript

I am trying to change the HTML image src using Javascript. I have two images Plus.gif and Minus.gif.I have inserted HTML img tag and have written a Javascript function to change the image src when clicked.
Problem is that I want to change it back again when user clicks on the image.
For example when the page is loaded the Plus.gif shows and when user clicks on it the image it changes to Minus.gif.
I want it so, when the image is Minus.gif and user clicks on it this should be changed to Plus.gif.
Here is my Javascript function:
<script language="javascript" type="text/javascript">
function chngimg() {
var img = document.getElementById('imgplus').src; //= 'Images/Minus.gif';
if (img) {
document.getElementById('imgplus').src = 'Images/Minus.gif';
} else if (!img) {
document.getElementById('imgplus').src = 'Images/Plus.gif';
alert(img);
}
}
</script>
Image tag:
<img id="imgplus" alt="" src="Images/Plus.gif" onmouseover="this.style.cursor='pointer'" onclick="chngimg()" />
See the changes I made to make it working
<script language="javascript" type="text/javascript">
function chngimg() {
var img = document.getElementById('imgplus').src;
if (img.indexOf('Plus.gif')!=-1) {
document.getElementById('imgplus').src = 'Images/Minus.gif';
}
else {
document.getElementById('imgplus').src = 'Images/Plus.gif';
}
}
</script>
<img id="imgplus" alt="" src="Images/Plus.gif" onmouseover="this.style.cursor='pointer'" onclick="chngimg()" />
Hope that resolves your question.
One way would be to add a toggle variable in your function:
var toggle = false;
function chngimg() {
if (toggle === true) {
document.getElementById('imgplus').src = 'Images/Minus.gif';
} else {
document.getElementById('imgplus').src = 'Images/Plus.gif';
alert(img);
}
toggle = !toggle;
}
Note that it's a better practice to use a sprite for this kind of thing. If you're using two images, the user experience is going to be clunky, because the first time they click the image, there will be a slight delay while the second image loads.
Ideally you would have the two images as a sprite sheet, and be using JQuery. Then you could just do it like this.
HTML
<img id="imgplus" src="Images/Sprite.gif" onclick="chngimg()" />
CSS
#imgplus .clicked { background-position: 0 -30px; }
Javascript
function chngimg() {
$("#imgplus").toggleClass("clicked");
}
I have successfully used this general solution in pure JS for the problem of toggling an img url:
function toggleImg() {
let initialImg = document.getElementById("img-toggle").src;
let srcTest = initialImg.includes('initial/img/url');
let newImg = {
'true':'second/img/url',
'false':'initial/img/url'}[srcTest];
return newImg;
}
Then call toggleImg() inside whatever event handler you use....
someButton.addEventListener("click", function() {
document.getElementById("img-toggle").src = toggleImg();
}

Toggling between two images by clicking

Due to this link
I changed it to this one:
<html>
<head>
<script>
var toggleimage=new Array("p1.gif","p.gif")
//do not edit the variables below
var image_1=new Image()
var image_2=new Image()
image_1.src=toggleimage[0]
image_2.src=toggleimage[1]
var i_image=0
function testloading() {
isloaded=true
}
function toggle() {
if (isloaded) {
document.togglepicture.src=toggleimage[i_image]
}
i_image++
if (i_image>1) {i_image=0}
}
onload=testloading
</script>
<title>
</title>
<meta content="">
<style></style>
</head>
<body>
<img name="togglepicture" src="p1.gif" border="0">
</body>
</html>
when I click on the image p it will show me p1 and vice versa
Now I have problem image has a name:
<img name="togglepicture" src="p1.gif" border="0">
and it will get the name here:
document.togglepicture.src=toggleimage[i_image]
I want to have many images so I thaught I need to change the togglepicture to a variable
for example:
function toggle(a) {
if (isloaded) {
document.a.src=toggleimage[i_image]
}
i_image++
if (i_image>1) {i_image=0}
}
and for input forexample it will be toggle('nameofimage') and in the href it will be something like
<a href="javascript:toggle('pic1')">
I wasn't successful.How can I use this function when I have more than a picture to click?
I made a modular toogle, visible here: http://jsfiddle.net/Regisc/N7bgz/2/
Usage sample:
<img id="image1" src="http://dummyimage.com/50/f00/fff&text=a"
onclick='toogle(this, ["http://dummyimage.com/50/ab0/fff&text=b",
"http://dummyimage.com/50/ab0/fff&text=c"]);' />
you can't use
document.a.src=toggleimage[i_image];
instead use
document.getElementById(a).src=toggleimage[i_image];
And you also need to add an id to your img element.
Something like the following should work for any number of images provided toggleimage is a contiguous array.
var toggleimage = ["p1.gif","p.gif"];
var toggle = (function() {
var count = 0;
var len = toggleimage.length;
var el = document.getElementsByName('togglepicture')[0]
return function() {
if (isloaded) {
el.src = toggleimage[count++ % len];
}
};
}());
I'm not entirely sure I got your question. Are you asking:
How to edit the function to allow toggling between more than just two images, or
How to edit the function to handle more than one set of toggle images?
Toggling between more than just two images
var toggleimage=new Array("p1.gif","p.gif","p2.gif","p3.gif","p4.gif")
var totalImages=4;
function toggle() {
if (isloaded) {
document.togglepicture.src=toggleimage[i_image]
}
i_image++
if (i_image>totalImages) {i_image=0}
}
How to edit the function to handle more than one set of toggle images?
call the JS function like this
<a href="javascript:toggle(this)">
And, in your JS function,
var id = div.id;
Use this in an if-else to determine which control called the function and accordingly which array of images to use.
function toggle(div)
{
var id = div.id;
if (isloaded)
{
if (id == 'myFirstToggleImageControl')
{
document.togglepicture.src=toggleimage[i_image];
}
else if (id == 'mySecondToggleImageControl')
{
document.togglepicture.src=toggleimageSource2[i_image];
}
}
i_image++
if (i_image>1) {i_image=0}
}
Note: You will want to use an independent counter for the second control. So, possibly i_image1 and i_image2
<html>
<head>
<script>
// images list (properties name must by equal to id of IMAGE html element)
var imageList={
image1: {
currentIndex:0,
images:["p1.gif","p.gif"]
}
};
// preloading images using closure (additionaly replace image URL's with image objects)
(function() {
for(var p in imageList)if(imageList.hasOwnProperty(p)) {
for(var i=0;i<imageList[p].images.length;i++) {
var img=new Image(),src=imageList[p].images[i];
(imageList[p].images[i]=img).src=src;
}
}
})();
function toogleImage() {
var info=imageList[this.id];
info.currentIndex++;
if(info.currentIndex===info.images.length)info.currentIndex=0;
this.src=info.images[info.currentIndex].src;
}
// setting start images
window.onload=function() {
for(var p in imageList)if(imageList.hasOwnProperty(p)) {
//try{
document.getElementById(p).src=imageList[p].images[0].src;
//}
//catch(ex){}
}
}
</script>
</head>
<body>
<img id="image1" onclick="toogleImage.call(this);"/>
</body>
</html>
http://jsfiddle.net/X4Q2m/

Javascript to Remove Elements loaded in iFrame

After searching Google and Stack Overflow I decided to ask if this is even possible.
Currently I am loading an iFrame on my site. I wish to hide a certain element loaded in the iFrame.
<span id="blahblah">
function collapseAll(){
var body = document.getElementById('body');
var spans = body.getElementsByTagName("span");
var span;
for (i = 0; i < spans.length; i++){
span = spans[i];
if(span.class=='blahblah'){
span.style.visibility = "hidden";
}
}
}
However this did not work. Question number one is can this be done? If yes could you explain how?
Thank you kindly.
You'll have to put that script inside the contents of the iframe. You can't access the DOM of another frame, especially if it's from another domain.
Sorry, but you cannot access elements within an iframe from the outer window, due to security controls.
You would have to try this, but you might be able to create a function on the window object of the iframe and the call it from the outer window.
In the iframe:
<script type="text/javascript">
window.collapseAll = function() {
.....
}
</script>
In the outer window:
<script type="text/javascript">
function doCollapse() {
document.getElementById('my_iframe").window.collapseAll();
}
</script>
Again, that's untested but I'm pretty sure Facebook does something similar to that.
if the iframe is from the same domain as your javascript is from then this is doable.
using plain javascript you would write the following
`
function collapseAll(){
var body = document.getElementById('body');
var spans = body.getElementsByTagName("span");
var span;
for (i = 0; i < spans.length; i++){
span = spans[i];
if(span.class=='blahblah'){
**span.style.display = "none";**
}
}
}
this fixes the issue.
if the iframe is from a different site (domain) then things would get really difficult..
there are solutions like greasemonkey which can operate on pages from different domains.
you can try
document.frame.document.getElementsByTagName('span')
<script type="text/javascript">
function remove_elemment() {
var body = document.getElementById('body');
var divs = body.getElementsByTagName("div");
var div;
for (i = 0; i < divs.length; i++){
div = divs[i];
if(div.class=='buybox'){
**div.style.display = "none";**
}
}
};
function doRemove() {
document.frame.document.getElementById('my_iframe').remove_elemment();
}();
</script>
<div class="floating-widget">
<iframe id="my_iframe" src="http://www.nodebeginner.org/index-vi.html" frameborder="0" width="100%" height="500">
</iframe>
</div>

Categories

Resources