Responsive Design - how to toggle a menu's visibility - javascript

Update
I have a new post here with jsfiddles and a clearer question.
I am attempting to use principles of responsive design to adapt to changing screen size. I have CSS which will hide a vertical menu contained in a div (main-nav-vert) and display a "Menu" button contained in a div (div_menu_toggle) when the browser width drops into a range. There is other div resizing happening, but this code is simplified.
When clicking on the Menu button, js code runs to toggle the menu div (main-nav-vert) by changing its display property.
All works great with the button appearing and the menu being hidden when the browser width shrinks.
Then when clicking on the Toggle Button, the menu is briefly made visible... and then spontaneously disappears again. I have verified that the code to hide the div is not being run (.display = 'none'). Is the menu getting hidden again because the CSS code is always active? If so, how can I accomplish this task? I am looking for a pure js answer, please no jQuery. Thanks.
CSS
/* When screen shrinks to this range, hide Menu, display Menu button */
#media (max-width: 697px) and (min-width: 320px) {
.div_menu_toggle{
display: block;
}
.main-nav-vert{
display: none;
}
}
JS
<script type="text/javascript">
function showmenu() {
var mainnavvert = getElementsByClassName('main-nav-vert');
var i, s, len = mainnavvert.length;
for (i = 0; i < len; ++i) {
if (i in mainnavvert) {
// toggle the menu
mainnavvert[i].style.display = 'block';
} else {
mainnavvert[i].style.display = 'none';
}
}
}
function getElementsByClassName(className) {
if (document.getElementsByClassName) {
return document.getElementsByClassName(className);
} else {
return document.querySelectorAll('.' + className);
}
}
</script>

*not tested but I'm guessing you just need a separate class for display:none and display:block;
then change the class, not the style. something like
if (i in mainnavvert) {
// toggle the menu
mainnavvert[i].className = "show-me";
} else {
mainnavvert[i].className = "hide-me";
}
}

Toggle the display depending of the current state of it.
Something like this might work.
for (i = 0; i < len; ++i) {
var menu = mainnavvert[i];
if (menu.style.display === 'block') {
menu.style.display = 'none';
} else {
menu.style.display = 'block';
}
}

you need to take new class to set active/inactive toggle menu.
css
/* When screen shrinks to this range, hide Menu, display Menu button */
#media (max-width: 697px) and (min-width: 320px) {
.div_menu_toggle{
display: block;
}
.main-nav-vert{
display: none;
}
.main-nav-vert.active{
display: block;
}
}
js
<script type="text/javascript">
function showmenu() {
var mainnavvert = getElementsByClassName('main-nav-vert');
var i, s, len = mainnavvert.length;
for (i = 0; i < len; ++i) {
if (i in mainnavvert) {
// toggle the menu
if(mainnavvert[i].style.display == "block")
removeClass(mainnavvert[i]);
}
else {
addClass(mainnavvert[i]);
}
}
}
}
function getElementsByClassName(className) {
if (document.getElementsByClassName) {
return document.getElementsByClassName(className);
} else {
return document.querySelectorAll('.' + className);
}
}
function addClass(ele) {
var classString = ele.className;
var newClass = classString.concat(" active");
ele.className = newClass;
}
function removeClass(ele)
{
[].forEach.call(ele, function(el) {
el.classList.remove("active");
});
}
});
As you want pure javascript,here it is but code is going very smooth and optimze if you do it with jquery and I don't know why you use for loop if there is only 1 element then you can ignore the loop.

Related

Problem with a CSS property when using a JS script

Noob question. I am practicing with a Web-Site; and I have a toggleable menu that appears when it gets to a certain width (250-750px) and disappears when it reaches 751px. When I insert a js script it remains hidden.
CSS
#media (min-width: 250px) and (max-width: 750px){
.headernav ul li {
width: 100%;
display: block;
background-color: hsl(3, 43%, 56%);
opacity: 0;
transition: .5s;
}
#media (min-width: 751px){
.headernav ul li{
opacity: 1;
}
}
Here is the js code
let toggledNavMenu = false;
function toggleMenu(){
let getMenu = document.querySelector(".menu");
let getLi = document.querySelectorAll(".headernav ul li");
let liSize = getLi.length;
if(toggledNavMenu == false){
for (let i = 0; i < liSize; i++) {
getLi[i].style.opacity ="0";
}
toggledNavMenu = true;
}
else{
for (let i = 0; i < liSize; i++) {
getLi[i].style.opacity ="1";
}
toggledNavMenu = false;
}
}
The problem is that if I click on the menu; and the opacity is set to 0 in the js script, the menu remains hidden when I expand the screen. So basically I end up with an invisible menu. I'll let a sequence of images to explain it better. The only way to fix this is by going to a width<=750 so the buttom shows and then click on it, bringing the opacity back to 1 and it's really annoying.
Starting Nav
When Width is <= 750 the toggleable menu appears
The menu displays when clicked
Width is now > 750 and the menu disappears
I felt like you wrote many unnecessary codes like for loop functions for a simple Nav-Bar.
CSS code
#media (min-width: 250px) and (max-width: 750px){
.menu{
display: none;
}
}
JS code
function toggleNav() {
var toggledNavMenu = document.getElementById(".menu");
if (toggledNavMenu.style.display === "none") {
toggledNavMenu.style.display = "block";
} else {
toggledNavMenu.style.display = "none";
}
}
// just piece of cake ;)
You're getting the job wrong.
First - install jQuery, it's simple enough for a newbiew.
Second - Explore and learn.
Third - Implement.
In most cases css elements are bound to jQuery/Javascript events. So when you hover, then you add 'active' class to the element that was clicked. You add other class to the parent as well.
So you get
<ul class="dropdown-is-active"><li class="selected"> ... </ul>
Basically you react to events, add/remove classes and compose css properly. Remember that it's hard to make uniform dropdown menu. It's always somehow limited.

(HTML/Js) Cycling element visibilities

var terminal = document.getElementById('terminal');
var vncScreen = document.getElementById('screen');
var video = document.getElementById('video');
var vncToggle = document.getElementById('vncToggle');
var termToggle = document.getElementById('terminalToggle');
termToggle.onclick = function toggleTerminal() {
if (terminal.classList.contains('hide')) {
terminal.classList.remove('hide');
if (vncScreen.classList.contains('hide')) {} else {vncScreen.classList.add('hide')}
if (video.classList.contains('hide')) {} else {video.classList.add('hide')}
} else {
terminal.classList.add('hide');
if (video.classList.contains('hide')) {video.classList.remove('hide')} else {}
}
}
vncToggle.onclick = function toggleVNC() {
if (vncScreen.classList.contains('hide')) {
vncScreen.classList.remove('hide');
if (terminal.classList.contains('hide')) {} else {terminal.classList.add('hide')}
if (video.classList.contains('hide')) {} else {video.classList.add('hide')}
} else {
vncScreen.classList.add('hide');
if (video.classList.contains('hide')) {video.classList.remove('hide')} else {}
}
}
.black-box {
background: black;
height: 500px;
width: 500px;
position: absolute;
}
.green-box {
background: green;
height: 500px;
width: 500px;
position: absolute;
}
.blue-box {
background: blue;
height: 500px;
width: 500px;
position: absolute;
}
.hide {
display: none;
}
<button class="button" id="terminalToggle" title="Toggle Terminal">Toggle terminal</button>
<button class="button" id="vncToggle" title="Toggle Terminal">Toggle vnc</button>
<div id='video' class="black-box"></div>
<div id='screen' class="green-box hide"></div>
<div id='terminal' class="blue-box hide"></div>
basically when you click "Toggle terminal" it should show blue and then if you click again go back to black; when you click "Toggle vnc" it should show green and then if you click again go back to black. If you click "Toggle vnc" and it is already blue, it should turn green and vice versa (but clicking "Toggle terminal")
I currently have the following Js:
var terminal = document.getElementById('terminal'); //video-like element
var vncScreen = document.getElementById('screen'); //video-like element
var video = document.getElementById('video'); //video-like element
var vncToggle = document.getElementById('vncToggle'); //button
var termToggle = document.getElementById('terminalToggle'); //button
termToggle.onclick = function toggleTerminal() {
terminal.classList.toggle('hide');
vncScreen.classList.toggle('hide');
video.classList.toggle('hide');
}
vncToggle.onclick = function toggleVNC() {
vncScreen.classList.toggle('hide');
terminal.classList.toggle('hide');
video.classList.toggle('hide');
}
and css:
.hide {
display: none;
}
When I had just two different HTML elements, this class toggling methodology worked. Now that there are 3, I'm not sure it will work as desired.
video is initially visible i.e. hide is not in its classList
terminal is initially hidden i.e. hide is in its classList
vncScreen is initially hidden i.e. hide is in its classList
When toggleTerminal() is called:
video becomes hidden
terminal becomes visible
vncScreen becomes visible (but it should not)
If toggleVNC() is called (after toggleTerminal()):
video becomes visible again (but it should not)
terminal becomes hidden
vncScreen becomes hidden
Note how if the either of the function calls were toggled only by themselves, this method would work (provided I removed vncScreen.classList.toggle('hide'); in toggleTerminal() and terminal.classList.toggle('hide'); in toggleVNC()).
The problem is I need to account for any order of button-presses of termToggle and vncToggle. Essentially my goal is to "cycle" these elements such that:
1) Toggling of the "selected" element (i.e. termToggle corresponds to visibility of terminal element && vncToggle corresponds to visibility of vncScreen element) hides the remaining two elements (video && vncScreen || terminal && video respectively)
2) The order of toggling of "selected" elements does not affect 1)
3) A second toggle of the "selected" element will hide itself and the other element that is not video
Any ideas on how to best accomplish this?
At one point I thought about doing some logic that evaluated whether hide was contained in the appropriate classList's and just manually add or remove the hide class accordingly but this seemed kind of sloppy to me (idk, maybe its not?).
See code snippet in question for functionality, Js redundantly posted here:
var terminal = document.getElementById('terminal');
var vncScreen = document.getElementById('screen');
var video = document.getElementById('video');
var vncToggle = document.getElementById('vncToggle');
var termToggle = document.getElementById('terminalToggle');
termToggle.onclick = function toggleTerminal() {
if (terminal.classList.contains('hide')) {
terminal.classList.remove('hide');
if (vncScreen.classList.contains('hide')) {} else {vncScreen.classList.add('hide')}
if (video.classList.contains('hide')) {} else {video.classList.add('hide')}
} else {
terminal.classList.add('hide');
if (video.classList.contains('hide')) {video.classList.remove('hide')} else {}
}
}
vncToggle.onclick = function toggleVNC() {
if (vncScreen.classList.contains('hide')) {
vncScreen.classList.remove('hide');
if (terminal.classList.contains('hide')) {} else {terminal.classList.add('hide')}
if (video.classList.contains('hide')) {} else {video.classList.add('hide')}
} else {
vncScreen.classList.add('hide');
if (video.classList.contains('hide')) {video.classList.remove('hide')} else {}
}
}

Remove image from span on screen resize | jQuery

I am trying to add and remove images from span dependable on screen size.
I have 1 event handler to check the screen size and fire one of the functions if condition is true.
Here is my event handler:
jQuery(window).resize(function() {
var innerWidth = window.innerWidth;
if (innerWidth < 1000) {
ApplyIconsToMobileNav();
console.log("apply icons hit");
} else if (innerWidth > 1000) {
RemoveIconsDesktopNav();
console.log("removed icons hit");
}
});
Here is my apply icons function:
function ApplyIconsToMobileNav() {
var Categories = jQuery(".nav-menu > .nav-mobile > .nav-item > a").find("span:first-of-type");
jQuery(Categories).each(function() {
var Category = jQuery(this).text();
if(Category == "E-Liquid") {
jQuery(this).html("<img src='/media/wysiwyg/purple_icons/e-liquid(32x32).png' />" + Category);
} else if (Category == "E-Cigarette Kits") {
jQuery(this).html("<img src='/media/wysiwyg/purple_icons/e-cigarette(32x32).png' />" + Category);
}
});
};
And here is my remove icons function:
function RemoveIconsDesktopNav() {
var CategoriesImg = jQuery(".nav-menu > .nav-mobile > .nav-item > a").find("span:first-of-type");
jQuery(CategoriesImg).each(function() {
jQuery("img", this).hide();
});
};
I have a lot more images in the navigation but pasted only relevant code. My event listener is working fine, so is the ApplyIconsToMobileNav() function, however, I can't get the RemoveIconsDesktopNav() to work. I know, that I can do exactly the same thing I did in the ApplyIconsToMobileNav() but add style of display: none to the image but I want to select all images from the selected span and hide/remove them.
I am not familiar with this syntax: jQuery("img", this).hide();
However, you could try the following: $(this).find('img').hide();
Alternatively, you can also use .toggle(); instead of .hide(); if you wish to alternate between show/hide.
Instead of jQuery use CSS Media Queries. eg-
This CSS will work only when screen is than 767px that is a normal mobile screen
#media (max-width: 767px){
.class_name img{
display: none;
}
}

Remove/add css classes on breakpoint with matchmedia.js

I have following code which works fine when the screen size is 770px and below (as determined by breakpoints):
var handleMatchMedia = function (mediaQuery) {
if (mediaQuery.matches) {
$j(".view-all a").removeClass("button");
$j(".view-all").removeClass("view-all");
} else {
$j(".view-all a").addClass("button");
$j(".view-all").addClass("view-all");
}
},
mql = window.matchMedia('all and (max-width: 770px)');
handleMatchMedia(mql);
mql.addListener(handleMatchMedia);
The problem is when the window is resized to 770px and up I lose my classes.
How to achive to change class on window resize?
You need to cache your selectors. See jsfiddle as well :
var viewAll = $j(".view-all")
, buttons = $j(".view-all a")
, handleMatchMedia = function (mediaQuery) {
if (mediaQuery.matches) {
buttons.removeClass("button");
viewAll.removeClass("view-all");
} else {
buttons.addClass("button");
viewAll.addClass("view-all");
}
}
, mql = window.matchMedia('all and (max-width: 770px)');
handleMatchMedia(mql);
mql.addListener(handleMatchMedia);
Guessing what you're going for is changing the design page when media changes, by adding classes.
Simply using css and media queries will achieve this:
#media all and (max-width: 770px) {
.viewall a {
color: blue;
}
}
but if you truly want it too be handled with javascript I'll recommend using another class as marker, like .adapt and changing the code to:
var handleMatchMedia = function (mediaQuery) {
if (mediaQuery.matches) {
$j(".adapt a").removeClass("button");
$j(".adapt").removeClass("view-all");
} else {
$j(".adapt a").addClass("button");
$j(".adapt").addClass("view-all");
}
},
mql = window.matchMedia('all and (max-width: 770px)');
handleMatchMedia(mql);
mql.addListener(handleMatchMedia);
I would suggest to save the needed classes in a data-770-classes attribute.
if (mediaQuery.matches) {
buttons.removeClass(buttons.attr('data-770-classes'));
viewAll.removeClass(viewAll.attr('data-770-classes'));
} else {
buttons.addClass(buttons.attr('data-770-classes'));
viewAll.addClass(viewAll.attr('data-770-classes'));
}
I assume $j creates a jQuery object.
The HTML would look like:
<div class="view-all" data-700-classes="view-all">...</div>
You can use element.className += "button" to add class and .className = ""to remove class, here's the code you need:
var viewAll = document.getElementsByClassName("view-all")[0];
var buttons = viewAll.getElementsByTagName("a");
var handleMatchMedia = function (mediaQuery) {
if (mediaQuery.matches) {
buttons.className += "button";
viewAll.className = "";
} else {
buttons.className += "button";
viewAll.className += "view-all";
}
}
var mql = window.matchMedia('all and (max-width: 770px)');
handleMatchMedia(mql);
mql.addListener(handleMatchMedia);

How to make text appear on scroll in html

Hello, I want a certain text to appear when I scroll past it or when I scroll until the point where the text is. The effect when appearing should be somewhat like the first effect on the top of the website http://namanyayg.com/.
I want the effect in minimal code with pure CSS and JS i.e no jQuery.
I was thinking that maybe I would use something like a display:none property for a span and then when you scroll past it the display becomes block but I dont know how to trigger the effect using javascript.
Any help would be appreciated.
First wrap whatever your text or content that you want to show on scroll, in one div so that you can show hide the div depending upon the scroll. Write two classes for your target div.
Your CSS:
/*Use this class when you want your content to be hidden*/
.BeforeScroll
{
height: 100px; /*Whatever you want*/
width: 100%; /*Whatever you want*/
.
.
display: none;
}
/*Use this class when you want your content to be shown after some scroll*/
.AfterScroll
{
height: 100px; /*Whatever you want*/
width: 100%; /*Whatever you want*/
.
.
display: block;
}
Your HTML:
<!--Set class BeforeScoll to your target div-->
<div id = "divToShowHide" class = "BeforeScroll">Content you want to show hide on scroll</div>
Your Script:
<!--include these script in head section or wherever you want-->
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/jquery-ui.min.js" type="text/javascript"></script>
<script type = "text/javascript">
$(document).ready(function(){
//Take your div into one js variable
var div = $("#divToShowHide");
//Take the current position (vertical position from top) of your div in the variable
var pos = div.position();
//Now when scroll event trigger do following
$(window).scroll(function () {
var windowpos = $(window).scrollTop();
//Now if you scroll more than 100 pixels vertically change the class to AfterScroll
// I am taking 100px scroll, you can take whatever you need
if (windowpos >= (pos.top - 100)) {
div.addClass("AfterScroll");
}
//If scroll is less than 100px, remove the class AfterScroll so that your content will be hidden again
else {
s.removeClass("AfterScroll");
}
//Note: If you want the content should be shown always once you scroll and do not want to hide it again when go to top agian, no need to write the else part
});
});
</script>
Hope it will solve your problem.
I would recommend this plugin
http://johnpolacek.github.io/superscrollorama/
Edit:
I don't know how no one noticed that the solution had to be made without using external libraries like jQuery. However, the solution is extremely easy with basic functionality. Find it here
HTML:
<div id="parent-div">
<div id="child-div">
Psst .. I am here!!
</div>
</div>
CSS:
#parent-div
{
position:relative;
height:3000px;
width:300px;
background-color:red;
}
#child-div
{
color:white;
position:relative;
top:1000px;
width:300px;
display:none;
text-align:center;
}
JS:
var body=document.getElementsByTagName("body")[0];
var parent=document.getElementById("parent-div");
var child=document.getElementById("child-div");
body.onscroll = function(){
//console.log(documenhttps://fiddle.jshell.net/3urv0tp0/#tidyt.getElementById("child-div").style.top)
if(document.documentElement.scrollTop>=child.offsetTop)//Adjust Tolerance as you want
{
child.style.display="block"
}
};
I was looking for this either. Here i was trying to make "show text after scrolling to (number)px with fade effect". I wish it will work as it works for me :) The animation will be playing again if u scroll back to it, idk how to make it just one like in web u showed xd (i will edit if I find out)
window.addEventListener("scroll", function() {showFunction()});
function showFunction() {
if (document.body.scrollTop > 900 || document.documentElement.scrollTop > 900) {
document.getElementById("toptexts2").style.display = "block";
} else {
document.getElementById("toptexts2").style.display = "none";
}
}
.toptexts2 {
animation: fadeEffect 3s; /* fading effect takes 3s */
}
#keyframes fadeEffect { /* from 0 to full opacity */
from {opacity: 0;}
to {opacity: 1;}
}
<div class="toptexts2" id="toptexts2">
<div>Hi!</div>
<div>↓ go down ↓</div>
</div>
I like this:
var doc = document, dE = doc.documentElement, bod = doc.body;
function E(e){
return doc.getElementById(e);
}
function xy(e, d){
if(!d)d = 'Top';
d = 'offset'+d;
var r = e[d];
while(e.offsetParent){
e = e.offsetParent; r += e[d];
}
return r;
}
function x(e){
return xy(e, 'Left');
}
function y(e){
return xy(e);
}
var txt = E('theId'), txtS = txt.style;
onscroll = function(){
var left = dE.scrollLeft || bod.scrollLeft || 0;
var top = dE.scrollTop || bod.scrollTop || 0;
var w = innerWidth || dE.clientWidth || bod.clientWidth;
var h = innerHeight || dE.clientHeight || bod.clientHeight;
if(top > y(txt)-h){
txtS.display = 'none';
}
else{
txtS.display = 'block';
}
}
I left the left stuff in there, just in case, but you can probably remove it.
var div=$("#divtochange");
$(window).scroll(function () {
var windowpos = $(window).scrollTop();
//---check the console to acurately see what the positions you need---
console.log(windowpos);
//---------------------
//Enter the band you want the div to be displayed
if ((windowpos >= 0) && (windowpos <= 114)){
div.addClass("AfterScroll");
}
else{
div.removeClass("AfterScroll");
}

Categories

Resources