How to remove glitch from jQuery infinite background loop? - html

I have a background image set to loop infinitely on a 10 second CSS animation. I'm using jQuery to find the height of the image based on the users screen size. Then I use background-position-y and go from 0 to exactly the height of the image. This creates a smooth loop, for any desktop screen size (A separate bg image will be used for mobile).
Issue: On page load, the animation appears to not work correctly on the first iteration of the loop. The image pans slowly for 10s, "jumps" back to the original position, then works correctly for all future iterations of the loop.
Looking for help on how to make the first animation loop, the first 10s to work how it should/like the remaining loops and the path appears to be infinite.
JS Fiddle: https://jsfiddle.net/bennimbl/7xkyhgz2/3/
View the fiddle, note it's slowness for 10 seconds, then note it works correctly after then.

The problem is the starting set up of the background image.
There is a bit of a mixture in this code. It seems as though an attempt was made to use CSS keyframes for the animation and that this was then abandoned and JS/jquery used instead on a timeout.
This snippet simplifies things by getting rid of JS/jquery animation and going back to the keyframes (this can in any case help CPU usage).
The code already sets a CSS variable --height to the height of the current viewport so this is used in the keyframes to move the background image from a top position of 0 to a top position of -this height.
There was a spurious : after animation in the CSS set up which has been removed.
The only other change that has been made is to set the background image to top 0 from the start rather than at the bottom of the viewport.
var fullhdWidth = 1920;
var fullhdHeight = 2685;
var fullhdRatio = fullhdWidth / fullhdHeight;
$('#s1Bg').ready(function() {
var containerWidth = $(this).width();
var containerHeight = $(this).height();
var containerRatio = containerWidth / containerHeight;
var realWidth = null;
var realHeight = null;
if (containerRatio > fullhdRatio) {
realWidth = containerWidth;
realHeight = containerWidth / fullhdRatio;
//alert(realWidth + ' ' + realHeight);
} else {
realWidth = containerHeight * fullhdRatio;
realHeight = containerHeight;
//alert(realWidth + ' ' + realHeight);
}
$('<style>').text(`:root{--height: ${realHeight};}`).appendTo(document.head);
$("#s1Bg").css({
'width': '100vw',
'height': '100vh',
'margin': '0',
'background': '#000000 url("https://iili.io/sVrZXe.jpg") 0% 0%/cover repeat-y',
'animation': 'rideup 10s linear infinite'
});
});
body {
margin: 0;
}
#keyframes rideup {
from {
background-position-y: 0;
}
to {
background-position-y: calc(-1px * var(--height));
}
}
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
</head>
<div id="s1Bg" class="s1-bg"></div>

I've made a little change on your css and gotime function to start at the realHeight and then animate to background-position-y: 0. I moved some css to the css file to since it didn't belong in the js file. Though i couldn't really figure out why it didn't worked out in the previous fiddle it does in this one
JS:
$("#s1Bg").css({
'background-position-y': realHeight,
'animation:' : 'rideup 10s linear infinite'
});
var gotime = function() {
$('#s1Bg').animate({
'background-position-y': 0,
}, 10000, 'linear', function() {
$(this).css('background-position-y', realHeight);
gotime();
});
}
CSS:
#s1Bg {
height: 100vh;
width: 100vw;
margin: 0;
background-image: url('https://iili.io/sVrZXe.jpg');
background-size: cover;
}

Related

Animation with requestAnimationFrame is stuttery on iOS

I'm making a page with parallax background scrolling and I've written the following code to adjust the background image position based on the scroll height:
function animateParallax()
{
if(document.body)
{
document.body.style.backgroundPositionY = (-document.body.scrollTop * 0.35) + "px";
}
window.requestAnimationFrame(animateParallax);
}
window.onload = animateParallax;
This works fine on PC, but on iOS it looks quite stuttery. Is there any way to fix this? Thanks

How to add a tint to a background image with transparency in CSS

I have some content on a page that serves as a global background.
I put a sprite (div with background-image: url(...), changing frames by modifying background-position) on top of that using position: absolute. The sprite is a PNG with alpha-channel.
Now I'm trying to add some tint to that image (greenish or blueish or other).
I've studied the similar questions and apparently the only possible solutions are:
Create a div on top of the sprite with the desired color as its background-color, desired tint strength as opacity and the original sprite image as mask-image (and setting the mask-type: alpha). While it should work on paper, it doesn't in practice - this new div is just invisible :(
Use mix-blend-mode for the overlaying colored div and specify something like multiply or overlay. It produces perfect results as long as the global background is black. If it's something else - it gets included in the calculations and the overlay div modifies it as well, producing a tinted rectangle instead of tinted sprite...
Use SVG filter as described in an answer here: https://stackoverflow.com/a/30949302/306470 .
I didn't try this one yet, but it feels unnecessary complicated for this task. I'm concerned about the performance here too, will it slow down things a lot if there will be multiple tinted sprites on the screen at the same time? If anyone had experience with it - please comment here :)
Prepare a tinted version of the sprite using an invisible canvas. Sounds even more complicated, has a disadvantage of having to spend time to prepare the tinted version of the sprite, but should work as fast as the original sprite once it's prepared? Implementation should be pretty complicated though. Pure CSS solution would be much better...
Am I missing something? Are there any other options? Or should I go with #3 or #4?
Here is a working example of the outlined comment I left, hope it helps. I use a created div element to overlay on top of the image. Get the image elements position using boundingClientRect and this.width/this.height inside a for loop looping over the image elements. Set the overlay elements position to that of the image element being looped over and randomize a color using function with rgb setting alpha to 0.5.
let fgrp = document.getElementById("group");
let images = document.querySelectorAll(".imgs");
//function to randomize the RGB overlay color
function random() {
var o = Math.round,
r = Math.random,
s = 255;
return o(r() * s);
}
//function to randomize a margin for each image to show the overlay will snap to the image
function randomWidth() {
var n = Math.round,
ran = Math.random,
max = 400;
return n(ran() * max);
}
// loop through the img elements and create an overlay div element for each img element
for (let i = 0; i < images.length; i++) {
// load the images and get their wisth and height
images[i].onload = function() {
let width = this.width;
let height = this.height;
this.style.marginLeft = randomWidth() + "px";
// create the overlay element
let overlay = document.createElement("DIV");
// append the overlay element
fgrp.append(overlay);
// get the image elements top, left positions using `getBoundingClientRect()`
let rect = this.getBoundingClientRect();
// set the css for the overlay using the images height, width, left and top positions
// set position to absolute incase scrolling page, zindex to 2
overlay.style.cssText = "width: " + this.offsetWidth + "px; height: " + this.offsetHeight + "px; background-color: rgba(" + random() + ", " + random() + ", " + random() + ", 0.5); left: " + rect.left + "px; top: " + rect.top + "px; position: absolute; display: block; z-index: 2; cursor pointer;";
}
}
img {
margin: 50px 0;
display: block;
}
<div id="group">
<image src="https://artbreeder.b-cdn.net/imgs/275c7c05efca3a40e3178208.jpeg?width=256" class="imgs"></image>
<image src="https://artbreeder.b-cdn.net/imgs/275c7c05efca3a40e3178208.jpeg?width=256" class="imgs"></image>
<image src="https://artbreeder.b-cdn.net/imgs/275c7c05efca3a40e3178208.jpeg?width=256" class="imgs"></image>
</div>
Following the guide below, it is possible to at a colorful tint over a div/image using only CSS, like so:
<html>
<head>
<style>
.hero-image {
position: relative;
width: 100%;
}
.hero-image:after {
position: absolute;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, .5);
top: 0;
left: 0;
display: block;
content: "";
}
</style>
</head>
<body>
<div class="hero-image">
<img src="https://cdn.jpegmini.com/user/images/slider_puffin_before_mobile.jpg" alt="after tint" />
</div>
<div>
<img src="https://cdn.jpegmini.com/user/images/slider_puffin_before_mobile.jpg" alt="before tint" />
</div>
</body>
</html>
Since you are trying to place it on top of an absolute position image, as the guide says, add a z-index of 1 (for example) to the :after chunk.
Edit: It might need some tweaking on the width's percentage!
Source: https://ideabasekent.com/wiki/adding-image-overlay-tint-using-css

Mobile iOS - Fixed background image solution

I know similar issues have been asked several times before but I have trawled through many questions/ answers and cannot find a solution that works for my specific issue.
Basically I have a responsive website which has fixed background images - the images are 1280 x 853 px, they are applied to the html tag via the following css (which is currently a bit of a mess due to trying several solutions) -
html {
background: url(/content/images/bg_lrg.jpg) no-repeat top center fixed;
-webkit-background-size: 1024px 768px;
background-attachment: fixed;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
My idea was to apply a background size - if this worked I'd use media queries to apply relevant sizes for ipad / iphone / other.
the image currently appears huge in iOS devices - as it is constraining itself to the height of the document rather than the viewport - I know there are many issues with fixed backgrounds in mobile Ios - does anyone have a workaround solution? where my image could cosntain to viewport width not document height?
First Solution, have you tried setting your ViewPort? In the head of your HTML, you can include this:
<meta name="viewport" content="width=device-width, initial-scale=1">
I would first try that. You can even specify the width for iPhones. This is the best solution at first in order to get your device to display the size of the image properly on your phone. Here is a link with a quick description of what you can do with ViewPorts:
Many sites set their viewport to "width=320, initial-scale=1" to fit precisely onto the iPhone display in portrait mode. Using the viewport meta tag to control layout on mobile browsers
Secondary Solution:
If that doesn't work, I created a modified this custom solution before these new feature came out. I modified this function to make the background of a website always fill the background regardless of screen size:
JavaScript using JQuery:
//Resize background image function
$(function () {
var $window = $(window);
var width = $window.width();
var height = $window.height();
setInterval(function () {
//Checks for screen resize every hundreth of a second and resizes elements based on that new screen size
if ((width != $window.width()) || (height != $window.height())) {
//resets the variables to prevent glitching
width = $window.width();
height = $window.height();
//calls resizing functions
resizeBg();
}
}, 100);
});
And it calls this function:
function resizeBg() {
var theWindow = $(window),
$bg = $("#bgVideo"),
aspectRatio = 1920 / 1080; //-- This is the aspect ratio (width / height) of the background image. if the video changes size.
//actually apply aspect ratio
if ((theWindow.width() / theWindow.height()) < aspectRatio) {
$bg.removeClass().addClass('bgheight');
} else {
$bg.removeClass().addClass('bgwidth');
}
}
In my CSS I have the following classes:
.bgwidth {
width: 100%;
}
.bgheight {
height: 100%;
}
And on your HTML, you want to have something like this:
<video id="bgVideo".....
OR
<img id="bgVideo"...
and I have the following CSS for my background ID:
#bgVideo {
position: fixed;
top: 0;
left: 0;
z-index: 1;
}
I hope this helps.

Fade transition

I am looking to create a photographic website which has a background image that changes every few seconds. I have the images changing by using:
<script type='text/javascript'>
var imageID=0;
function changeimage(every_seconds){
//change the image
if(!imageID){
document.getElementById("myimage").src="John%20Gallacher%20Photography/images/composite/Composite%201.jpg";
imageID++;
}
else{if(imageID==1){
document.getElementById("myimage").src="John%20Gallacher%20Photography/images/composite/Composite%202.jpg";
imageID++;
}
else{if(imageID==2){
document.getElementById("myimage").src="John%20Gallacher%20Photography/images/composite/Composite%203.jpg";
imageID=0;
}
}
}
//call same function again for x of seconds
setTimeout("changeimage("+every_seconds+")",((every_seconds)*5000));
}
</script>
</head>
<body onload='changeimage(2)'>
<div>
<img id="myimage" src="John%20Gallacher%20Photography/images/composite/Composite%201.jpg"/>
</div>
Is it possible to make the images fade in and then out again, and if so what would be the easiest way to do this. I have a basic understanding of html and css, my javascript is very basic. Any help would be great thanks
What is the support list? If you're not worried about older IE, then you can go with CSS Transitions for the transition and change the state with js
http://jsfiddle.net/Bushwazi/MYKFT/
#myimage {
-webkit-transition:all 1s linear 0s;
-moz-transition:all 1s linear 0s;
-o-transition:all 1s linear 0s;
transition:all 1s linear 0s;
-webkit-transform: translate3d(0,0,0); /* Fixes trails in Chrome */
}
And then just use js to change the opacity, then image, the opacity...
var imageID = 0,
ti = document.getElementById("myimage");;
var changeImage = function(t){
// change the opacity of the image to 0, let the css control the animation
ti.style.opacity = "0.0";
ti.style.filter = 'alpha(opacity=00)'; // IE fallback
// after 1 second (the animation), change the image
setTimeout(function(){
//change the image
switch(imageID){
case 0:
ti.src="https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcTM7c8EFwQ_PseqOEblAtm9qXali9kzvBKsmrGDECLYu1HJP3EO";
break;
case 1:
ti.src="https://si0.twimg.com/profile_images/2317326635/3kglmsqti3msjlb1nr60.png";
break;
case 2:
// return to the original image
ti.src="http://upload.wikimedia.org/wikipedia/en/c/cc/FPO_mark3.jpg";
break;
default:
// do nothing
}
if(imageID == 2){
imageID = 0;
} else {
imageID++;
}
// change the opacity of the image to 0, let the css control the animation
ti.style.opacity = "1.0";
ti.style.filter = 'alpha(opacity=100)'; // IE fallback
},1000);
} // close changeimage
//call same function again for x of seconds
window.setInterval(changeImage, 5000);
You may use jQuery. This has a number of transitions including fadeIn() and fadeOut().
Apply those functions to your images like this:
$("#image_id").fadeIn(); $("#image_id").fadeOut();
But firstly in your head you need to include jQuery. You can do that like this:
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
The #image_id is the id= of the <img> in your HTML Markup.
You can use a simple plugin for that, like jQuery Cycle. The code should look like this:
<head>
...
<script src="js/jquery-1.10.1.min.js"></script>
<script src="js/jquery.cycle.lite.js"></script>
...
</head>
...
<div class="fader">
<img src="image1.jpg" width="100px" height="100px">
<img src="image2.jpg" width="100px" height="100px">
<img src="image3.jpg" width="100px" height="100px">
</div>
...
<script>
$('.fader').cycle();
</script>
</body>
Where you shoud replace '/js' with the path to that files (that you should download).
I think a plugin is a lot of overhead for something that you can do with a little code.
I set up a quick example for you:
http://jsfiddle.net/Pevara/XcBTx/1/
A few remarks:
- I chose to work with background images, as I believe a background is what you are after, and you would not want the picture to show up on print. You could argue that for a photography website the background image is actual content, but changing the code to work with images in stead should be easy.
- Note that I use 2 div's for the images, so I can fade one in and one out. Perhaps it would be better to add the second one with javascript to avoid unnessacary markup. The first div I would keep, cause you want users without javascript to see at least one photo. You could consider setting it on the body, but again, I leave that up to you.
- It will be probably nessacary to preload the images, and wait for them to be loaded before you start the slideshow. Should not be to hard, plenty of information out there.
And the javascript (to be put in the $(window).load handler):
// the list of background images
var myImages = ['http://placekitten.com/900/400','http://placekitten.com/550/600'];
// the transition speed
var fadeSpeed = 500;
// the time between transitions
var playSpeed = 2000;
function fadeToNextImage() {
// -- prepare some vars
// the image wrappers
var $bg1 = $('#bg1');
var $bg2 = $('#bg2');
// the index of the next image in our array
var nextNr = parseInt($bg1.data('number')) + 1;
// if the index is larger then the number of images,
// we want the first image
if (nextNr > myImages.length - 1) { nextNr = 0; }
// the path to the next image
var nextImg = 'url(' + myImages[nextNr] + ')';
// set the image as background on bg2
$bg2.css('background-image', nextImg);
// fade out bg1
$bg1.fadeOut(fadeSpeed);
// fade in bg2
$bg2.fadeIn(fadeSpeed, function() {
// when the cross fade is ready
// set the image as background on bg1
$bg1.css('background-image', nextImg);
// update the number attribute
$bg1.data('number', nextNr);
// show bg1 (which now contains the same image as bg2)
$bg1.show();
// hide bg2 (to prepare it for the next slide)
$bg2.hide();
});
}
// start the slideshow
var interval = window.setInterval(function() {fadeToNextImage();}, playSpeed + fadeSpeed);
I put plenty of comments in there, but feel free to ask!

Scroll background image untill the end not further

I am working on a site and I don't want to repeat the background in the y direction.
I know how to do that.
But after the image I don't want background to becomes white or any other color.
I would like it to fix when it reaches that place or to let the background scroll slower then the rest of the site so I wont get to a white part.
Thanks a lot
I found this thread while I was looking for a solution to just this problem. I managed to write a short jQuery script adapting the hints given by Alex Morales.
With the following code, the background-image of the body scrolles down with the rest of the site until its bottom is reached. You can take a look at my homepage (http://blog.neonfoto.de) to see what it does.
$( window ).scroll( function(){
var ypos = $( window ).scrollTop(); //pixels the site is scrolled down
var visible = $( window ).height(); //visible pixels
const img_height = 1080; //replace with height of your image
var max_scroll = img_height - visible; //number of pixels of the image not visible at bottom
//change position of background-image as long as there is something not visible at the bottom
if ( max_scroll > ypos) {
$('body').css('background-position', "center -" + ypos + "px");
} else {
$('body').css('background-position', "center -" + max_scroll + "px");
}
});
This is actually the very first thing I did with JavaScript and JQuery, so any improvement would be great!
It's css3 so it's not super well supported, but I would look at the background-size property.
This is just off the top of my head but I think you will probably have to create a separate div containing the background image. If you place it in your markup before the main content and position the main content absolutely, it will sit behind the main content and at the top of the page. So:
CSS:
#background_div
{
background: url(images/some_image.png);
height: 600px;
width: 900px;
}
#main
{
height: 1200px;
width: 800px;
background: rgba(0, 0, 0, 0.25);
position: absolute;
top: 0;
}
HTML:
<div id="background_div"> </div>
Then what you do is you use javascript (I recommend jQuery) to detect the div's position on the screen.
jQuery:
This code grabbed from http://www.wduffy.co.uk/blog/keep-element-in-view-while-scrolling-using-jquery/
var $scrollingDiv = $("#background_div");
$(window).scroll(function(){
$scrollingDiv
.stop()
.animate({"marginTop": ($(window).scrollTop()) + "px"}, "slow" );
});