I have this pair of divs that should resize on click, it works fine except that every once in a while the div kind of flashes before resizing. I done a lot of research and everybody agrees it should fix with "-webkit-backface-visibility: hidden;" but I've tried it and it doesn't change anything. It fails both in chrome and firefox. I mean sometimes it works fine and other times it just flickers really horribly.
Any ideas on what is wrong?
Is it in the jquery? in the css?
Any help is appreciated.
My JS:
(function($){
setup = function setup(){
var windowWidth;
$('.day').each(function(){
var $this = $(this),
links = $('.links', $this),
images = $('.images', $this),
largeWidth,
smallWidth,
linksWidth,
imagesWidth;
images.click(function(){
windowWidth = $(window).width();
linksWidth = $('.links', $this).width();
imagesWidth = $('.images', $this).width();
largeWidth = Math.max(linksWidth,imagesWidth);
smallWidth = Math.min(linksWidth,imagesWidth);
if (windowWidth < 850){
images.width(largeWidth);
links.width(smallWidth);
}
})
links.click(function(){
windowWidth = $(window).width();
linksWidth = $('.links', $this).width();
imagesWidth = $('.images', $this).width();
largeWidth = Math.max(linksWidth,imagesWidth);
smallWidth = Math.min(linksWidth,imagesWidth);
if (windowWidth < 850){
links.width(largeWidth);
images.width(smallWidth);
}
})
});
}
$(document).ready(setup);
}(jQuery))
And the CSS:
.column {
width: 50%;
float: left;
overflow: hidden;
-webkit-transition: width 0.3s linear;
-moz-transition: width 0.3s linear;
-o-transition: width 0.3s linear;
transition: width 0.3s linear;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-webkit-perspective: 1000;
-webkit-transform:translate3d(0,0,0);
-webkit-transform: translateZ(0);
}
Here is the jsfiddle: http://jsfiddle.net/cKvYq/2/
Thanks a lot!
The reason why their widths start animating less and less is because you set the width to be changed to based on the current width, so when one is clicked while it is transitioning those values are thrown off. To remedy this you could attempt to calculate the large and small width based on window size initially and on window resize, but what I recommend and the method I used is to disable the clicks using .on and .off with a setInterval the duration of the transition.
The other problem of the right div wrapping to the next line is caused by the width temporarily taking up more than the window width. I assume it's because sometimes the divs are just slightly animated at different times, thus one expands before the other contracts throwing it to the next line. I remedied this problem by lessening the width of both of them by a couple pixels and using a negative margin, increased padding trick to have the right div called images to take up that space that I removed. This part could probably be done in a cleaner way than I did it, such as including that small decrease in the initial calculation somewhere or perhaps in the CSS, but for this demo I didn't figure it was too big of an issue, it functions well and was made to show you the problem
Here is the Updated jsFiddle
Here is the changed jQuery
(function ($) {
setup = function setup() {
var windowWidth;
$('.day').each(function () {
var $this = $(this),
links = $('.links', $this),
images = $('.images', $this),
largeWidth,
smallWidth,
linksWidth,
imagesWidth,
count = 0;
var imagesClick = function () {
images.off('click');
links.off('click');
windowWidth = $(window).width();
if(count === 0)
{
linksWidth = $('.links', $this).width() - 2;
imagesWidth = $('.images', $this).width() - 2;
images.css({'margin-right': "-=4", 'padding-right': "+=4"});
count++;
} else{
linksWidth = $('.links', $this).width();
imagesWidth = $('.images', $this).width();
}
largeWidth = Math.max(linksWidth, imagesWidth);
smallWidth = Math.min(linksWidth, imagesWidth);
if (windowWidth < 850) {
images.width(largeWidth);
links.width(smallWidth);
setTimeout(function () {
images.on('click', imagesClick);
links.on('click', linksClick);
}, 300);
}
}
images.on('click', imagesClick);
var linksClick = function () {
images.off('click');
links.off('click');
windowWidth = $(window).width();
if(count === 0)
{
linksWidth = $('.links', $this).width() - 2;
imagesWidth = $('.images', $this).width() - 2;
images.css({'margin-right': "-=4", 'padding-right': "+=4"});
count++;
} else{
linksWidth = $('.links', $this).width();
imagesWidth = $('.images', $this).width();
}
largeWidth = Math.max(linksWidth, imagesWidth);
smallWidth = Math.min(linksWidth, imagesWidth);
if (windowWidth < 850) {
links.width(largeWidth);
images.width(smallWidth);
setTimeout(function () {
images.on('click', imagesClick);
links.on('click', linksClick);
}, 300);
}
}
links.on('click', linksClick);
});
}
$(document).ready(setup);
}(jQuery))
Related
I have a custom cursor that I implemented using some JS found on here. It work's perfectly - BUT, I need to turn it off on touch screens, otherwise it just sits on the screen as a big yellow dot.
Unfortunately, apart from the inline styles, I don't understand the JS enough to edit it to achieve this.
This is the JS
$("body").append('<div class="cursor"></div>');
$("html").append('<style>html, body, .msty_notcur {cursor:none !important;}.cursor {z-index:10000000000000; mix-blend-mode: difference; position: fixed;background-color:#FDFF07; width:25px;height:25px;border-radius:100%;transform:translate(-50%,-50%);top:0px;left:0px;pointer-events:none; -webkit-transition: width 200ms, height 300ms; -webkit-transition: height 200ms, width:300ms; } .overlink {width:45px;height:45px; -webkit-transition: width 300ms, height 300ms; -webkit-transition: height 200ms, width:200ms;} .overtext {background-color:rgba(100,100,255,0.25) !important;border: 1px solid rgba(0,0,100,0.25) !important;}</style>');
var scrollY = 0, scrollX = 0;
$(document).mousemove(function(e){
$(".cursor").css("top",e.pageY - scrollY + "px").css("left",e.pageX - scrollX + "px");
});
$(document).scroll(function(e){
scrollY = $(window).scrollTop();
scrollX = $(window).scrollLeft();
});
setInterval(function(){scroll = $(window).scrollTop();}, 1000);
$("*").hover(function(e){
var index = -1;
try {
index = $(this).attr("class").toLowerCase().indexOf("button");
if (index == -1) {
index = $(this).attr("class").toLowerCase().indexOf("link");
}
}
catch(e) {
index = -1;
}
if($(this).css("cursor") == "pointer" || $(this).get(0).tagName == "A" || $(this).get(0).tagName == "BUTTON" || $(this).hasClass("msty_cur") || index > -1) {
$(this).addClass("msty_cur");
$(this).css("cursor","none");
$(".cursor").addClass("overlink");
}
if($(this).css("cursor") != "none") {
$(this).addClass("msty_notcur")
}
}, function(e){
$(this).css("cursor","none");
$(".cursor").removeClass("overlink");
});
And the website where it is implemented is here
The difficulty I have with using just CSS is applying the mix-blend-mode to the cursor
Using JavaScript, your best bet is to try and detect the screen size. It looks like 768 is a safe bet for max-width.
You'd want to add both a conditional statement (for when the page loads) onresize for the document. I'd also wrap the cursor creation into a function for re-usability/convenience.
customCursor = () => {
$("body").append('<div class="cursor"></div>');
$("html").append('<style>.cursor {z-index:10000000000000; mix-blend-mode: difference; position: fixed;background-color:#FDFF07; width:25px;height:25px;border-radius:100%;transform:translate(-50%,-50%);top:0px;left:0px;pointer-events:none; -webkit-transition: width 200ms, height 300ms; -webkit-transition: height 200ms, width:300ms; } .overlink {width:45px;height:45px; -webkit-transition: width 300ms, height 300ms; -webkit-transition: height 200ms, width:200ms;} .overtext {background-color:rgba(100,100,255,0.25) !important;border: 1px solid rgba(0,0,100,0.25) !important;}</style>');
var scrollY = 0,
scrollX = 0;
$(document).mousemove(function(e) {
$(".cursor").css("top", e.pageY - scrollY + "px").css("left", e.pageX - scrollX + "px");
});
$(document).scroll(function(e) {
scrollY = $(window).scrollTop();
scrollX = $(window).scrollLeft();
});
setInterval(function() {
scroll = $(window).scrollTop();
}, 1000);
$("*").hover(function(e) {
var index = -1;
try {
index = $(this).attr("class").toLowerCase().indexOf("button");
if (index == -1) {
index = $(this).attr("class").toLowerCase().indexOf("link");
}
} catch (e) {
index = -1;
}
if ($(this).css("cursor") == "pointer" || $(this).get(0).tagName == "A" || $(this).get(0).tagName == "BUTTON" || $(this).hasClass("msty_cur") || index > -1) {
$(this).addClass("msty_cur");
$(this).css("cursor", "none");
$(".cursor").addClass("overlink");
}
if ($(this).css("cursor") != "none") {
$(this).addClass("msty_notcur")
}
}, function(e) {
$(this).css("cursor", "none");
$(".cursor").removeClass("overlink");
});
}
if (window.innerWidth <= 768) {
document.getElementsByTagName('BODY')[0].style.cursor = 'default'
} else {
customCursor()
}
$(window).resize(function() {
if (window.innerWidth <= 768) {
var cursor = $(".cursor")
cursor.remove()
$('body').css({
cursor: "default",
})
} else {
$('body').css({
cursor: "none",
})
customCursor()
}
});
Honestly, your best bet is to utilize CSS more as opposed to using jQuery to append/manipulate things but that's up to you.
I am trying to create an animation which takes a image that is anywhere on a page and moves it to the middle while resizing it to full width of the browser window. My solution works, but has some stutters/jumps in it, which I can't really explain. Is there anyone who has tried creating a similar animation already? EDIT: I noticed that the stutter problem only seems to appear in macOS Safari. In other browsers this animation appears to run perfectly smooth.
Here is my js code:
function getWindowWidth() {
return document.documentElement.clientWidth
}
function getWindowHeight() {
return document.documentElement.clientHeight;
}
//at the moment this is hacky and only supports one image to be enlarged
let en_img_left = null;
let en_img_top = null;
function enlargeImage(img) {
let boundingClientRect = img.getBoundingClientRect();
img.style.position = "fixed";
en_img_top = boundingClientRect.y + "px";
img.style.top = en_img_top;
en_img_left = boundingClientRect.x + "px";
img.style.left = en_img_left;
img.style.width = boundingClientRect.width + "px";
img.style.zIndex = "1000";
setTimeout(function() {
img.style.transition = "1s ease-in-out";
setTimeout(function() {
let scaleFactor = getWindowWidth() / boundingClientRect.width;
img.style.transform = "scale(" + scaleFactor + ")";
img.style.left = getWindowWidth() / 2 - (boundingClientRect.width / 2) + "px";
img.style.top = getWindowHeight() / 2 - boundingClientRect.height / 2 + "px";
}, 1);
}, 1);
return img;
}
function delargeImage(img) { //sorry for the function name
img.style.transition = "1s ease-in-out";
setTimeout(function() {
img.style.transform = "scale(1)";
img.style.left = en_img_left;
img.style.top = en_img_top;
}, 1);
return img;
}
example HTML+CSS code, but it can be any image with an ID on a website:
HTML:
<div class="container">
<img id="example" style="width: 100%" src="https://images.pexels.com/photos/1361815/pexels-photo-1361815.jpeg?cs=srgb&dl=blur-bokeh-close-up-1361815.jpg&fm=jpg">
</div>
CSS:
.container {
width: 200px;
}
I also made a jsfiddle displaying the stutter problem quite nicely:
https://jsfiddle.net/robske_110/vhz5Ln4o/11/
You are not using CSS animations or transitions!
The animation itself is executed through JavaScript in your example. Instead of computing every single step of an animation in JS and setting a new CSS property on each iteration, you should setup a CSS animation with the desired start- and end-states or define the properties, that should be transitioned. This way the animation should look smooth while transitioning.
Your example using a CSS transition (without any JS code):
.container {
width: 200px;
transition: width ease-in 1s;
}
.container:hover {
width: 80vw;
}
.container img {
width: 100%;
}
<div class="container">
<img id="example" src="https://images.pexels.com/photos/1361815/pexels-photo-1361815.jpeg?cs=srgb&dl=blur-bokeh-close-up-1361815.jpg&fm=jpg">
</div>
I'm trying to change the opacity of a DIV based on how much is visible (height-wise) in the window. For example if 50% of the DIV is visible in the window then the opacity should be .5
Here is what I've got, I know it's amateur and not optimal code. It's my math that is the problem. When the DIV is roughly 50% on the screen, with my calculations it comes out to around 80%
$(window).scroll(function () {
var block = $('.block')
var blockHeight = block.outerHeight();
var bottom_of_block = block.offset().top + blockHeight;
var blockOpacity = 0;
if (bottom_of_block < ($(window).height() + $(window).scrollTop())) {
// Sets opacity to 1 if div is completely on screen
blockOpacity = 1;
} else {
// This is the math that I cant figure out completely
blockOpacity = ($(window).height() + $(window).scrollTop()) / (bottom_of_block);
}
block.css('opacity', blockOpacity);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="height: 500px"></div>
<div class="block" style="background: blue;height: 220px;width: 220px;"></div>
I think you need to calculate blockOpacity like this:
blockOpacity = ($(window).height() + $(window).scrollTop() - block.offset().top) / blockHeight;
I'm working on a progress bar animation which needs to animate from 0 to whatever percentage when the progress bar becomes visible within browser's viewport. Animation should always happen when element is scrolled into the view which means that scrolling it outside has to reset animation to start.
Here's my non-working code:
var $animation_elements = $('.progressAnimation');
var $window = $(window);
function check_if_in_view() {
var window_height = $window.height();
var window_top_position = $window.scrollTop();
var window_bottom_position = (window_top_position + window_height);
$.each($animation_elements, function() {
var $element = $(this);
var element_height = $element.outerHeight();
var element_top_position = $element.offset().top;
var element_bottom_position = (element_top_position + element_height);
//check to see if this current container is within viewport
if ((element_bottom_position >= window_top_position) &&
(element_top_position <= window_bottom_position)) {
$element.animate({
"width": (600 * $($element).data("percent")) / 100
}, 3000);
} else {
$element.animate({
"width": "0"
}, 1000)
}
});
}
$window.on('scroll resize', check_if_in_view);
$window.trigger('scroll');
body{
height:4000px;
margin-top:800px;
}
.myContainer{
width:1000px;
margin:50px auto;
}
.myContainer .progressBackground{
width:600px;
height:40px;
margin:0 auto 40px;
background-color:#eaeaea;
}
.myContainer .progressAnimation{
width:0;
height:100%;
background-color:#00f36d;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="myContainer">
<div class="progressBackground">
<div class="progressAnimation" data-percent="80">
</div>
</div>
<div class="progressBackground">
<div class="progressAnimation" data-percent="60">
</div>
</div>
</div>
Note: run code snippet in fullscreen.
Animating using Javascript within scroll/resize event isn't really wise. Without throttling the event it is wiser to do something very simple.
I haven't delved into your code and why it doesn't work, but I've devised an example based on your code, but I'm doing animation using CSS (offloading animation off of browser process), and simply changing elements' state when it's different from what it should be. This means that I'm shrinking progress bar to 0 only when element goes off screen (and not every single time a scroll/resize event fires which is what you're doing) and animating progress bar when it comes on screen only when it's been off screen.
This is the code:
var $animation_elements = $('.progressAnimation');
$(window).on('scroll resize', function(){
var viewportHeight = document.documentElement.clientHeight;
$animation_elements.each(function() {
var $el = $(this);
var position = this.getBoundingClientRect();
if (position.top > viewportHeight || position.bottom < 0) {
this.inView && $el.css({ width: 0 });
this.inView = false;
} else {
!this.inView && $el.css({ width: 6 * $el.data("percent") });
this.inView = true;
}
});
});
As you can see I've also used as much vanilla Javascript as possible to make event handler as fast as possible.
And here is a working JSFiddle.
I have implemented a parallax scrolling effect based on a tutorial I found. The effect works great. However, when I specify the background images, I am unable to control the y (vertical) axis. This is causing problems because I'm trying to set locations on multiple layered images.
Any thoughts on what's causing the problem?
Here is one external script:
$(document).ready(function(){
$('#nav').localScroll(800);
//.parallax(xPosition, speedFactor, outerHeight) options:
//xPosition - Horizontal position of the element
//inertia - speed to move relative to vertical scroll. Example: 0.1 is one tenth the speed of scrolling, 2 is twice the speed of scrolling
//outerHeight (true/false) - Whether or not jQuery should use it's outerHeight option to determine when a section is in the viewport
$('#mainimagewrapper').parallax("50%", 1.3);
$('#secondaryimagewrapper').parallax("50%", 0.5);
$('.image2').parallax("50%", -0.1);
$('#aboutwrapper').parallax("50%", 1.7);
$('.image4').parallax("50%", 1.5);
})
This is another external script:
(function( $ ){
var $window = $(window);
var windowHeight = $window.height();
$window.resize(function () {
windowHeight = $window.height();
});
$.fn.parallax = function(xpos, speedFactor, outerHeight) {
var $this = $(this);
var getHeight;
var firstTop;
var paddingTop = 0;
//get the starting position of each element to have parallax applied to it
$this.each(function(){
firstTop = $this.offset().top;
});
if (outerHeight) {
getHeight = function(jqo) {
return jqo.outerHeight(true);
};
} else {
getHeight = function(jqo) {
return jqo.height();
};
}
// setup defaults if arguments aren't specified
if (arguments.length < 1 || xpos === null) xpos = "50%";
if (arguments.length < 2 || speedFactor === null) speedFactor = 0.1;
if (arguments.length < 3 || outerHeight === null) outerHeight = true;
// function to be called whenever the window is scrolled or resized
function update(){
var pos = $window.scrollTop();
$this.each(function(){
var $element = $(this);
var top = $element.offset().top;
var height = getHeight($element);
// Check if totally above or totally below viewport
if (top + height < pos || top > pos + windowHeight) {
return;
}
$this.css('backgroundPosition', xpos + " " + Math.round((firstTop - pos) * speedFactor) + "px");
});
}
$window.bind('scroll', update).resize(update);
update();
};
})(jQuery);
Here is the CSS for one section:
#aboutwrapper {
background-image: url(../images/polaroid.png);
background-position: 50% 0;
background-repeat: no-repeat;
background-attachment: fixed;
color: white;
height: 500px;
width: 100%;
margin: 0 auto;
padding: 0;
}
#aboutwrapper .image4 {
background: url(../images/polaroid2.png) 50% 0 no-repeat fixed;
height: 500px;
width: 100%;
margin: 0 auto;
padding: 0;
}
.image3{
margin: 0 auto;
min-width: 970px;
overflow: auto;
width: 970px;
}
Both of these are being called to achieve the parallax scrolling. I really just want to more specifically control the background image locations. I've tried messing with the CSS background position and I've messed with the first javascript snippet as well. No luck.
just a quick shot, have you tried actually placing the images, either in a div or just using the img src tag to actually move the element rather than manipulating the y axis of a background image?