I am trying to make a message appear if the user doesn't scroll for specific amount of time and then make the text fade out as soon as the user scroll. What I have tried so far is not working.
I am looking for vanilla javascript solutions only.
thank you for your help.
// make scroll button appear ---------------
var scrollText = document.getElementById("scrollMsg");
function showMsg() {
scrollText.className = "show";
}
setTimeout(showMsg, 2000);
// make scroll button fadout ---------------
function scrollHide() {
var scrollText2 = document.querySelector("#scrollMsg.show");
var scrllTPosition = scrollText2.getBoundingClientRect().top;
var screenPosition = window.innerHeight / 0.5;
if (scrllTPosition < screenPosition) {
scrollText2.classList.add("scrollHide");
}
}
window.addEventListener("scroll", scrollHide);
#scrollMsg {
height: auto;
position: sticky;
bottom: 175px;
z-index: 1;
opacity: 0;
-webkit-transition: opacity 0.7s;
-moz-transition: opacity 0.7s;
transition: opacity 0.7s;
}
#scrollMsg.show {
opacity: 1;
-webkit-transition: opacity 0.7s ease-in-out;
-moz-transition: opacity 0.7s ease-in-out;
transition: opacity 0.7s ease-in-out;
}
#scrollhide {
opacity: 0;
-webkit-transition: opacity 0.7s ease-in-out;
-moz-transition: opacity 0.7s ease-in-out;
transition: opacity 0.7s ease-in-out;
}
<p id="scrollMsg">scroll</p>
I've added some large divs to allow us to scroll through the document.
// make scroll button appear ---------------
var scrollText = document.getElementById("scrollMsg");
window.addEventListener('scroll', (e) => {
console.log('user scrolled!')
scrollText.style.opacity = 0
});
#scrollMsg {
opacity: 1;
transition: opacity 1s;
}
<div style="height:100px"></div>
<p id="scrollMsg">scroll</p>
<div style="height:4000px"></div>
Related
I tried this way of code to save menu state when refresh and user can expand and close the menu but go some problems
javascript functions used to togglesidebar open/close menu
function toggleSidebar(){
if(!document.readyState === 'complete') {
return;
}
toggleElements();
if ($('.collapseSidebar').length > 0) {
upSizeSidebar();
} else {
collapseSidebar();
}
};
function toggleElements(){
$('.site-menubar-footer').toggle();
$('.site-menu-title').toggle();
$('.navbar-header').find('.fa-bars').toggle();
$('.navbar-header').find('.fa-chevron-left').toggle();
};
function collapseSidebar(){
localStorage.setItem('collapsed', 'true');
$(".site-menubar").removeClass("upSizeSidebar");
$(".site-menubar").addClass("collapseSidebar");
$("#layout_new").css("margin-left", "75px");
};
function upSizeSidebar(){
localStorage.setItem('collapsed', 'false');
$(".site-menubar").removeClass("collapseSidebar");
$(".site-menubar").addClass("upSizeSidebar");
$("#layout_new").css("margin-left", "290px");
};
function setMenuState(){
var menuState = localStorage.getItem('collapsed')
if (menuState !== null && menuState === 'true') {
toggleElements();
collapseSidebar();
}
};
function activateMenuToggleButtons(){
$('.navbar-header').find('.fa-chevron-left').css('pointer-events', 'auto');
$('.navbar-header').find('.fa-bars').css('pointer-events', 'auto');
};
document.addEventListener("DOMContentLoaded", function(){
activateMenuToggleButtons();
setMenuState();
});
CSS used for transition when open/close menu
.collapseTransition {
-moz-transition: width 0.2s ease-in-out, left 0.2s ease-in-out;
-webkit-transition: width 0.2s ease-in-out, left 0.2s ease-in-out;
-moz-transition: width 0.2s ease-in-out, left 0.2s ease-in-out;
-o-transition: width 0.2s ease-in-out, left 0.2s ease-in-out;
transition: width 0.2s ease-in-out, left 0.2s ease-in-out;
}
.collapseSidebar {
width: 45px !important;
}
.upSizeSidebar {
width: 260px !important;
}
Sometimes when clicking to open close and refreshing this occur
I am starting to use the IntersectionObserver API and could create some basic animations, which includes hiding and appearing of elements. However, once a person wants to scroll back to the top, the elements which disappeared by one of the triggers are not getting visible again.
My Solution so far
So I thought I might create another test variable within the intersection observer callback function (the stepI and stepII variable in my code), which checks if the callback function was previously triggered. If so, instead of disappearing the elements, let them appear again.
My current problem
So let's say a background image (id="hiddenImg") should appear when the first text block (id="I") passes the 50% border of the viewport and it disappears when the second text block (id="II") enters this area. Even though the image is getting visible again when scrolling back up, if the user does not scroll back completely (so that the second text block goes out of the viewport) and then scrolls back to the bottom, the disappearing trigger of that second text block is not called. This would mean that the background image would stay visible, which it shouldn't.
Here is the js part:
var stepI = false;
var stepII = false;
// list of options
let options = {
rootMargin: '0px 0px -50%' //WHEN reaching half of the viewport
};
// instantiate a new Intersection Observer
"use strict";
var intersectionObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (change) {
if (change.isIntersecting) {
if (change.target.id == "I") {
$("#hiddenImg").removeClass("hidden_img");
$("#hiddenImg").addClass("visible_img");
stepI = true;
observer.unobserve(change.target);
}
if (change.target.id == "II") {
if (stepII == false) {
$("#hiddenImg").removeClass("visible_map");
$("#hiddenImg").addClass("hidden_map");
stepII = true
} else {
$("#hiddenImg").removeClass("hidden_map");
$("#hiddenImg").addClass("visible_map");
stepII = false;
}
}
}
});
},options);
// list of paragraphs
let elements = document.querySelectorAll(".stepper");
for (let elm of elements) {
intersectionObserver.observe(elm);
}
Here is my complete code:
<html>
<head>
<!-- Load the polyfill. -->
<script src="/js/intersection-observer.js"></script>
<script src='https://unpkg.com/intersection-observer#0.5.0/intersection-observer.js'></script>
</head>
<body>
<style>
.intro-imgs {
display: block;
margin: 0 auto; /* Will not center vertically and won't work in IE6/7. */
left: 0;
right: 0;
position: fixed;
position: expression(fixed);
}
.hidden_img {
visibility: hidden;
opacity: 0;
-ms-transform: scaleX(0); /* IE 9 */
-webkit-transform: scaleX(0); /* Safari 3-8 */
-o-transform: scaleX(0);
-moz-transform: scaleX(0);
transform: scaleX(0);
-webkit-transition: visibility 0s 0.5s, opacity 0.5s linear, -webkit-transform 0.5s;
-moz-transition: visibility 0s 0.5s, opacity 0.5s linear, -moz-transform 0.5s;
-o-transition: visibility 0s 0.5s, opacity 0.5s linear, -o-transform 0.5s;
transition: visibility 0s 0.5s, opacity 0.5s linear, transform 0.5s;
}
.visible_img {
visibility: visible;
opacity: 1;
-ms-transform: scaleX(1); /* IE 9 */
-webkit-transform: scaleX(1); /* Safari 3-8 */
-o-transform: scaleX(1);
-moz-transform: scaleX(1);
transform: scaleX(1);
-webkit-transition: opacity 0.5s linear, -webkit-transform 0.5s;
-moz-transition: opacity 0.5s linear, -moz-transform 0.5s;
-o-transition: opacity 0.5s linear, -o-transform 0.5s;
transition: opacity 0.5s linear, transform 0.5s;
}
.stepper{
max-width: 70rem;
margin: 550px auto 600px auto;
width: 90%;
background-color: rgba(248, 248, 248, 0.95);
font-family: "Helvetica";
font-size: 17px;
line-height: 26px;
padding: 15px;
}
</style>
<!--HTML-->
<div class="headline">
<img id="hiddenImg" class="hidden_img intro-imgs" src="https://image.shutterstock.com/image-photo/funny-portrait-hero-260nw-410898763.jpg" >
</div>
<div id="I" class="stepper">
<p>Lorem Ipsum</p>
</div>
<div id="II" class="stepper">
<h1>THE HEADLINE</h1>
</div>
<!-- SCRIPT-->
<script>
var stepI = false;
var stepII = false;
// list of options
let options = {
rootMargin: '0px 0px -50%' //WHEN reaching half of the viewport
};
// instantiate a new Intersection Observer
"use strict";
var intersectionObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (change) {
if (change.isIntersecting) {
if (change.target.id == "I") {
$("#hiddenImg").removeClass("hidden_img");
$("#hiddenImg").addClass("visible_img");
stepI = true;
observer.unobserve(change.target);
}
if (change.target.id == "II") {
if (stepII == false) {
$("#hiddenImg").removeClass("visible_map");
$("#hiddenImg").addClass("hidden_map");
stepII = true
} else {
$("#hiddenImg").removeClass("hidden_map");
$("#hiddenImg").addClass("visible_map");
stepII = false;
}
}
}
});
},options);
// list of paragraphs
let elements = document.querySelectorAll(".stepper");
for (let elm of elements) {
intersectionObserver.observe(elm);
}
</script>
</body>
I've implemented ngAnimate into a project to help with animations, but I'm getting really odd behaviour with a certain element.
To add some background, we have a shop with categories and products inside the categories. I'm doing an ng-repeat with: data-ng-repeat="product in currentProductCategory.Products" and I have data-ng-class="{ 'open': product.ShowDetails == true }" on my root element.
My root element also has an id of product-{{product.Id}}-{{currentProductCategory.Id}} and I have a child element with id product-options-{{product.Id}}-{{currentProductCategory.Id}} which products expected results.
When clicking a button, I call a function that sets the max-height on the parent element to a desired height, and the animation is handled in the CSS. Here's the function code:
var reg = /\d+/g;
var productParentElement = $('#product-' + product.Id + '-' + $scope.currentProductCategory.Id);
var optionsElement = $('#product-options-' + product.Id + '-' + $scope.currentProductCategory.Id);
var productParentPaddingTop = parseInt(productParentElement.css("padding-top").match(reg));
var productParentPaddingBottom = parseInt(productParentElement.css("padding-bottom").match(reg));
var productParentTotalHeight = productParentPaddingTop + productParentPaddingBottom + productParentElement.height() + optionsElement.height();
var optionsElementPaddingTop = parseInt(optionsElement.css("padding-top").match(reg));
var optionsElementPaddingBottom = parseInt(optionsElement.css("padding-bottom").match(reg));
var optionsElementTotalHeight = optionsElementPaddingTop + optionsElementPaddingBottom + optionsElement.height();
var totalHeight = productParentTotalHeight + optionsElementTotalHeight;
if (product.ShowDetails) {
product.ShowDetails = true;
productParentElement.css("max-height", totalHeight);
} else {
product.ShowDetails = false;
productParentElement.removeAttr('style');
}
And my CSS for the closed and open classes:
Closed:
.products-list .product {
margin-bottom: 20px;
max-height: 200px;
overflow: hidden;
-moz-transition: max-height 2s ease;
-o-transition: max-height 2s ease;
-webkit-transition: max-height 2s ease;
transition: max-height 2s ease;
}
Open:
.products-list .product.open {
-moz-transition: max-height 2s ease;
-o-transition: max-height 2s ease;
-webkit-transition: max-height 2s ease;
transition: max-height 2s ease;
max-height: 200px;
}
The issue is that out of the many products over 4 categories, the same one which is the same product in each category is not animating open. It animates the close/shrink, but when opening, it just instantly appears open.
This has been gating on us for a long time now and it's becoming a real issue, any help is greatly appreciated.
UPDATE: Now none of the "products" will animate open, but they do animate closed. Could this be because I'm setting the max-height on the style rather than a class?
Sorry but this might sound like I am pointing out the obvious and I can't see the rest of your code but in your CSS, you have;
.products-list .product {
margin-bottom: 20px;
max-height: 200px;
overflow: hidden;
-moz-transition: max-height 2s ease;
-o-transition: max-height 2s ease;
-webkit-transition: max-height 2s ease;
transition: max-height 2s ease;
}
for your closed list which has a 'max-height: 200px' but is also the same in your open list;
.products-list .product.open {
-moz-transition: max-height 2s ease;
-o-transition: max-height 2s ease;
-webkit-transition: max-height 2s ease;
transition: max-height 2s ease;
max-height: 200px;
}
Which also has a max-height of 200px. So in this case you're asking it to transition from 200px to 200px. try changing the height of open classes to be bigger or smaller. Then it will transition.
I am looking for a native JS solution to toggle div display using display:'none' and display:'block' properties. I have the first part done. I only need the part to do a simple fadeIn and fadeOut animation.
I need to use native JS and display:block,none.
var e = document.getElementById('calendarPickerContainer');
if (e.className == 'visible') {
e.className = 'hidden';
} else {
e.className = 'visible';
}
need to adapt to this css
.visible{
display:block;
}
.hidden {
display:none;
}
If you wanna use a pure JavaScript fadeIn and fadeOut, try this:
transition: opacity 1s linear;
This is a pure CSS method.
#cont {-webkit-transition: opacity 1s linear; -o-transition: opacity 1s linear; transition: opacity 1s linear;}
#cont.hidden {opacity: 0;}
<button onclick="cont.classList.add('hidden'); setTimeout('cont.style.display=\'none\'', 1000);">Click</button>
<div id="cont">
Hello
</div>
Working Snippet (includes toggle):
#cont {-webkit-transition: opacity 1s linear; -o-transition: opacity 1s linear; transition: opacity 1s linear; opacity: 1;}
#cont.hidden {opacity: 0; -webkit-transition: opacity 1s linear; -o-transition: opacity 1s linear; transition: opacity 1s linear;}
<button onclick="if (cont.style.display != 'none') { cont.classList.add('hidden'); setTimeout('cont.style.display=\'none\'', 1000); } else {cont.style.display='block'; setTimeout('cont.classList.remove(\'hidden\')', 10);}">Click</button>
<div id="cont">
Hello
</div>
You can achieve this easily with CSS3
.visible {
visibility: visible;
opacity: 1;
transition: opacity 2s linear;
}
.hidden {
visibility: hidden;
opacity: 0;
transition: visibility 0s 2s, opacity 2s linear;
}
Native JS fade function:
var s = document.getElementById('calendarPickerContainer').style;
s.opacity = 1;
(function fade(){(s.opacity-=.1)<0?s.display="none":setTimeout(fade,40)})();
You can simplfy this with classList
document.querySelector('.toggle').addEventListener('click',function(e) {
e.target.classList.toggle('hide');
})
Css:
div {
transition:all 0.3s ease-in;
}
.hide {
opacity: 0;
}
We're using opacity since display cannot be animated.
Example
I'm creating a Website with HTML, CSS, and JavaScript (no jQuery).
I have created the following script to change my Navigation Class when my pageoffset is more than 50 and change it back if its less then 50:
window.onscroll = function (event) {
var nav = document.getElementsByClassName('main-navigation');
var navscr = document.getElementsByClassName('main-navigation-scrolled');
if (window.pageYOffset > 50) {
for(var i = 0; i < nav.length; i++) {
nav[i].className = 'main-navigation-scrolled';
}
}
else {
if (window.pageYOffset < 50) {
for(var i = 0; i < navscr.length; i++) {
navscr[i].className = 'main-navigation';
}
}
}
}
For some reason, when I scroll very slowly or reload the page when my offset is more than 50 only half the li-elements change class.
Maybe there is a smarter solution which also has better performance?
This is my first question, go easy on me please :)
€dit: HTML
<div id="nav-menu-container-fix">
<ul>
<li><a class="main-navigation" href="index.html">Home</a></li>
<li><a class="main-navigation" href="about.html">About</a></li>
<li><a class="main-navigation" href="#">Team</a></li>
<li><a class="main-navigation" href="#">24 Weeks</a></li>
<li><a class="main-navigation" href="#">Donate</a></li>
<li><a class="main-navigation" href="#">Downloads</a></li>
<li><a class="main-navigation" href="#">Forum</a></li>
</ul>
</div>
Aaaaand CSS
a.main-navigation {
padding:18px 15px 15px 15px;
background-color:#222222;
color:#bbbbbb;
display:inline-block;
text-decoration:none;
-webkit-transition: all 600ms ease;
-moz-transition: all 600ms ease;
-ms-transition: all 600ms ease;
-o-transition: all 600ms ease;
transition: all 600ms ease;
}
a.main-navigation:hover {
padding:18px 15px 15px 15px;
background-color:#555555;
color:#ffffff;
display:inline-block;
text-decoration:none;
-webkit-transition: all 600ms ease;
-moz-transition: all 600ms ease;
-ms-transition: all 600ms ease;
-o-transition: all 600ms ease;
transition: all 600ms ease;
}
a.main-navigation-scrolled {
padding:7.5px 15px 7.5px 15px;
background-color:#604D9D;
color:#eeeeee;
display:inline-block;
text-decoration:none;
-webkit-transition: all 600ms ease;
-moz-transition: all 600ms ease;
-ms-transition: all 600ms ease;
-o-transition: all 600ms ease;
transition: all 600ms ease;
}
a.main-navigation-scrolled:hover {
padding:7.5px 15px 7.5px 15px;
background-color:#402c6c;
color:#ffffff;
display:inline-block;
text-decoration:none;
-webkit-transition: all 400ms ease;
-moz-transition: all 600ms ease;
-ms-transition: all 600ms ease;
-o-transition: all 600ms ease;
transition: all 600ms ease;
}
Scroll event will be called hundreds of times while you are scrolling. so you need to perform the actions one and only once when the conditions are matched.
the following will reduce dom accessing
var scrolled = false; // initially page is not scrolled
window.onscroll = function (event) {
if (window.pageYOffset > 50 && !scrolled) { //perform following only if it's not done already
var nav = document.querySelectorAll('main-navigation');
for (var i = 0; i < nav.length; i++) {
nav[i].className = 'main-navigation-scrolled';
scrolled = true; // applied scroll class no need to do this again
}
} else if (window.pageYOffset < 50 && scrolled) { //perform the following only it's not done already
var navscr = document.querySelectorAll('main-navigation-scrolled');
for (var i = 0; i < navscr.length; i++) {
navscr[i].className = 'main-navigation';
scrolled = false; // applied no scroll class, no need to do it again
}
}
}
Update: working fiddle
I don't really know why it didn't work, but I know it works now. I started using jquery and with the following code it works just fine.
$(document).scroll(function () {
if (window.scrollY > 50) {
$(".main-navigation").attr('class', 'main-navigation-scrolled');
} else {
$(".main-navigation-scrolled").attr('class', 'main-navigation');
}
});