Apologies for the long winded question but any help would be much appreciated!
I have a navigation div on a website that disappears when the screen gets smaller to be replaced by a menu button, using a media query. The menu button uses JavaScript to show and hide the menu.
This all works apart from one small bug that I can't figure out, it's a bit hard to explain so I'll bullet point it -
1) Open small browser window so button shows.
2) Open and close menu using button.
3) Maximise screen.
4) The button disappears (which it should) but the menu doesn't reappear.
You can see a live example here - http://andrewbruce.me
I'll put relevant code below -
var clicks = 0;
function decide(x) {
if (clicks == 0) {
document.getElementById("nav").style.visibility = "visible";
document.getElementById("nav").style.opacity = "1";
x.classList.toggle("change");
clicks = 1;
}
else if (clicks == 1) {
document.getElementById("nav").style.visibility = "hidden";
document.getElementById("nav").style.opacity = "0";
x.classList.toggle("change");
clicks = 0;
}
}
#nav {
height: 100%;
width: 22%;
text-align: center;
box-shadow: 2px 2px 5px #888888;
visibility: visible;
opacity: 1;
transition: all .3s ease-in-out;
background-color: #1b1d1f;
float: left;
position: fixed;
z-index: 2;}
#media handheld, screen and (max-width: 1000px) {
#nav {width: 40%; visibility: hidden; opacity: 0;}
.menuButton {visibility: visible;}
}
<div class="menuButton" onclick="decide(this);">
<div id = "bar1"></div>
<div id = "bar2"></div>
<div id = "bar3"></div>
</div>
Try this.
I hope helps.
#media (min-width: 1000px){
#nav{
opacity:1!important;
visibility: visible!important;
}
}
You should not change style by this method document.getElementById("nav").style, it will add inline style and override your properties. Instead create a class with those properties, then use scripts to toggle it.
For example:
CSS
.nav-hidden {
visibility: hidden;
opacity: 0;
}
JS
element.classList.add("nav-hidden");
element.classList.remove("nav-hidden");
use below JS
window.addEventListener("resize", menuChange);
function menuChange() {
if (window.innerWidth > 999){
document.getElementById("nav").style.visibility = "visible";
document.getElementById("nav").style.opacity = "1";
x.classList.toggle("change");
}
}
Related
Ok so here's a challenge: I'm looking to rotate a fixed element when you scroll up and down inside a < div > - and not when you scroll on the entire page. So how do i target the scroll within a specific < div> (my div has classname="elementor")?
My code so far looks like this:
HTML
/* The image i'm trying to rotate */
<img class="portfolio" id="rotatelogo" src="http://jakobnatorp.com/wp-content/uploads/2021/10/cropped-JAKOB-LERCHE-DAA-NATORP.png"/>
/* And a div container with class="elementor" */
CSS
.portfolio {
position: fixed;
width:150px;
height:150px;
margin-top:50px;
margin-bottom:-300px;
margin-left:50px;
}
.elementor {
width: 100vh;
height: 100vw;
overflow-x: scroll;
overflow-y: scroll;
transform: rotate(-90deg) translateX(-100vh);
transform-origin: top left;
-ms-overflow-style: none;
}
JS
var element = document.getElementsByClassName("elementor")[0]
var elem = document.getElementById("rotatelogo");
element.addEventListener('scroll', function() {
var value = element.scrollY * 0.25;
elem.style.transform = `translatex(-50%) translatey(-50%) rotate(${value}deg)`;
});
Edit: I changed the code and it works now. I replaced the "scrollY" with "scrollTop". My new JS looks like this:
var element = document.getElementsByClassName("elementor")[0]
var elem = document.getElementById("rotatelogo");
element.addEventListener('scroll', function() {
var value = element.scrollTop * 0.25;
elem.style.transform = `translatex(-50%) translatey(-50%) rotate(${value}deg)`;
});
If I understand it right, you could select the element you'r adding an event to.
Something like :
const scrollDiv = document.querySelector(".scrollOnMe");
scrollDiv.addEventListener("wheel", () => {
console.log("Scrolling !");
})
div {
height: 30px;
}
.scrollOnMe {
background-color: green;
}
.foo {
background-color: red;
}
<div class="scrollOnMe">Scroll on me !</div>
<div class="foo">Don't :(<div>
I want my navbar to be transparent, but when the user scrolls a bit I want it to change to a solid color and I am using bootstrap for the navbar, I have done the code that is needed with javascript.
I had this javascript in my HTML file, but it doesn't seems to work and I don't really know why
<script>
var myNav = document.getElementById("mynav");
window.onscroll = function() {
use strict";
if (document.body.scrollTop >= 100) {
myNav.classList.add("scroll");
} else {
myNav.classList.remove("scroll");
}
};
</script>
and I have also added the CSS code.
.scroll {
background-color: transparent !important;
transition: all 0.5s ease-in;
}
I don't know why it doesn't work, it is not displaying any errors, I have also manually put the class and it worked so the problem is from the js code and not the CSS.
Use scrollY property of Window object.
See the Snippet below:
var myNav = document.getElementById("mynav");
window.onscroll = function() {
if (window.scrollY >= 100) {
myNav.classList.add("scroll");
} else {
myNav.classList.remove("scroll");
}
};
.scroll {
background-color: transparent !important;
transition: all 0.5s ease-in;
}
.main-container{
height: 1000px;
}
#mynav{
position: fixed;
background-color: gray;
height: 50px;
margin:0 auto;
top: 0;
bottom:0;
line-height: 50px;
padding:5px;
width: 100%;
}
<div class="main-container">
<div class="mynav" id="mynav">
Hello World! this is mynav
</div>
</div>
Try using window.scrollY instead of document.body.scrollTop.
if (window.scrollY >= 100)
You can also use document.documentElement.scrollTop. It's the html element that actually scrolls, not the body. Typically document.body.scrollTop will always be 0.
Background: I am using a snippet of JQuery to assign an event to an element based on its ID. That event slides a menu from the left side of the screen.
Question: When the screen size changes to < 710px I am going to hide the original element and show a new element (which is just a different icon). But I want that new element to trigger the same event.
Should I just assign the event to both elements one after another or can I combine that into one Event?
Below is an example of my HTML JS and CSS
PLEASE NOTE THE TRIGGER WILL NOT WORK UNLESS THE TEST WINDOW IS ABOVE 711PX
window.onload = function(){
document.getElementById('megga-nav-toggle').addEventListener('click', function () {
var documentBody = $('#megga-global-menu');
documentBody.toggleClass('is-active');
if (documentBody.hasClass('hide-megga')) {
documentBody.removeClass('hide-megga');
return;
}
documentBody.addClass('hide-megga');
});
document.getElementById("megga-global-menu").addEventListener("mouseleave", menuHide);
};
function menuHide() {
document.getElementById("megga-global-menu").classList.add('hide-megga');
}
#megga-global-menu {
background: red ;
position: fixed;
top: 50px;
bottom: 0;
left:0px;
width: 200px;
z-index: 1000000;
transition: ease all .6s;
}
#megga-global-menu.hide-megga {
left: -200px;
transition: ease all .6s;
}
#megga-nav-toggle {
display: inline-block;
z-index:999998;
font-size: 30px;
color: #000;
cursor: pointer;
}
#media screen and (min-width: 710px) {
#megga-navmobile-toggle {
display:none;
}
}
#media screen and (max-width: 710px) {
#megga-nav-toggle {
display:none;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<span id="megga-nav-toggle">FULL SCREEN</span><Bn/><Br/>
<span id="megga-navmobile-toggle">MOBILE SCREEN</span>
<div id="megga-global-menu" class="">
My slide out menu goes here!
</div>
I'm not sure I understand your problem, but if you want just show different icon based on screen size, why not put both of them in the same element and display the wanted icon with #media?
#media screen and (min-width: 710px) {
#megga-navmobile-toggle-icon { display: none; }
}
#media screen and (max-width: 710px) {
#megga-nav-toggle-icon { display: none; }
}
And your html should be:
<div id="megga-nav-toggle">
<span id="megga-nav-toggle-icon">FULL SCREEN</span><Bn/><Br/>
<span id="megga-navmobile-toggle-icon">MOBILE SCREEN</span>
</div>
The problem with my slider is that when it gets to the last slide and i click next it jumps over the two slides to get to the first one. Similarly when i am on the first slide and click previous, it jumps over slides to get to the last one. I would like to make it that when i get to the last slide and click NEXT the first slide would come from the right to left. (similar concept for the PREVIOUS button on first slide). I tried using insertBefore() and appendChild() for the slides but couldn't figure it out...
Here is my code:
// Slider
const slider_wrapp = document.querySelector('.tract-slider');
const slider = document.querySelector('.tract-slider-wrapp');
var slide = document.getElementsByClassName('tract-slide');
const leftBtn = document.querySelector('.slide-left');
const rightBtn = document.querySelector('.slide-right');
let swWidth = slider_wrapp.clientWidth;
let sliderWidth = swWidth * slide.length;
let slideWidth = 0;
slider.style.width = sliderWidth + "px";
for (var i = 0; i < slide.length; i++) {
slide.item(i).style.width = swWidth + "px";
}
function moveRight() {
slideWidth === sliderWidth - swWidth ? slideWidth = 0 : slideWidth += swWidth;
slider.style.transform = "translateX(" + (-slideWidth) + "px)";
}
function moveLeft() {
slideWidth === 0 ? slideWidth = sliderWidth - swWidth : slideWidth -= swWidth;
slider.style.transform = "translateX(" + (-slideWidth) + "px)";
}
rightBtn.addEventListener("click", function() {
moveRight();
});
leftBtn.addEventListener("click", function() {
moveLeft();
});
.tract-slider {
width: 100%;
height: 75vh;
position: relative;
overflow: hidden;
}
.tract-slider-wrapp {
height: 100%;
position: relative;
-webkit-transition: all 350ms cubic-bezier(.08, .13, 0, .81);
-o-transition: all 350ms cubic-bezier(.08, .13, 0, .81);
transition: all 350ms cubic-bezier(.08, .13, 0, .81);
}
.tract-slide {
height: 100%;
float: left;
position: relative;
display: block;
background-position: center;
-webkit-background-size: cover;
background-size: cover;
}
.tract-slide:nth-child(1) {
background-image: url("https://static.pexels.com/photos/126282/pexels-photo-126282.jpeg");
}
.tract-slide:nth-child(2) {
background-image: url("https://static.pexels.com/photos/29017/pexels-photo-29017.jpg");
}
.tract-slide:nth-child(3) {
background-image: url("https://static.pexels.com/photos/70760/dandelion-dandelion-seeds-taraxacum-fluffy-70760.jpeg");
}
.tract-slider-control {
position: absolute;
left: 0;
bottom: 0;
background: #ffffff;
padding: 1em;
}
.tract-slider-btn {
display: inline-block;
cursor: pointer;
margin-left: 1em;
}
.tract-slider-btn:nth-child(1) {
margin-left: 0;
}
<div class="tract-slider">
<div class="tract-slider-wrapp">
<div class="tract-slide"></div>
<div class="tract-slide"></div>
<div class="tract-slide"></div>
</div>
<div class="tract-slider-control">
<div class="tract-slider-btn slide-left">Prev</div>
<div class="tract-slider-btn slide-right">Next</div>
</div>
</div>
PS. Please use JavaScript for solution
Creating an infinite slider means you need to move your slides around in DOM so they give the impression of a continuous track.
The first thing you need to change is having their backgrounds tied up to their position in DOM. If we want to slide back from first slide to the last one, we need to take the last slide, prepend it before the first one but, considering your current CSS, that will change the backgrounds of all slides, as they are currently bound to their position in DOM (...:nth-child {background-image:...}...).
The second thing that needs changing is positioning the slides into the slider track. If they're floated, whenever we change their order, all the rest of the slides will be affected. By positioning them with position:absolute each slide moves independently, without affecting the others, so it's easier to rearrange them while keeping control.
Long story short, I started from scratch and placed all methods inside a single object: theSlider.
The reset() function does the heavy lifting: it puts before class on first element, current on second and after on all the rest. So you have to put the "last" slide first, because the slider will start with it appended before the "current" one.
The sliding is done by applying go-left and go-right classes to the track. After the transition is done, I just move the first/last slide into the new position, depending on case, and run reset() again (which strips all classes and reapplies them based on new positions).
Animations are handled by CSS. All JavaScript does is apply/remove classes and move the slides in DOM.
var theSlider = {
track : document.querySelector('.tract-slider-wrapp'),
// has to match `transition-duration` in CSS:
duration : 600,
reset : function() {
var slides = document.querySelectorAll('.tract-slider-wrapp > div');
for (var i = 0; i < slides.length; i++) {
slides[i].className = '';
slides[i].classList.add(i > 1? 'after' : (i ? 'current':'before'))
}
},
init : function() {
theSlider.reset();
theSlider.track.classList.remove('not-loaded')
},
next : function() {
theSlider.track.classList.add('go-right');
setTimeout(function(){
var firstSlide = document.querySelector('.tract-slider-wrapp > div:first-child');
theSlider.track.appendChild(firstSlide);
theSlider.reset();
theSlider.track.classList.remove('go-right')
},theSlider.duration)
},
prev : function() {
theSlider.track.classList.add('go-left');
setTimeout(function() {
var lastSlide = document.querySelector('.tract-slider-wrapp > div:last-child');
theSlider.track.insertBefore(lastSlide, theSlider.track.firstChild);
theSlider.reset();
theSlider.track.classList.remove('go-left')
},theSlider.duration)
},
prevButton : document.querySelector('.slide-left'),
nextButton : document.querySelector('.slide-right')
};
window.addEventListener("load", theSlider.init);
theSlider.prevButton.addEventListener('click', theSlider.prev);
theSlider.nextButton.addEventListener('click', theSlider.next);
.tract-slider {
width: 100%;
height: 75vh;
position: relative;
overflow: hidden;
background-color: #f5f5f5;
}
.tract-slider-wrapp {
height: 100%;
transition: all 350ms cubic-bezier(.08, .13, 0, .81);
opacity: 1;
}
.tract-slider-wrapp.not-loaded {
opacity: 0;
}
.tract-slider-wrapp>div {
height: 100%;
position: absolute;
background: transparent no-repeat 50% 50% /cover;
width: 100%;
}
.tract-slider-wrapp > div.before {
margin-left: -100%;
}
.tract-slider-wrapp > div.current + div {
margin-left: 100%;
}
.tract-slider-wrapp > div.after ~ div {
opacity: 0;
}
.tract-slider-control {
position: absolute;
width: 100%;
z-index: 1;
top: 50%;
display: flex;
justify-content: space-between;
transform: translateY(-50%);
}
.tract-slider-control div {
background-color: rgba(0,0,0,.35);
padding: .5rem 1rem;
color: white;
cursor: pointer;
}
.tract-slider-control :first-child {
border-radius: 0 17px 17px 0;
}
.tract-slider-control :last-child {
border-radius: 17px 0 0 17px;
}
body {
margin: 0;
}
.go-right div {
transform: translateX(-100%);
}
.go-left div {
transform: translateX(100%);
}
.go-right div, .go-left div {
transition-property: transform;
transition-timing-function: cubic-bezier(.4,0,.2,1);
/* has to match `duration` in js: */
transition-duration: 600ms;
}
<div class="tract-slider">
<div class="tract-slider-wrapp not-loaded">
<div style="background-image:url('https://static.pexels.com/photos/126282/pexels-photo-126282.jpeg')"></div>
<div style="background-image:url('https://static.pexels.com/photos/29017/pexels-photo-29017.jpg')"></div>
<div style="background-image:url('https://static.pexels.com/photos/70760/dandelion-dandelion-seeds-taraxacum-fluffy-70760.jpeg')"></div>
</div>
<div class="tract-slider-control">
<div class="tract-slider-btn slide-left">Prev</div>
<div class="tract-slider-btn slide-right">Next</div>
</div>
</div>
If you want to change the animation duration you need to change it in both js and css.
The only current limitation is it needs at least 3 slides to work. I guess it could be adjusted to work with only two slides by: cloning the "inactive" slide into third position, removing the clone after transition and cloning the other one.
ToDo's:
prefix CSS so it works in more browsers
replace .classList.add('whatever') with .className += ' whatever' and
.classList.remove('whatever') with .className.replace('whatever', '') if you want to show IE some love.
I told the above just to tell you this: if you want to get going, don't reinvent the wheel.
It's great you use vanilla javascript. But sooner or later you'll end up writing your own wrappers for common things. Depending on how good you are/have become, you'll write your own, limited, custom version of jQuery. Allow me to put things into perspective: Google included a lite version of jQuery into AngularJS. It's that good.
You, as an single developer, do not stand a chance at writing a better, more streamlined and tested version of it. And besides, you don't have to. Use your skill and abilities to go forward, not sideways.
I have a page which i need to dim a certain area (div) instead of the entire page. How can I achieve this?
I have googled some answer but all of them is about dimming the whole page. Below is the sample code that I got but it dimmed the entire page.
<div id="dimmer"></div>
#dimmer
{
background:#000;
opacity:0.5;
position:fixed; /* important to use fixed, not absolute */
top:0;
left:0;
width:100%;
height:100%;
display:none;
z-index:9999; /* may not be necessary */
}
It covered the whole page because you set the width and height to 100%. If you were to make it 100px or 50%, that would work, but if you set it to 100%, it will cover 100% of the page.
.area-to-dim {
position: relative;
}
.dimmer {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
}
HTML
<div class="area-to-dim">
<div class="dimmer"></div>
</div>
Two ways, one really simple but I'm not 100% sure this is what you wanted.
First way, use CSS
.genericClassGivenToDivs, #idOfDiv {
background:#fff;
}
/* on mouse over, change the background colour */
.genericClassGivenToDivs:hover, #idOfDiv:hover {
background:#aaa;
}
The second way is more complex. Basically, reposition a div using javascript on mouse over. This requires some CSS and javascript. The following could be a lot cleaner with some work.
<html>
<head>
<style>
body {
margin:1em;
background:#ddd;
}
#contain {
margin:auto;
width:100%;
max-width:720px;
text-align:center;
}
#row1, #row2, #row3 {
width:100%;
height:48px;
line-height:48px;
color:#000;
background:#fff;
}
#row2 {
background:#eee;
}
#dim {
position:absolute;
top:0px;
left:0px;
width:100%;
height:100%;
background:rgba(0,0,0,0.5);
display:none;
}
</style>
</head>
<body>
<div id="contain">
<div id="row1">Row 1</div>
<div id="row2">Row 2</div>
<div id="row3">Row 3</div>
</div>
<div id="dim"></div>
<script>
var dimEl = document.getElementById('dim');
function over() {
//console.log('over:['+ this.id +']');
dimEl.style.top = this.offsetTop +'px';
dimEl.style.left = this.offsetLeft +'px';
dimEl.style.height = this.offsetHeight +'px';
dimEl.style.width = this.offsetWidth +'px';
dimEl.style.display = 'block';
}
window.onload = function() {
var list = ['row1', 'row2', 'row3'];
var e;
for(x in list) {
e = document.getElementById(list[x]);
if (e) {
e.onmouseover = over;
}
}
}
</script>
</body>
</html>
Not entirely sure what "dimming a certain area" means, but I recently created a solution that might be applicable in some extent.
I had a div with a background image and some overlaid text, and the background (but not the text) should darken slightly on mouse over.
I solved it by having two containers and a textfield, so that the outermost div had the background image, the inner div expanded to 100% height and width and had a transparent black solid-color background, and then there was some text in that div.
Then, simply, on hover, I change the inner div background-color from rgba(0, 0, 0, 0) to rgba(0, 0, 0, .3), dimming the background image.
If this sounds applicable, see this jsFiddle
Why the display is none?
Check this?
#dimmer {
background: #111;
top: 0;
left: 0;
width: 100px;
height: 100px;
z-index: 9999;
/* may not be necessary */
}
#dimmer:hover {
background: #000;
opacity: 0.5;
transition: opacity 1s ease;
cursor: pointer;
}
<div id="dimmer">ok</div>