Toggling a slide out menu - javascript

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!

Related

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>

Using touchmove to trigger hover event

I'm relatively new to coding and am running into a particular issue with my website. My homepage has images on it with overlay text hover effect that occurs when a cursor is moved over the image. It works perfectly on desktop, however, not on mobile. I would like for the hover text to appear when the user swipes across the image in any direction. I've done some research and it appears that I should somehow be using jQuery and the touchmove function to make this happen. But I just can't figure it out. I am using Shopify (debut theme) to build my website. Any help will be greatly appreciated!
Here's my CSS for hover event:
//hover effect//
.container {
position: relative;
width: 100%;
}
.image {
display: block;
width: 100%;
height: auto;
}
.overlay {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 99%;
width: 100%;
opacity: 0;
transition: .5s ease;
background-color: #000000;
}
.container:hover .overlay {
opacity: 0.7;
}
.text {
color: white;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 20px;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
text-align: center;
white-space: pre;
}
Thanks!!!!
You'd need to apply a class with the desired effect to the target element.
You could do it with Jquery, but javascript is perfectly capable to do it on its own.
Something like:
Javascript:
const myTargetElement = document.getElementsByClassName('overlay')[0]; // index to be confirmed
// add hover style
myTargetElement.addEventListener('touchmove', function (e) {
e.target.classList.add('hover'); // or whichever class name you'd like
});
// remove hover style on end
myTargetElement.addEventListener('touchend', function (e) {
e.target.classList.remove('hover'); // or whichever class name you'd like
});
CSS:
.container:hover .overlay,
.overlay.hover {
opacity: 0.7;
}
Note: if you want to target all the elements .overlay on your page with that code, you would need something like:
Javascript:
const myTargetElements = document.getElementsByClassName('overlay');
// convert HTML collection to array
const myTargetElementsArray = [].slice.call(myTargetElements);
myTargetElementsArray.forEach(function (element) {
// add hover style
element.addEventListener('touchmove', function (e) {
e.target.classList.add('hover'); // or whichever class name you'd like
});
// remove hover style on end
element.addEventListener('touchend', function (e) {
e.target.classList.remove('hover'); // or whichever class name you'd like
});
});
so Moustachiste's code works! It had a few syntax errors but I was able to resolve them quickly. Here's the final version:
const myTargetElements = document.getElementsByClassName('overlay');
// convert HTML collection to array
const myTargetElementsArray = [].slice.call(myTargetElements);
myTargetElementsArray.forEach(function (element) {
// add hover style
element.addEventListener('touchmove', function (e) {
e.target.classList.add('hover'); // or whichever class name you'd like
});
// remove hover style on end
element.addEventListener('touchend', function (e) {
e.target.classList.remove('hover'); // or whichever class name you'd like
});
});
Paste the code into your theme.js and adjust the variable names accordingly. Should work for everyone!
Cheers to this guy!

JQuery Hover and SlideToggle

I wanted to make the navbar to stay displaying, not until i left my pointer hovered to that portion. What happens is that if I hover my pointer to the navbar, the display keeps getting toggled (displaying in then hiding.. it's on loop?) I just want it to stay. Then hide again when my pointer left
<script>
$(document).ready(function(){
$(".menu-trigger").hover(function(){
$("li").slideToggle(400, function(){
jQuery(this).toggleClass("nav-expanded").css('show','');
});
});
});
</script>
img {
padding: 0px;
max-width: 100%;
max-height: auto;
}
.menu-trigger {
pointer: cursor;
display: block;
position: fixed;
font-family: Sans-serif;
font-size: 15px;
background-color: #664c7d;
height: 35px;
width: 100%;
}
li{
display: none;
}
li.navbar ul {
}
}
div.nav-expanded {
display: block;
}
Your code has a few errors and it is not entirely clear what you are trying to accomplish (.css('show', '')?).
I assume that what you need is an element that will toggle its class when hovered and will change back to its original state when it is not hovered anymore.
What you need to do, is toggle the class of your navigation bar every time your mouse goes over the element and out of it.
Assuming $nav is your navigation bar, you can use:
$nav.on('mouseover mouseout', function(){
$nav.toggleClass('show');
});
Alternatively (and arguably safer):
$nav.on('mouseover', function(){
$nav.addClass('show');
}).on('mouseout', function(){
$nav.removeClass('show');
});
You can see usage in this JSFiddle.

When scrolling to top of div hide another div

this is what I have so far:
$("#main").each(function() {this.scrollTop = this.scrollHeight;
if ($(this).scrollTop()>0)
{
$('#navigation').addClass("nav-hide");
}
else
{
$('#navigation').addClass("nav-normal");
}
});
So basically, I am trying to figure out when you scroll to the top of a div it will hide the navigation bar. So you could read the div without the navigation bar over it. Any ideas? Thanks.
Here's my JSFiddle: https://jsfiddle.net/qb15p5g7/3/
You need to use jquery's window scroll function and not each function unless you are going to have more than one section that you need to hide the navigation on there is no reason to use each and I'm assuming that you don't because you are using an id for #main and Id's are supposed to be unique. Also you don't need to add more than one class you can just add the class and remove the class. So if im correct in assuming that you don't have more than one section that you need to hide the nav in multiple instances on your page then your code should look something like this:
$(window).scroll(function() {
if ($(this).scrollTop() >= $('#main').offset().top) {
$('#navigation').addClass("nav-hide");
}else {
$('#navigation').removeClass("nav-hide");
}
});
And you will just add the nav-hide class and then remove it when scrolling back up.
Here is a fiddle of this working JSFiddle Demo
I assume this is what you are looking for if not let me know so I can edit my answer.
The $(window).scroll() method executes on scroll change of the window. You can use it to hide your #navigation id selector
$(window).scroll(function() {
if ($(this).scrollTop() > 100) {
$('#navigation').fadeIn();
} else {
$('#navigation').fadeOut();
}
});​
JSFiddle here
See the jQuery documentation for .scroll() here
function scrollpos() {
if (window.scrollY<document.getElementById('header').clientHeight) {
document.getElementById('navigation').style.display = 'block';
} else {
document.getElementById('navigation').style.display = 'none';
}
}
#navigation {
width: 100%;
height: 50px;
background-color: #586e75;
position: fixed;
z-index: 1000;
transition: transform 200ms ease;
}
header,
section {
height: 100vh;
width: 100%;
position: static;
}
header {
background: #4f4244;
}
section {
background: #222222;
}
.nav-normal {
transform: translateY(0%);
}
.nav-hide {
transform: translateY(-100%);
}
<body onscroll="scrollpos()">
<div id="navigation"></div>
<header id="header"></header>
<section id="main"></section>
</body>
do u need something like this?#Steboney

Forcing mobile devices to activate :hover CSS properties on first touch and activate link on second touch

: )
So, I'm trying to solve a hover effect issue. I have tooltips on some of my links. Code looks like this:
<a href="https://wikipedia.org/wiki/Space_Shuttle_Atlantis">
<h6 class="has-tip">Space Shuttle
<p class="tip">The space shuttle was invented by Santa Claus</p>
</h6>
</a>
And the CSS is a bit more involved:
.tip {
display: block;
position: absolute;
bottom: 100%;
left: 0;
width: 100%;
pointer-events: none;
padding: 20px;
margin-bottom: 15px;
color: #fff;
opacity: 0;
background: rgba(255,255,255,.8);
color: coal;
font-family: 'Ubuntu Light';
font-size: 1em;
font-weight: normal;
text-align: left;
text-shadow: none;
border-radius: .2em;
transform: translateY(10px);
transition: all .25s ease-out;
box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.28);
}
.tip::before {
content: " ";
display: block;
position: absolute;
bottom: -20px;
left: 0;
height: 20px;
width: 100%;
}
.tip::after { /* the lil triangle */
content: " ";
position: absolute;
bottom: -10px;
left: 50%;
height: 0;
width: 0;
margin-left: -13px;
border-left: solid transparent 10px;
border-right: solid transparent 10px;
border-top: solid rgba(255,255,255,.8) 10px;
}
.has-tip:hover .tip {
opacity 1;
pointer-events auto;
transform translateY(0px);
}
Now, on desktop this works wonderfully. You hover over the tiny title and you get a pretty looking tooltip, then if you click anywhere on the title or tooltip (unless you decide to put yet another link in the paragraph which works separately and nicely) you activate the link. Yay : )
Now on mobile, the whole thing gets funky. Touching just activates the link. If you have slow internet, or iOS, you might glimpse the tooltip just as the next page loads.
I would like the following behavior:
User taps on tiny title (h6) which has class (has-tip)
If this is the first tap, the tooltip shows, and nothing else happens. 3)
If the tooltip is already showing when they tap (as in a subsequent
tap) then the link is activate and the new page loads.
Any ideas how I might implement this? No jQuery if possible.
One way to do it is to save a reference to the last clicked has-tip link and to apply a class to it which forces the tip to show. When you click on a link and it matches the the last one clicked, you let the event pass.
EDIT: oh, I forgot to mention you might need a classList shim for old IE.
JSFiddle link.
HTML
<a href="http://jsfiddle.net/1tc52muq/5/" class="has-tip">
JSFiddle<span class="tip">Click for some fun recursion</span>
</a><br />
<a href="http://google.com" class="has-tip">
Google<span class="tip">Click to look for answers</span>
</a>
JS
lastTip = null;
if(mobile) {
var withtip = document.querySelectorAll(".has-tip");
for(var i=0; i<withtip.length; ++i) {
withtip[i].addEventListener("click", function(e) {
if(lastTip != e.target) {
e.preventDefault();
if(lastTip) lastTip.classList.remove("force-tip");
lastTip = e.target;
lastTip.classList.add("force-tip");
}
});
}
}
CSS
.has-tip {
position: abolute;
}
.tip {
display: none;
position: relative;
left: 20px;
background: black;
color: white;
}
.has-tip:hover .tip, .force-tip .tip {
display: inline-block;
}
Edit: Just wanted to say that Jacques' approach is similar, but much more elegant.
On touch devices, you'll need to make a click/tap counter:
1) On first tap of any link, store the link and display the hover state.
2) On another tap, check to see if it's the same as the first, and then perform the normal tap action if it is. Otherwise, clear any existing hovers, and set the new tap target as the one to count.
3) Reset / clear any hovers if you tap on non-links.
I've made a rudimentary JSFiddle that console.logs these actions. Since we're not using jQuery, I didn't bother with adding/removing CSS classes on the elements.
Also, sorry about not writing taps instead of clicks.
var clickTarget;
var touchDevice = true;
if(touchDevice) {
var links = document.getElementsByTagName('a');
for(var i=0; i<links.length; i++) {
links[i].onclick = function(event) {
event.stopPropagation();
event.preventDefault(); // this is key to ignore the first tap
checkClick(event);
};
};
document.onclick = function() {
clearClicks();
};
}
var checkClick = function(event) {
if(clickTarget === event.target) {
// since we're prevent default, we need to manually trigger an action here.
console.log("Show click state and also perform normal click action.");
clearClicks();
} else {
console.log("New link clicked / Show hover");
clickTarget = event.target;
}
}
var clearClicks = function() {
console.log("Clearing clicks");
clickTarget = undefined;
};
http://jsfiddle.net/doydLt6v/1/

Categories

Resources