jquery slide up and down with animate wont stop sliding - javascript

i have a photo with some content on top of it (name, desc, price) the content is in a ul. in default state the ul only shows the name by setting the absolute position of the ul toward the bottom of the image and then hiding the overflow with a mask div. then when you mouseover the ul slides up showing the whole info as long as you stay on the image. when you mouseout it slides back down to its initial position just showing the title... that's how it should work. right now when you hover your mouse it slides up and down, up and down forever.
here is the html and styles
div.banner_product {
float: left; width: 236px; position: relative; overflow: visible;
}
div.banner_product ul {
width: 220px;
background-color: black;
font-size: 16px;
color: white;
list-style-type: none;
position: absolute; top: 230px;
margin: 8px;
filter: alpha(opacity=70); /* internet explorer */
-khtml-opacity: 0.7; /* khtml, old safari */
-moz-opacity: 0.7; /* mozilla, netscape */
opacity: 0.7; /* fx, safari, opera */
}
.mask {
position: absolute;
top: 0;
overflow: hidden;
height: 300px;
width: 235px;
}
/*html*/
<div class="banner_product" id="pi1"><img src="image1.jpg" alt="" border="0" height="306" width="235" /><div class="mask">
<ul id="bd1">
<li class="name-b">PRODUCT NAME</li>
<li class="text-b">DESCRIPTION</li>
<li class="price-b">PRICE</li>
</ul></div>
</div>
this is the script:
$('#pi1')
.bind('mouseover',enterImg)
.bind('mouseout',exitImg)
function enterImg(event){
$('#bd1').animate({"top": "4px"}, 2000);
event.stopPropagation();
}
function exitImg(event){
$('#bd1').animate({"top": "236px"}, 2000);
event.stopPropagation();
}

I think that every time #bd1 crosses your mouse pointer (which is presumably hovering over the image), it is calling the mouseout, then calling mouseover when it gets past.
To test this, activate the animation by pointing to the very bottom of the image, then moving the mouse out of the way immediately.
EDIT:
Hmmm... for me, if I make sure the banner doesn't cross the pointer, it helped, but of course that's not a fix.
One solution seems to be to use jQuery's hover() method instead of the specific mouse events:
$('#pi1').hover(
function (event){
$('#bd1').animate({"top": "4px"}, 500);
},
function (event){
$('#bd1').animate({"top": "236px"}, 500);
});
Works in webkit anyway. Haven't test IE.

var state = true;
$('#pi1').hover(function(){
if(state){
$('#bd1').slideDown('slow',function(){
state = false;
});
}
},function(){
if(!state){
$('#bd1').slideUp('slow',function(){
state = true;
});
}
})
stops redandent up down movement using jquery slideUp() and slideDown() together with hover events...
this would actually work anywhere mouseover and mouseout events are used...

Related

preventDefault() on first touch but still allow scrolling/touchmove

I have a few elements on my site in which there is content that only appears when you hover on the element. A perfect example would be the Instagram feed grid. I'm pulling in the last 8 images from an Instagram account using their API and displaying them in a grid with flexbox. When you :hover over one of the images with a mouse, a semi-transparent black overlay fades in, containing the caption of the Instagram post.
On desktop you are able to click anywhere on the image/hovered caption overlay as they are both wrapped in an <a> element and doing so takes you to the post on Instagram's website. This works perfectly on desktop, but on touch devices does not.
Because you can't :hover on touch devices, I decided to implement some javascript on the touchstart event that uses e.preventDefault() to stop the link from being clicked when you tap the Instagram image and instead adds the CSS opacity: 1 and visibility: visible to the overlay element (which is what happens when you :hover on the element). Because the overlay element is then "on top" of the image when it's made visible, the link is clickable because the touchstart event is only listened for on the image.
This all works great and means that I can tap once on the image which fades in the overlay and doesn't take me to the image on Instagram, and I can then click for the second time on the overlay, taking me to the image on Instagram.
The problem
Because I am using e.preventDefault() in the touchstart event, if you touch the image and then start dragging your finger to scroll, the page doesn't scroll at all which results in a bad user experience.
So...
How can I only preventDefault() on a single touch event, or how can I prevent the link from being clicked on the first touch of the element but not on the second whilst still allowing the user to scroll/drag the page?
Slightly simplified version of my code
function toggleHoveredStateOn(e) {
e.preventDefault();
let hoverElem = this.querySelector('.js-touch-hover');
// remove all 'visible' classes from other "hovered" items first
document.querySelectorAll('.js-touch-trigger').forEach(touchTrigger => {
let hoverElem = touchTrigger.querySelector('.js-touch-hover');
Object.assign(hoverElem.style, {
visibility: 'hidden',
opacity: '0',
pointerEvents: 'none'
});
});
// add visible to the touched element's hover element
Object.assign(hoverElem.style, {
visibility: 'visible',
opacity: '1',
pointerEvents: 'all'
});
}
function initMobileTouchFunctionality() {
let touchTriggers = [...document.querySelectorAll('.js-touch-trigger')];
touchTriggers.forEach(touchTrigger => {
touchTrigger.addEventListener('touchstart', toggleHoveredStateOn, false);
touchTrigger.querySelector('.js-touch-hover').addEventListener('touchstart', function(e) {
e.stopPropagation();
}, false);
});
}
initMobileTouchFunctionality();
.flex-grid__item {
position: relative;
height: 263px;
border: 1px solid #FFF;
&:hover {
.flex-grid--social__hover {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.flex-grid--social__hover {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
background-color: rgba(0, 0, 0, 0.8);
padding: 20px;
transition: opacity 0.2s ease-in-out;
opacity: 0;
visibility: hidden;
overflow: hidden;
pointer-events: none;
cursor: pointer;
}
<div class="flex-grid__item js-touch-trigger">
<a href="<?php // link to instagram. php code gets this ?>">
<img class="" src="<?php // instagram image. php code gets this ?>"/>
<div class="flex-grid--social__hover js-touch-hover">
<p><?php // instagram caption. php gets this ?></p>
</div>
</a>
</div>
You can decide whether to e.preventDefault or not using the e.target to see if the user tapped the image or the overlay.
You can read more at https://developer.mozilla.org/en-US/docs/Web/API/Event/target

How to make an element reset its position after mouseout event in javascript

trying to make a button like this: https://gyazo.com/9afbd559c15bb707a2d1b24ac790cf7a. The problem with the code right now is that it works as it is supposed to on the first time; but after that, instead of going from left to right as intented, it goes from right to left to right.
HTML
<div class="btn-slide block relative mx-auto" style="overflow: hidden; width: 12rem;">
<span class="z-10">View Pricing</span>
<span class="slide-bg block absolute transition" style="background-color: rgba(0,0,0,.1); z-index: -1; top: 0; left:-10rem; width: 10rem; height: 3rem;"></span>
</div>
Javascript
const btns = document.querySelectorAll(".btn-slide");
const slide = document.getElementsByClassName('slide-bg');
btns.forEach(function(btn) {
btn.addEventListener('mouseout', function () {
slide[0].style.transform = 'translateX(230%)';
slide[0].style.transform = 'none';
})
btn.addEventListener('mouseover', function() {
slide[0].style.transform = 'translateX(80%)';
}, true)
})
Unless you have to compute a value in JavaScript (like the height of an element).
Use CSS classes as modifiers (is-hidden, is-folded, is-collapsed, ...).
Using JavaScript, only add/remove/toggle the class
yourElement.addEventListener(
"mouseenter",
function (event)
{
yourElement.classList.remove("is-collapsed");
}
);
yourElement.addEventListener(
"mouseleave",
function (event)
{
yourElement.classList.add("is-collapsed");
}
);
is-collapsed is only an exemple, name it according to your class naming standard.
You're probably going to need a bit more code than what you're showing, as you have two mutually exclusive CSS things you want to do: transition that background across the "button" on mouseenter/mouseout, which is animated, and then reset the background to its start position, which should absolutely not be animated. So you need to not just toggle the background, you also need to toggle whether or not to animation those changes.
function setupAnimation(container) {
const fg = container.querySelector('.label');
const bg = container.querySelector('.slide-bg');
const stop = evt => evt.stopPropagation();
// step one: make label text inert. This is critical.
fg.addEventListener('mouseenter', stop);
fg.addEventListener('mouseout', stop);
// mouse enter: start the slide in animation
container.addEventListener('mouseenter', evt => {
bg.classList.add('animate');
bg.classList.add('slide-in');
});
// mouse out: start the slide-out animation
container.addEventListener('mouseout', evt => {
bg.classList.remove('slide-in');
bg.classList.add('slide-out');
});
// when the slide-out transition is done,
// reset the CSS with animations _turned off_
bg.addEventListener('transitionend', evt => {
if (bg.classList.contains('slide-out')) {
bg.classList.remove('animate');
bg.classList.remove('slide-out');
}
});
}
setupAnimation(document.querySelector('.slide'));
.slide {
position: relative;
overflow: hidden;
width: 12rem;
height: 1.25rem;
cursor: pointer;
border: 1px solid black;
text-align: center;
}
.slide span {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.slide-bg {
background-color: rgba(0,0,0,.1);
transform: translate(-100%, 0);
transition: none;
z-index: 0;
}
.slide-bg.animate {
transition: transform 0.5s ease-in-out;
}
.slide-bg.slide-in {
transform: translate(0%, 0);
}
.slide-bg.slide-out {
transform: translate(100%, 0);
}
<div class="slide">
<span class="label">View Pricing</span>
<span class="slide-bg"></span>
</div>
And thanks to browsers being finicky with rapid succession mouseenter/mouseout events, depending on how fast you move the cursor this may not even be enough: you might very well still need a "step" tracker so that your JS knows which part of your total animation is currently active, and not trigger the mouseout code if, by the time the slide-in transition ends, the cursor is in fact (still) over the top container (or, again).
I advice you use the .on event listener
$('').on("mouseentre","elem",function(){$('').toggleclass('.classname')})
$('').on("mouseleave","elem",function(){$('').toggleclass('.classname')})
Then you can toggle css classes to your element in the function
toggle class adds the css of a class to your jquery selection, you can do it multiple times and have keyframes for animation in the css class
Keyframes are great way to implement animation and are supported on every browers

on click function to reveal hover overlay - appears on click but won't disappear on 2nd click

I have a portfolio grid of images and when a user hovers or taps on a mobile a transparent overlay with some text and a button appears
I am using the on click function
It works fine on my touch screen laptop but not on my iOS phone or tablet
The overlay appears on first tap, but when I tap again it does not disappear unless I tap another grid image.
I would like it to disappear on 2nd tap
I have tried various ways of making this work, and the closest I have got it for it to disappear when another grid image is tapped
Here is my code:
HTML
<div class="col-xs-12 col-sm-7"><div class="image-wrap">
<div onclick="on()">
<img src="assets/images/pic.jpg">
<div class="overlay blue">
<h3>Portfolio item 1</h3>
<hr>
<p><strong>Coming Soon</strong><br> some overlay text here</p>
<br>
View Website
</div>
</div>
</div>
</div>
JS
function on() {
document.getElementById("overlay").style.display = "block";
}
function off() {
document.getElementById("overlay").style.display = "none";
}
CSS
.image-wrap {
display: inline-block;
position: relative;
}
.overlay {
position: absolute;
top:0;
left: 0;
width: 100%;
height: 100%;
color:white;
opacity: 0;
transition:opacity .5s ease-out;
text-align: center;
hr {
border: 1px solid #fff;
width: 10%;
}
}
.image-wrap:hover .overlay {
opacity: 1;
}
.red {
background: rgba(102,67,154,0.7);
}
.blue {
background: rgba(23,56,179,0.7);
}
.purple1 {
background: rgba(140,23,179,0.7);
}
.purple2 {
background: rgba(71,13,142,0.7);
}
}
I initially tried this with just CSS which gave me the desired result on all devices apart from iOS!
So I have decided to use the on click function to be more sure it works on all devices. I added the on click function to my existing code which I wrote to be used with CSS, but as I am rather new to JS I am wondering if I have it in the wrong place (the on-click)? I have tried lots of variations but this is the best I can get it to work
Any ideas of suggestions on how I can make the overlay disappear on the 2nd click would be great!
js fiddle
https://jsfiddle.net/49h450g9/14/
Please note: This works fine on touch-screen laptops, just not mobiles!
Thanks!
Your functions on and off on jsfiddle example are not working at all. What happening is your hover effect on normal screen which as the behavior of mobile work like focus on mobile device.
Moreover, from your description here I believe that you have more than one portfolio on your project. So you have several element with the id overlay and multiple use of same id is not validate for html and also will cause JavaScript error.
To let your project work properly follow my list below:
Make sure you have jQuery added on your project (generally before </body>)
Now let us thinks of these portfolio item below
<div class="portfolio">
<img src="images/portfolio-1.jpg" alt="...">
<div class="overlay">Link</div>
</div>
<div class="portfolio">
<img src="images/portfolio-2.jpg" alt="...">
<div class="overlay">Link</div>
</div>
<div class="portfolio">
<img src="images/portfolio-3.jpg" alt="...">
<div class="overlay">Link</div>
</div>
Then give the normal hover css styles inside media query like this. So that it never effect your js styles (I decide medias less than 992px as mobile device):
.portfolio{
background-color: #f1f1f1;
position: relative;
}
.portfolio .overlay{
background-color: rgba(0, 0, 0, 0.7);
display: block;
position: absolute;
top: 0;
left: 0;
opacity: 0;
transition: all 0.3s ease;
width: 100%;
height: 100%;
}
#media all and (min-width:992px){
.portfolio:hover .overlay{
opacity: 1;
}
}
Now with jQuery you can use event while user click any of the .portfolio item and toggle a class on it by which we will add further css to it:
$(document).ready(function(){
'use strict';
$(.portfolio).on('click', function(){
$(this).siblings('.portfolio').removeClass('hovered');
$(this).toggleClass('hovered');
});
});
Now it will add hovered class on 1st click and remove the hovered class on 2nd click. Also it will remove .hovered from other portfolio items. Now add the same css to it as the hover effect:
.portfolio.hovered .overlay{
opacity: 1;
}
Try this:
$("*").on("click, touchend", function(e) { $(this).focus(); });
or to achieve the opposite;
$("*").on("click touchend", function(e) { $(this).hover(); });
However the hover event doesn't work well on ios or other mobiles.
Another suggestion is to try replace any css using
:hover with :active.

React.js show part of component on hover issue

I have a problem with showing an overlay over my component. Below is the code.
<div className="content">
<div className="main" onMouseEnter={this.mouseOver} onMouseLeave={this.mouseLeaves}>
...
</div>
<div className="overlay" style={this.getOverlayStyle()} ref="overlay">
</div>
</div>
This is the style method:
getOverlayStyle: function() {
return {
display: 'none',
position: 'absolute',
top: '0',
bottom: '0',
left: '0',
right: '0',
zIndex: '100'
};
}
And these are the mouse event handlers:
mouseOver: function() {
this.refs.overlay.style.display = 'block';
},
mouseLeaves: function() {
this.refs.overlay.style.display = 'none';
},
Okay, so, when I hover over the content part, the overlay becomes visible, but it's flickering. When I stop moving the mouse above the content, the overlay is displaying nicely. When I move the mouse again, it flickers again, it's barely watchable, very annoying.
When I try making the overlay visible in the console (just your regular document.getElementsByClassName('overlay')[0].style.display = 'block', it works normally and doesn't flicker. I'm guessing this problem is due to my not yet great React knowledge.
Any ideas why is this happening?
Ps, I tried using a pure CSS solution: selector1 + selector2 { display: block; } and it behaved the same as above.
EDIT, I tried setting the visibility through state (change state on mouse enter and mouse leave), following a recommendation in the comments, but it still flickers when the mouse is moving.
I'm pretty sure you need to move the mouseenter and mouseleave to the .content div, not the .main div
what I expect is happening is this:
you enter main, the overlay is displayed which means the mouse leaves main and enters overlay. because it left main, the overlay is then hidden, and when the overlay is hidden, the mouse reenters main causing the cycle to rinse and repeat
although really this can be accomplished with css selectors. is there a reason you want to do this in react?
There is a pure css solution to this (codepen)
.content {
position: relative;
}
.main {
background-color: #0d0;
min-height: 30px;
min-width: 30px;
}
.overlay {
display: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
zIndex: 100;
background-color: #d00;
}
.content:hover .overlay {
display: block;
}

grow/shrink image gallery with jquery WITHOUT affecting the layout

I got an image gallery organized as an <ul>. all images are in <li> elements and when I move my mouse over one of those pictures, it should grow to give the user a visual feedback. thing is, when I just change the size of the image using animate(), the other pictures will be pushed to the side as the resized image uses more space.
therefore I went with cloning the image element, float it right over the original image and then calling animate. this comes with the problem that onMouseOut() is called as soon as the cloned images pops up. so I need a nested hover() function and this is where things got complicated.
I got two errors and I can't find out whats causing them. the first one is, that animate() won't let the cloned image grow beyond the right border of its original, the second is, that I get weird grow/shrink behavior, when moving my mouse quickly over the gallery.
html:
<ul id="gallery1" class="gallery_container">
<li class="frame">
<img src="pic1.jpg" class="picture" /></li><li class="frame">
<img src="pic2.jpg" class="picture" /></li><li class="frame">
<img src="pic3.jpg" class="picture" /></li>
</ul>
css:
.picture
{
height: 200px;
border: 0px;
margin: 0px;
padding: 0px;
}
.frame
{
display: inline-block;
position: relative;
margin: 0px;
margin-right:8px;
padding: 0px;
}
.frame a
{
padding: 0px;
margin: 0px;
}
.gallery_container
{
height: 200px;
width: 150%;
position: relative;
top: 4px;
padding: 0px;
margin: 0px;
}
and finally the code that is giving me those headaches:
$(document).ready(function()
{
var zooming = false;
var zoom = 4;
var speed_zoom = 100;
$('.gallery_container li a').hover(function(element)
{
// disable zooming to prevent unwanted behavior
if(zooming) return;
zooming = true;
$(this).after( $(this).clone(false) );
$(this).next().attr('id', 'focus_frame');
},
function(element) // when the new element pops up, onmouseout is triggered, since the focus_frame is in front of the image
{
$(this).next().hover(function(element)
{
// we need to re-position the element in the dom-tree, since it needs to grow out of a container with overflow: hidden
$('#focus_frame img').animate({'left' : zoom * -1, 'top' : zoom * -1, 'height' : 200+(zoom*2), 'width' : $('#focus_frame img').outerWidth() + (zoom*2)}, speed_zoom);
},
function(element)
{
$(this).remove();
zooming = false;
});
});
});
var $doc=$(document.body)
$doc.on({
"mouseenter" : function (e) {
$doc.find("> .gallery_clone").remove();
var $i=$(this).parent();
$i.pos = $i.offset();
$i.clone()
.addClass("gallery_clone "+$i.parent().parent().attr("class"))
.css({
top:(Math.round($i.pos.top)-3)+"px"
,left:(Math.round($i.pos.left)-3)+"px"
,width:$i.width()
}).appendTo($doc);
}
},
" ul > li > img"
).on ({
"mouseleave" : function (e) {
$(this).remove();
},"> .gallery_clone");
in css .gallery_clone is position:absolute
then i animate .gallery_clone:hover through css but you can do it in the jquery as well i guess, adding a mouseenter event on .gallery_clone
edit : i've literally copy/pasted from my script so you'll have to adapt this code to your html
nb: give css anim a go, it's worth it even if older ie will not animate; (i also made lightbox effect almost pure css for that same gallery - will publish later, not ready for plugin release just now sorry)
nb2: that part "+$i.parent().parent().attr("class") is because in the cms they can chose gallery background color so adding that class forward the background color & other gallery style to the clone (ie you should not need it)

Categories

Resources