How to force browsers to preload image with display: none? - html

Firefox will not load images with display: none until they are required to be shown to the user. Chromium will stall until the image is loaded, and then display it.
With smaller file sizes, there is a brief flash if the image is not already loaded on Firefox. With larger file sizes, there is a much longer delay that will also make Chromium's stall noticeable.
I would like to have images with display: none preloaded so there is no delay when displaying them.
I have tried using Javascript to declare a new Image object, but this does not work with Firefox or Chromium.
You can cycle between images in this example with the right and left arrow keys.
<!DOCTYPE html>
<html>
<head>
<style>
body, html {
height: 100%;
margin: 0;
padding: 0;
}
.imgs {
width:50%;
height: 50%;
}
</style>
</head>
<body>
<img src="https://picsum.photos/200/100" style="display: block;" class="imgs">
<img src="https://picsum.photos/200/200" style="display: none;" class="imgs">
<script>
imgs = document.getElementsByClassName("imgs");
// THIS DOES NOT WORK
//~ function preloadImage(url)
//~ {
//~ var img = new Image();
//~ img.src = url;
//~ }
//preloadImage("myImg.jpg"); THIS DOES NOT WORK
document.onkeydown = checkKey; // directional keys
function checkKey(e) {
if (document.activeElement.tagName != "INPUT") {
e = e || window.event;
switch (e.keyCode) {
case 38:
// up arrow
break;
case 40:
// down arrow
break;
case 37:
// left arrow
imgs[0].style.display = "block";
imgs[1].style.display = "none";
break;
case 39:
// right arrow
imgs[0].style.display = "none";
imgs[1].style.display = "block";
break;
}
}
}
</script>
</body>
</html>

I have figured out my own solution to this problem.
I use a class called "imgBuffer" to hold images that need to be displayed immediately. Images of this class will hold the source of images that need to be readily displayed, but will not display the images themselves.
The tricky part is making sure the hidden images are in a location on screen that does not affect the layout in any way.
Notice the width and height of the hidden buffered image matches that of the displayed images. If you adjust the dimensions of the hidden image, the page may behave differently such as adding a scrollbar when it's not really necessary.
<!DOCTYPE html>
<html>
<head>
<style>
body, html {
height: 100%;
margin: 0;
padding: 0;
}
.imgs {
width:50%;
height: 50%;
}
.imgBuffer {
position: absolute;
height: 50%;
width: 50%;
visibility: hidden;
z-index: -1;
}
</style>
</head>
<body>
<img src="https://picsum.photos/200/100" style="display: block;" class="imgs">
<img src="https://picsum.photos/200/200" style="display: none;" class="imgs">
<img src="https://picsum.photos/200/100" class="imgBuffer">
<img src="https://picsum.photos/200/200" class="imgBuffer">
<script>
imgs = document.getElementsByClassName("imgs");
// THIS DOES NOT WORK
//~ function preloadImage(url)
//~ {
//~ var img = new Image();
//~ img.src = url;
//~ }
//preloadImage("myImg.jpg"); THIS DOES NOT WORK
document.onkeydown = checkKey; // directional keys
function checkKey(e) {
if (document.activeElement.tagName != "INPUT") {
e = e || window.event;
switch (e.keyCode) {
case 38:
// up arrow
break;
case 40:
// down arrow
break;
case 37:
// left arrow
imgs[0].style.display = "block";
imgs[1].style.display = "none";
break;
case 39:
// right arrow
imgs[0].style.display = "none";
imgs[1].style.display = "block";
break;
}
}
}
</script>
</body>
</html>

Related

how to make a loading animation with my code

I can't seem to figure out how to make the boxes rotate. I tried transformation, JS, and even html special code. I do suck at CSS, so this is my code so far:
<!DOCTYPE html>
<html>
<head>
<script>
//great code from Scriptkiddy1337 on stack overflow
const pageStack=[];
function getParameterByName(name, url) {
url = url || window.location.href;
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
window.addEventListener('load', function (e) {
var templates = document.getElementsByClassName('sitecontent');
for (var i = 0, v; v = templates[i]; i++) {
for (var j = 0, x; x = v.childNodes[j]; j++) {
if (x.nodeType === Node.ELEMENT_NODE) {
pageStack.push(x);
}
}
}
var pageIndex = getParameterByName('page') || '0';
loadPage(pageIndex);
});
function loadPage(index) {
if (index >= pageStack.length || index < 0) {
document.body.innerText = '404 Page not found';
return;
}
document.body.innerHTML = '';
document.body.appendChild(pageStack[index]);
}
</script>
<style>
box{
transition: 3s;
width:50px;
height:50px;
position:fixed;
transform:/*im confused here*/;
}
</style>
</head>
<body>
<pageholder class="sitecontent">
<page>
<animator>
<!--I want them to rotate in a circle-->
<box style="background-color:red">.</box><br><br><br>
<box style="background-color:red">.</box><br><br><br>
<box style="background-color:red">.</box><br><br><br>
</animator>
Next Page
</page>
<page>
<h1>Homepage</h1>
<hr>
<p>Need help :(</p>
</page>
</pageholder>
</body>
</html>
I tried to transform CSSstuff, JS animations (which I also kinda suck at), and even special HTML code. I might be missing something, but as far as I know (which isn't a lot, unfortunately), I have done nearly everything I can think of.
I would highly recommend you read up on CSS Animations
<style>
/* The animation code */
#keyframes rotateBox {
to {transform: rotate(360deg)}
}
box{
transition: 3s;
width: 50px;
height: 50px;
position: fixed;
/* Use the animation here */
animation: rotateBox 3s;
}
</style>

How to make the image swap every second

This code will turn the bulb on/off but i want to make the lightbulbs keeps flashing. I've tried different methods and nothing works
<!DOCTYPE html>
<html>
<body>
<img id="bulb" onclick="switch()" src="off.png" width="100" height="180">
<p>On/Off</p>
<script>
function
switch () {
var image = document.getElementById('Bulb');
if (image.src.match("on")) {
image.src = "off.png";
} else {
image.src = "on.png";
}
}
</script>
</body>
</html>
Here is an example, using setInterval(). I have swapped the image to a div thats background changes color, but same principal applies.
I think its also worth pointing out that you could also do this with a css animation and then just use javascript to toggle the class onto the element. But assuming you just wanna stick to JS for now:
let flashInterval = null;
let flashSpeed = 100;
let bulb = document.getElementById('bulb');
function toggleBulb() {
if (bulb.classList.contains('on')) {
bulb.classList.remove('on');
} else {
bulb.classList.add('on');
}
}
function flashBulb() {
if (flashInterval === null) {
flashInterval = setInterval(() => {
toggleBulb();
}, flashSpeed);
} else {
clearInterval(flashInterval);
flashInterval = null;
}
}
document.getElementById('toggleBlub').addEventListener('click', toggleBulb);
document.getElementById('toggleFlash').addEventListener('click', flashBulb);
#bulb {
width: 50px;
height: 50px;
border-radius: 50%;
border: 1px solid #ccc;
background: transparent:
}
.on {
background: #fcba03;
}
<div id="bulb" class=""></div>
<br>
<button id="toggleBlub">Bulb On/Off</button>
<br><br>
<button id="toggleFlash">Flash On/Off</button>
in my opinion, don't use setInterval but u can use a CSS animation rather than it.
You should know about js event and js reserve keyword and be sure to use good code editor so that you can see your error.
I see you trying to keep flashing but you used onclick event that is clickable it will not flashing.
here is the code below, which you want,
<!DOCTYPE html>
<html>
<body>
<img id="bulb" src="off.jpg" width="100" height="180">
<p>On/Off</p>
<script>
var myImage = document.querySelector('#bulb');
var update = setInterval(myUpdate, 1000);
function myUpdate() {
setTimeout(() => {
if (myImage.src.match('off.jpg')) {
myImage.src = 'on.jpg'
} else {
myImage.src = 'off.jpg'
}
}, 500)
}
</script>
</body>
</html>
or you can use onclick event, when you click than it will start flashing
here is the code below
<!DOCTYPE html>
<html>
<body>
<img id="bulb" onclick="mySwitch(this)" src="off.jpg" width="100" height="180">
<p>On/Off</p>
<script>
function mySwitch(myImage) {
var update = setInterval(myUpdate, 500);
function myUpdate() {
setTimeout(() => {
if (myImage.src.match('off.jpg')) {
myImage.src = 'on.JPG'
} else {
myImage.src = 'off.jpg'
}
}, 100)
console.log(myImage)
}
}
</script>
</body>
</html>
I changed your function name to switchBulb because switch is reserved
var intervalID = window.setInterval(switchBulb, 1000);
function switchBulb() {
var image = document.getElementById('bulb');
if (image.src.match("on")) {
image.src = "off.png";
} else {
image.src = "on.png";
}
}

How to make an image clickable within span button?

I am trying to make a span within a button clickable. The span has a .png image within it. It will only act as a button when I click around the actual image, but not when I click on the image itself. I cant find any solutions that directly relates to my issue.
HTML
<button id="btn3"><span class"btn3"></span></button>
CSS
span.btn3 {
background: url("./images/raincloud.png") no-repeat top left;
background-size: contain;
cursor: pointer;
display: inline-block;
height: 80px;
width: 80px;
}
Edit:
Here is the JS function. It is meant to change the audio/video file when a certain button is clicked.
[].forEach.call(document.getElementsByClassName('btn'),
function(btn) {
btn.addEventListener('click', function(e) {
switch (e.target.id) {
case "btn3":
video.src = "./video/rain2.mp4";
video.play();
break;
case "btn4":
video.src = "./video/rain1.mp4";
video.play();
break;
case "btn5":
audio.src = "./audio/rain.mp4";
audio.play();
break;
case "btn6":
audio.src = "./audio/rain2.mp4";
audio.play();
break;
}
})
})
Missing =in class="btn3"
You want the ID of the parent of the target
your forEach is not very convincing. I delegate instead from the nearest container
const audio = document.getElementById("audio");
const video = document.getElementById("video");
document.getElementById("container").addEventListener("click", function(e) {
var tgt = e.target;
if (tgt.tagName == "SPAN") {
var id = tgt.closest("button").id;
console.log(id)
switch (id) {
case "btn3":
video.src = "./video/rain2.mp4";
video.play();
break;
case "btn4":
video.src = "./video/rain1.mp4";
video.play();
break;
case "btn5":
audio.src = "./audio/rain.mp4";
audio.play();
break;
case "btn6":
audio.src = "./audio/rain2.mp4";
audio.play();
break;
}
}
})
span.btn3 {
background: url(https://img.icons8.com/cotton/2x/cloud.png) no-repeat top left;
background-size: contain;
cursor: pointer;
display: inline-block;
height: 80px;
width: 80px;
}
<div id="container">
<button id="btn3"><span class="btn3"></span></button>
<button id="btn3"><span class="btn3"></span></button>
<button id="btn4"><span class="btn3"></span></button>
<button id="btn5"><span class="btn3"></span></button>
</div>
<audio id="audio" />
<video id="video" />
Add the onClick property via JavaScript to the span element (https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick)
HTML
<button id="btn3"><span class="btn3" id="span_in_button"></span></button>
JavaScript
document.getElementById('span_in_button').onclick = function changeContent() {
// Your functionality here.
}
or by https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event
or add onclick property directly into the HTML span element https://www.w3schools.com/TAgs/att_onclick.asp
in HTML body:
<button id="btn3"><span class="btn3" onclick="myFunction()"></span></button>
in HTML head:
<script>
function myFunction() {
// Your functionality here.
}
</script>

dragleave event is firing on inner childs

I am trying to use HTML5 drag and drop and make the dropable container to change its style when the draggable element is over it.
the problem is if the dropable container contain inner elements a dragleave events getting fired making the container to lose its style.
as you can see when the draggable element is getting inside the small green box. we lose the red border of the outside div.
<html>
<head>
<style>
.droptarget {
width: 100px;
height: 100px;
margin: 15px;
margin-right: 100px;
padding: 10px;
border: 1px solid #aaaaaa;
}
.inner-droptarget {
margin-left: 20px;
margin-top: 20px;
width: 50px;
height: 50px;
border: 1px solid green
}
</style>
</head>
<body>
<p ondragstart="dragStart(event)" draggable="true" id="dragtarget">Drag me!</p>
<div class="droptarget" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" ondrop="drop(event)" ondragover="allowDrop(event)">
<div class="inner-droptarget">
</div>
</div>
<script>
function dragStart(event) {
event.dataTransfer.setData("Text", event.target.id);
}
function dragEnter(event) {
if ( event.target.className == "droptarget" ) {
event.target.style.border = "3px dotted red";
}
}
function dragLeave(event) {
if ( event.target.className == "droptarget" ) {
event.target.style.border = "";
}
}
</script>
<p>
The border of the outside div should remain red even if dragging into the green div!
</p>
</body>
</html>
You have to ignore "dragleave" events that are fired on elements that are contained in "droptarget" (for example "inner-droptarget").
To do so, you can detect if the event was fired from a descendant of the drop area. Your handler will look like this:
function dragLeave(event) {
if ( event.target.className == "droptarget" ) && !($('.droptarget').contains(event.fromElement) {
event.target.style.border = "";
}
}
When you enter the inner div during dragging, the event drag enter and then drag leave event is firing. We need a way to mark that you are leaving the outer div and entering the inner div so the border stays red on the outer div.
I can get both borders to be red, but when you leave its a similar problem, both borders go back to green.
<body>
<p ondragstart="dragStart(event)" draggable="true" id="dragtarget">Drag me!</p>
<div id="myOuterDiv" class="droptarget" ondragenter="dragEnter1(event)"
ondragleave="dragLeave1(event)"
ondrop="drop(event)"
ondragover="allowDrop(event)">
<div id="myInnerDiv" class="inner-droptarget" ondragenter="dragEnter2(event)"
ondragleave="dragLeave2(event)">
</div>
</div>
<script>
var inOuter = false;
var inInner = false;
function dragStart(event) {
event.dataTransfer.setData("Text", event.target.id);
}
function dragEnter1(event) {
inOuter = true;
document.getElementById("myInnerDiv").addEventListener("ondragenter", dragEnter2);
console.log("entered outer");
return highlightBorder();
}
function dragLeave1(event) {
console.log("left outer");
inOuter = false;
highlightBorder();
event.preventDefault();
}
function dragEnter2(event) {
console.log("entered inner");
inInner = true;
inOuter = true;
return highlightBorder();
}
function dragLeave2(event) {
console.log("left inner");
inInner = false;
inOuter = true;
return highlightBorder();
}
function allowDrop(ev) {
return false;
}
function drop(event) {
var inOuter = false;
var inInner = false;
document.getElementById("myInnerDiv").style.border ="3px solid green";
document.getElementById("myOuterDiv").style.border ="3px solid green";
return false;
}
function highlightBorder() {
if( inInner)
{
document.getElementById("myInnerDiv").style.border ="3px dotted red";
document.getElementById("myOuterDiv").style.border ="3px dotted red";
return false;
}
if(!inInner && inOuter)
{
document.getElementById("myInnerDiv").style.border ="";
document.getElementById("myOuterDiv").style.border ="3px dotted red";
return false;
}
if(!inInner && !inOuter)
{
document.getElementById("myInnerDiv").style.border ="";
document.getElementById("myOuterDiv").style.border ="";
return false;
}
}
</script>
<p>
The border of the outside div should remain red even if dragging into the green div!
</p>
</body>
</html>
You can use a counter to solve the problem.When dragenter counter++,when dragleave counter-- and check counter === 0 then do something.
// div has an child element
divEl.addEventListen("dragenter",dragEnter)
divEl.addEventListen("dragleave",dragLeave)
counter = 0
function dragEnter(){
counter++
}
function dragLeave(){
counter--
if(counter === 0){
// then do something
}
}

Hover not working with text below image in anchor tag html

I have this code for making a nav bar. I am trying to add image buttons with text below them. The problem is that the images can be of different sizes and thus they are not centered properly in the output.
Also, the title for all images must come at same level but its not the case.
ul.nav-icon {
list-style: none;
display: block;
margin: auto;
width: 800px;
}
ul.nav-icon li {
float: left;
}
ul.nav-icon a {
display: inline-block;
text-decoration: none;
}
ul.nav-icon a:hover {
background: #4095A6;
}
ul.nav-icon img {
margin: 0px 0px 0px 0px;
padding-top: 16px;
padding-left: 30px;
}
.img-box {
width: 160px;
height: 138px;
}
h6 {
color: white;
text-align: center;
}
<ul class="nav-icon">
<li>
<a href="#" class="img-box">
<img src="http://imgur.com/Et4vXHk.png">
<h6>Families</h6>
</a>
</li>
<li>
<a href="#" class="img-box">
<img src="http://i.imgur.com/lubEbTP.png">
<h6>Families</h6>
</a>
</li>
<li>
<a href="#" class="img-box">
<img src="http://i.imgur.com/lubEbTP.png">
<h6>Families</h6>
</a>
</li>
</ul>
Here's a way to deal with your problem: https://github.com/smohadjer/sameHeight
Here's the .js file you'll need to include in your html. It's better if it's an external file. For any confusion, this file can also be found in the link above with both minified/unminified versions.
;(function ($, window, document, undefined) {
'use strict';
var pluginName = 'sameHeight',
defaults = {
oneHeightForAll: false,
useCSSHeight: false
};
//private method
var getHeightOfTallest = function(elms) {
var height = 0;
$.each(elms, function() {
var _h = $(this).outerHeight();
if (_h > height) {
height = _h;
}
});
return height;
};
// The actual plugin constructor
function Plugin(element, options) {
this.$element = $(element);
this.options = $.extend({}, defaults, options);
this.init();
}
// methods
var methods = {
init: function() {
var self = this;
self.index = 0;
self.$elms = self.$element.children();
self.cssProperty = self.options.useCSSHeight ? 'height' : 'min-height';
$(window).on('resize.' + pluginName, function() {
//remove previously set height or min-height
self.$elms.css(self.cssProperty, '');
initSameHeight();
});
//use setTimeout to make sure any code in stack is executed before
//calculating height
setTimeout(function() {
initSameHeight();
}, 0);
function initSameHeight() {
//if there are adjacent elements
if (self.getRow(0).length > 1) {
self.setMinHeight(0);
if (self.options.callback) {
self.options.callback();
}
}
}
},
setMinHeight: function(index){
var self = this;
var row = self.options.oneHeightForAll ? self.$elms : self.getRow(index);
var height = getHeightOfTallest(row);
$.each(row, function() {
$(this).css(self.cssProperty, height);
});
if (!self.options.oneHeightForAll && self.index < self.$elms.length - 1) {
self.setMinHeight(self.index);
}
},
getRow: function(index) {
var self = this;
var row = [];
var $first = self.$elms.eq(index);
var top = $first.position().top;
row.push($first);
self.$elms.slice(index + 1).each(function() {
var $elm = $(this);
if ($elm.position().top === top) {
row.push($elm);
self.index = $elm.index();
} else {
self.index = $elm.index();
return false;
}
});
return row;
},
destroy: function() {
var self = this;
//remove event handlers
$(window).off('resize.' + pluginName);
//remove dom changes
self.$elms.css(self.cssProperty, '');
self.$element.removeData('plugin_' + pluginName);
}
};
// build
$.extend(Plugin.prototype, methods);
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[pluginName] = function(options) {
this.each(function() {
if(!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
});
return this;
};
})(jQuery, window, document);
After you include the above .js file, add this script to your current page:
$('.img-box').sameHeight();
This should make all of your boxes with image/text be the same size height wise.
Next in order to make sure the text is always at a certain point within your img-box, add some css inline, or make a class with the css as
h6 {
bottom:10px;
}
The amount of pixels can be anything you'd like it to be. To explain, the text will now always be 10 pixels from the bottom of the img-box.
Either this, or just make the images the background image for the container and set them all to predetermined sizes.