add :hover state to different elem on hover of other elem - javascript

So, basically I want to detect when a user hovers over one element (different div element, not parent nor sibling) and when that hover occurs, add :hover to my other div element. My :hover of other div element state is also below via css. Below is one attempt at achieving this by manually adding that css in jQuery chaining method, but did not work at all.
$('.song-thumb .hover-play').hover(function(){
$('section.suggestedAlbums img').css('transform', 'scale(1.2)');
// },function(){
// $('.flyout').hide();
});
section.suggestedAlbums img:hover {
transform: scale(1.2); z-index: 3; cursor: pointer;
}

I could not get the :hover css state to work but here's what I could do
Check out the demo or look at the snippet below.
Hope this helps.
$('.song-thumb .hover-play').on('mouseenter', function(e) {
var elem = $('section.suggestedAlbums img');
elem.trigger(e.type);
elem.addClass('imgHover');
});
$('.song-thumb .hover-play').on('mouseleave', function(e) {
var elem = $('section.suggestedAlbums img');
elem.trigger(e.type);
elem.removeClass('imgHover');
});
var count = 0;
$('section.suggestedAlbums img').hover(function() {
count++;
$('[remove]').html('<label remove><br>It triggers the hover event(' + count + ') too.<br></label>');
});
.song-thumb {
background: aliceblue;
padding: 1em;
}
.hover-play {
cursor: pointer;
color: green;
}
.imgHover {
transform: scale(1.2);
z-index: 3;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="song-thumb"><span class="hover-play">></span>
</div>
<section class="suggestedAlbums">
<img src="http://placehold.it/350x150">
</section><label remove></label>

Related

CSS incrementing transition animation on every button click

Given
var box = document.querySelector('.box');
document.addEventListener("click", (event) => {
if (!event.target.closest("button")) return;
if(event.target.id === "button") {
box.classList.add('move');
}
});
.box {
width: 100px;
height: 100px;
background-color: #000;
transition: transform 1s;
}
.move {
transform: translateX(20px);
}
<div class="box"></div>
<button id="button">button</button>
with a JS Fiddle here.
I want the box's x-position to increment by 20px on every button click.
I am not sure how to proceed. I initially tried using #KeyForms but that requires the from and to prefixes, on which I cannot (I think) add a variable value. Same issue arises here, it seems I cannot have a variable in the css code which I can increment. Am I using the correct function at all (transition) ?
I also tried
if(event.target.id === "button") {
if(!box.classList.contains('open')){
box.classList.add('open');
}else {
box.classList.remove('open');
}
}
but that seems to move the box back and forth repetitively.
Does anyone have any tips or ideas? (I am adding the Javascript tag, since I suspect this problem may potentially be solved in JS directly).
You can store the x position in a variable, increment by 20 every click and apply it to the transform style property:
var x = 0, box = document.querySelector('.box');
button.addEventListener('click', function() {
x += 20, box.style.transform = `translateX(${x}px)`;
})
.box {
width: 100px;
height: 100px;
background-color: #000;
transition: 1s;
}
<div class="box"></div>
<button id="button">button</button>
Just keep on adding Using javascript style
var button = document.querySelector('#button');
button.onclick = function () {
document.querySelector('.box').style.transform += "translateX(20px)";
};
.box {
width: 100px;
height: 100px;
background-color: #000;
transition: transform 1s;
}
<div class="box"></div>
<button id="button">button</button>
Using javascript style would answer your question. There is CSS style for javascript like box.style.transform = 'translateX(20px)'. In Javascript you can calculate styles values(Of course in CSS changing values with calculating is possible). So I added some codes like below.
var box = document.querySelector('.box');
let cnt = 0;
document.addEventListener("click", (event) => {
if (!event.target.closest("button")) return;
if(event.target.id === "button") {
console.log(box.style.transform)
cnt++;
console.log(cnt)
box.style.transform = `translateX(${20 * cnt}px)`;
}
});
.box {
width: 100px;
height: 100px;
background-color: #000;
transition: transform 1s;
}
.move {
transform: translateX(20px);
}
.move1 {
transform: translateX(-20px);
}
<div class="box"></div>
<button id="button">button</button>

Setting up an .active class to a dynamically created link JS

I built a navbar a few weeks back and just realised I did not set an .active class on it. Now, I built the navbar and the links dynamically in JS and would now like to give whichever one is active the according CSS.
This is how I built the navbar in JS:
let womensNav = document.createElement("ul");
womensNav.classList.add("womensNav");
const el1 = document.createElement("li");
el1.innerHTML = "<a>Jeans</a>";
el1.addEventListener("click", (e) => {
document.location.href =
"https://www.martadolska.com/product-category/women/womens-jeans";
});
womensNav.appendChild(el1);
document.querySelector(".ast-woocommerce-container").appendChild(womensNav);
I have more than one link, but for this purpose I don't need to show it all. So now the goal is to build a generic function that gives the active element within the navbar the according class.
document.querySelectorAll("#womensNav li").forEach(function (ele) {
ele.addEventListener("click", function (e) {
e.preventDefault();
document
.querySelectorAll("#womensNav li a.active")
.forEach((ele) => ele.classList.remove("active"));
ele.parentNode.classList.toggle("active");
});
});
And this is what my CSS looks like:
.womensNav li a:hover {
color: var(--main-text-color);
text-decoration: line-through darkred solid;
}
.womensNav li a::before {
content: "";
position: absolute;
width: 100%;
height: 2px;
bottom: 7px;
left: 0;
background-color: #b22222;
visibility: hidden;
transform: scaleX(0);
transition: all 0.3s ease-in-out 0s;
}
.womensNav li a:hover::before {
visibility: visible;
transform: scaleX(1);
}
.womensNav li a:active::before {
content: "";
position: absolute;
width: 100%;
height: 2px;
bottom: 10px;
left: 0;
background-color: #b22222;
}
// up until this point everything works
.active {
text-decoration: line-through darkred solid;
}
I am guessing there is something missing/not completely right in the second snippet of the JS code since nothing is happening when my link is active. I get the animation that I would like to get, but then it disappears once the user is redirected to that specific link, so you wouldn't know which sub-page you are on.
this is wrong
ele.parentNode.classList.toggle("active");
"ele" is the <li>, you are adding the "active" class to the <ul> via the parentNode, might be better to use the "e" event from the click and use e.target and then try and set the active class on the <a> or use childNode/children to get at your <a>

Transitioning Visibility/Opacity w/in JS

I have an alert box that I want to use sessionStorage so that it only appears once. When the user clicks to close the alert, I want the box to disappear (display:none) but fade-out.
I read that you have to use two different functions - one that is activated when clicked and starts the transition and another the adds the 'display' style once transitioned. However, I can't get that to work:
<style>
.ddAlert {
padding: 20px;
box-sizing: border-box;
background-color: #f0ad4e;
color: #fff;
opacity: 1;
transition: opacity 1s;
}
.hide {
opacity: 0;
display: none;
}
</style>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
let dismissed = sessionStorage.getItem("dismissed");
let alertDiv = document.getElementById("alert");
let dismissButton = document.getElementById("dismiss");
if (!dismissed) {
alertDiv.classList.remove("hide");
}
alertDiv.addEventListener("click", function() {
this.style.display = "block";
}.bind(alertDiv));
alertDiv.addEventListener("transitionend", function() {
if (this.className == "hide") {
this.style.display = "none";
}
sessionStorage.setItem("dismissed", true);
}.bind(alertDiv));
});
</script>
<div class="ddAlert hide" id="alert">
SOME ANNOYING ALERT HERE!
<button type="button" id="dismiss">X</button>
</div>
You are on the right track. Instead of listening on click on the alert, use the button as I assume it is there for that reason. When clicking the button the .hide class should be added to the alert. This will start the transition from opacity: 1; to opacity: 0;.
I suggest that instead of using inline-styles, that you stick to classes. Inline styles are hard to overwrite and prevents you from utilizing the full power of CSS. So I've added some classes in there to help you out.
Try out the example below.
<div class="ddAlert hidden" id="alert">
SOME ANNOYING ALERT HERE!
<button type="button" id="dismiss">X</button>
</div>
.ddAlert {
display: block;
transition: opacity 1s;
}
.hide {
opacity: 0;
}
.hidden {
display: none;
}
document.addEventListener("DOMContentLoaded", function() {
let dismissed = sessionStorage.getItem("dismissed");
let alertDiv = document.getElementById("alert");
let dismissButton = document.getElementById("dismiss");
if (!dismissed) {
alertDiv.classList.remove("hidden");
}
dismissButton.addEventListener("click", function() {
alertDiv.classList.add("hide");
});
alertDiv.addEventListener("transitionend", function({ target }) {
if (target.classList.contains("hide")) {
target.classList.add("hidden");
}
sessionStorage.setItem("dismissed", true);
});
});
This answer greatly lends from this SO question titled CSS3 Transition - Fade out effect which notes
When showing the element (by switching to the visible class), we want
the visibility:visible to kick in instantly, so it’s ok to transition
only the opacity property. And when hiding the element (by switching
to the hidden class), we want to delay the visibility:hidden
declaration, so that we can see the fade-out transition first. We’re
doing this by declaring a transition on the visibility property, with
a 0s duration and a delay.
I chose not to mark this question as a duplicate because it also involves the transitionend event. Additionally, I've focused only on the essence of the transition, with a minimal illustration.
The crucial element is the .dismissed-saved class.
let alertDiv = document.getElementById("alert");
let dismissButton = document.getElementById("dismiss");
dismissButton.addEventListener("click", function() {
// kick in the transition
alertDiv.classList.add("dismissed-saved");
// *this is where state should be committed
});
alertDiv.addEventListener("transitionend", function({
target
}) {
if (target === alertDiv) {
// clean up and show a nifty text message illustrating the event handler.
target.classList.add("hidden");
target.classList.remove("dismissed-saved");
document.getElementById("dismissed").classList.remove('hidden');
}
});
.ddAlert {
padding: 20px;
box-sizing: border-box;
background-color: #f0ad4e;
color: #fff;
opacity: 1;
}
.hidden {
display: none;
}
.dismissed-saved {
visibility: hidden;
opacity: 0;
transition: visibility 0s 2s, opacity 2s linear;
}
<div class="ddAlert" id="alert">
SOME ANNOYING ALERT HERE!
<button type="button" id="dismiss">X</button>
</div>
<div id="dismissed" class="hidden">
Dismissed!
</div>
Good luck!

I can expand my div, but how do I shrink it?

I've got a series of divs that, when clicked, expand a div immediately beneath each one of them. When another div is clicked, any previously expanded div is closed and the one below the clicked div is expanded. This is working really nicely. My problem is that clicking on the already open div should shrink the div beneath it, but it doesn't.
My code is based on this example...
https://wpbeaches.com/create-expandcollapse-faq-accordion-collapse-click/
This example works perfectly - clicking any div closes any other div, including its own if it's already open.
My code works well, but clicking a div doesn't close the div below it if it's already open.
CSS:
/* Style the element that is used to open and close the accordion class */
div.accordion {
background-color: #fff;
color: #444;
cursor: pointer;
padding: 0px;
width: 100%;
text-align: left;
border: none;
outline: none;
transition: 0.4s;
margin-bottom:10px;
opacity: 0.70;
filter: alpha(opacity=70);
}
/* Add a background color to the accordion if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
div.accordion.active, div.accordion:hover {
background: rgb(255,255,255);
background: linear-gradient(90deg, rgba(255,255,255,1) 0%, rgba(232,231,222,1) 50%, rgba(255,255,255,1) 100%);
opacity: 1;
filter: alpha(opacity=100);
}
/* Style the element that is used for the panel class */
div.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: 0.4s ease-in-out;
opacity: 0;
margin-bottom:10px;
}
div.panel.show {
opacity: 1;
max-height: 500px; /* Whatever you like, as long as its more than the height of the content (on all screen sizes) */
}
JAVASCRIPT:
<script>
document.addEventListener("DOMContentLoaded", function(event) {
var acc = document.getElementsByClassName("accordion");
var panel = document.getElementsByClassName('panel');
for (var i = 0; i < acc.length; i++) {
acc[i].onclick = function() {
var setClasses = !this.classList.contains('active');
setClass(acc, 'active', 'remove');
setClass(panel, 'show', 'remove');
if (setClasses) {
this.classList.toggle("active");
this.nextElementSibling.classList.toggle("show");
}
}
}
function setClass(els, className, fnName) {
for (var i = 0; i < els.length; i++) {
els[i].classList[fnName](className);
}
}
});
</script>
HTML:
My html is just like the code in the wpbeaches.com example above.
Add removing logic in your else case or remove the if condition since you are using toggle function. In your case, the toggle is working similar to the add method. Just check with the code
if (setClasses) {
this.classList.add("active");
this.nextElementSibling.classList.add("show");
} else {
this.classList.remove("active");
this.nextElementSibling.classList.remove("show");
}
What I understood is clicking on answer link doesn't close the question but if we click on already open question, it will close the respective answer. It's because you applied the onClick function only on accordian "p" element and not on panel "div" element.
You can apply 1 common class to both accordian and panel element and apply onCLick function on that class.
acc[i].onclick = function() {

Toggling a slide out menu

So I'm in the process of making a slide out menu on my site. It slides out on click, but how can I set it up so on another click it will slide back in?
Pretty simple source code right now:
$(document).ready(function() {
$("#menuicon").click(function() {
$("nav ul, .content").animate({left: "-15%"}, 1000);
});
});
Thanks in advance!
Check this simple Slide Out menu.
DEMO http://jsfiddle.net/yeyene/TLtqe/1/
$('a').on('click',function() {
if($('#website').css('left')=='0px'){
$('#website').animate({left: '-30%'}, 1000);
}else{
$('#website').animate({left:0}, 1000);
}
});
You may be able to just use the toggle() function in place of click, but I'm not a big fan of toggle. The below solution incorporates a class as well, but this is how I'd do it:
$(document).ready(function() {
$("#menuicon").click(function(e) {
var menuicon = $(e.target);
if (!menuicon.hasClass('open'){
menuicon.addClass('open');
$("nav ul, .content").animate({left: "-15%"}, 1000);
} else {
menuicon.removeClass('open');
$("nav ul, .content").animate({left: "0"}, 1000);
}
});
});
I would also incorporate a 'working' class on there to prevent double clicks, but that may be more than you need with your project.
EDIT:
Little extra tidbit that I use quite a bit, if you have complex menu options that involve a few different objects (like an anchor, with an img and a span inside, or some other elements in it) you can pair e.target with the jquery 'closest()' function to be sure you're always selecting the anchor and not one of its children.
var clicked = $(e.target).closest('a');
This is pretty helpful if you're trying to also fetch any attribute values from your clicked objects, using this you know for certain that your selection will always be the 'a' (rather than e.target returning a child img or something), and you can work from there.
Use the jquery slidetoggle instead!
E.g, $(document).ready(function() { $("#menuicon").click(function() { $("nav ul, .content").slideToggle(1000); }); }); instead of animate!
Couldn't you use something like this?
$(document).ready(function() {
$(".nav_button").click(function () {
$(".top.mini_nav").slideToggle();
});
});
I'm using this here -> DEMO
And this is the CSS I use for that button
.top.mini_nav {
display: none;
top: 20px;
left: 20px;
margin-bottom: 60px;
position: relative;
}
.top.mini_nav a:hover {
background-color: #F8F8F8;
}
.nav_button {
position: relative;
width: 40px;
height: 40px;
left: 40px;
display: block;
color: white;
background-color: #2898F2;
font-size: 20px;
font-weight: bold;
text-align: center;
line-height: 39px;
cursor: pointer;
top: 20px;
border-radius: 5px;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
}
.nav_button:hover {
background-color: #D0A624;
}
You will probably want something cleaner - but this works fine so far for me.
I realized that I just needed to make a variable that would set itself to true/false depending on if it was open.
var open = false;
$(document).ready(function() {
$("#menuicon").click (function() {
if (!open){
$(".content, nav ul").animate({left: "-=15%"}, 1000);
open = true;
} else {
$(".content, nav ul").animate({left: "+=15%"}, 1000);
open = false;
}
});
});
Thanks for all the help guys!

Categories

Resources