I'm having an issue that I'm hoping someone decent at Javascript can help with.
I have this pen:
https://codepen.io/connecteev/pen/ewYNBe
But I want this section to show up at the BOTTOM of the webpage, and only start animating when the section becomes visible on the page (desktop or mobile).
I want to change this pen to:
load this animation only on scrolling down to the section (lazy load)
if possible, use vanilla Javascript, and remove the extraneous libraries like:
https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/TweenMax.min.js
https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/plugins/CSSRulePlugin.min.js
Code:
HTML:
<div class="content">
</div>
<div class="Container">
<ul class="BlogList">
<li class="ArticleTeaser">
<h3 class="ArticleTeaser-title">PolyNo?</h3>
<div class="ArticleTeaser-bubble"></div>
<div class="ArticleTeaser-date">November 15th, 2015</div>
</li>
<li class="ArticleTeaser">
<h3 class="ArticleTeaser-title">BoomQueries - Element Queries, Today</h3>
<div class="ArticleTeaser-bubble"></div>
<div class="ArticleTeaser-date">April 24th, 2015</div>
</li>
<li class="ArticleTeaser">
<h3 class="ArticleTeaser-title">Reference SVGs Like the Cool Kids</h3>
<div class="ArticleTeaser-bubble"></div>
<div class="ArticleTeaser-date">October 14th, 2014</div>
</li>
<li class="ArticleTeaser">
<h3 class="ArticleTeaser-title">Modifying SVG Background Fills</h3>
<div class="ArticleTeaser-bubble"></div>
<div class="ArticleTeaser-date">September 29th, 2014</div>
</li>
</ul>
</div>
CSS:
html {
height: 100%;
}
body {
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Open Sans","Helvetica Neue",sans-serif;
letter-spacing: 0;
font-weight: 400;
font-style: normal;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-moz-font-feature-settings: "liga" on;
color: #686868;
font-size: 15px;
line-height: 1.4;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
box-sizing: border-box;
min-height: 100%;
}
body *, body *:before, body *:after {
box-sizing: inherit;
}
.Container {
max-width: 800px;
margin: 0 auto;
padding: 0 16px;
}
.BlogList {
padding: 16px 0;
margin: 0;
list-style: none;
position: relative;
}
#media (max-width: 767px) {
.BlogList {
padding: 32px 0;
}
}
.BlogList:before {
content: '';
position: absolute;
top: 0;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
background: #0177FA;
width: 8px;
height: 8px;
border-radius: 50%;
}
.BlogList:after {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
background: #0177FA;
width: 2px;
}
.ArticleTeaser {
position: relative;
padding: 32px 0;
z-index: 2;
visibility: hidden;
}
#media (max-width: 767px) {
.ArticleTeaser {
text-align: center;
background: #fff;
border-radius: 3px;
padding: 16px;
border: 2px solid #0177FA;
}
.ArticleTeaser:first-child {
margin-top: 16px;
}
.ArticleTeaser + * {
margin-top: 32px;
}
}
#media (min-width: 768px) {
.ArticleTeaser {
display: flex;
align-items: center;
}
.ArticleTeaser:before {
opacity: 0 !important;
}
}
.ArticleTeaser:hover .ArticleTeaser-bubble:before {
background: #0177FA;
}
.ArticleTeaser:last-child:after {
content: '';
position: absolute;
bottom: -16px;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
background: #0177FA;
width: 8px;
height: 8px;
border-radius: 50%;
visibility: visible;
}
#media (max-width: 767px) {
.ArticleTeaser:last-child:after {
bottom: -40px;
}
}
.ArticleTeaser a {
color: #686868;
text-decoration: none;
}
.ArticleTeaser-bubble {
width: 16px;
height: 16px;
border-radius: 50%;
background: #fff;
border: 2px solid #0177FA;
-webkit-transform-origin: 50% 50%;
transform-origin: 50% 50%;
position: relative;
z-index: 1;
}
.ArticleTeaser-bubble:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #fff;
border-radius: 50%;
transition: background 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
z-index: 1;
}
#media (min-width: 768px) {
.ArticleTeaser-bubble:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
width: 32px;
height: 2px;
background: rgba(1, 119, 250, 0.25);
z-index: -1;
}
}
#media (max-width: 767px) {
.ArticleTeaser-bubble {
position: absolute;
top: 0;
left: 50% !important;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
}
.ArticleTeaser-title {
margin: 0;
}
#media (min-width: 768px) {
.ArticleTeaser-title {
margin: 0 32px 0 0;
text-align: right;
width: 200px;
}
}
#media (min-width: 768px) {
.ArticleTeaser-date {
color: #a8a8a8;
margin: 0 0 0 32px;
width: 200px;
}
}
JS:
var optimizedResize = (function() {
var callbacks = [],
running = false;
// fired on resize event
function resize() {
if (!running) {
running = true;
if (window.requestAnimationFrame) {
window.requestAnimationFrame(runCallbacks);
} else {
setTimeout(runCallbacks, 66);
}
}
}
// run the actual callbacks
function runCallbacks() {
callbacks.forEach(function(callback) {
callback();
});
running = false;
}
// adds callback to loop
function addCallback(callback) {
if (callback) {
callbacks.push(callback);
}
}
return {
// public method to add additional callback
add: function(callback) {
if (!callbacks.length) {
window.addEventListener('resize', resize);
}
addCallback(callback);
}
}
}());
var forEach = function (array, callback, scope) {
for (var i = 0; i < array.length; i++) {
callback.call(scope, i, array[i]); // passes back stuff we need
}
};
var $articles = document.querySelectorAll('.ArticleTeaser');
setTimeout( run, 500 );
// Do the dew
function run() {
forEach($articles, function(index, value) {
articleAnim(value, index);
articleHover(value);
});
}
// Individual teaser animation
function articleAnim(element, count) {
var at = new TimelineMax();
at
.set(element, {
visibility: 'visible'
})
.from(element.querySelector('.ArticleTeaser-bubble'), .5, {
scale: 0,
delay: (count * .75),
ease: Elastic.easeOut.config(1.5, 1)
}, 'article-bubble')
.from(element, .5, {
delay: (count * .75),
opacity: 0,
ease: Elastic.easeOut.config(1.5, 1)
}, 'article-bubble')
.from(element.querySelector('.ArticleTeaser-title'), .5, {
x: '25%',
opacity: 0,
ease: Elastic.easeOut.config(1.5, 1)
}, 'article-teaser')
.from(element.querySelector('.ArticleTeaser-date'), .5, {
x: '-25%',
opacity: 0,
ease: Elastic.easeOut.config(1.5, 1)
}, 'article-teaser');
}
// Hover animation
function articleHover(element) {
var $articleLink = element.querySelector('.ArticleTeaser-title a');
element.timeline = new TimelineMax({ paused: true });
element.timeline
.to(element.querySelector('.ArticleTeaser-bubble'), 0.15, {
scale: 1.25
});
$articleLink.addEventListener('mouseenter', function() {
element.timeline.play();
}, false);
$articleLink.addEventListener('mouseleave', function() {
element.timeline.reverse();
}, false);
}
// Reset transform position for article bubble on resize
optimizedResize.add(function() {
forEach($articles, function(index, value) {
if (window.matchMedia('(min-width: 768px)').matches) {
TweenMax.set(value.querySelector('.ArticleTeaser-bubble'), {
x: '0%',
y: '0%'
});
} else {
TweenMax.set(value.querySelector('.ArticleTeaser-bubble'), {
x: '-50%',
y: '-50%'
});
}
});
});
Dependant on browser support I would suggest Intersection observers if you are looking for a clean vanilla JS approach.
If IE11 is still a requirement there is a reliable polyfill available from W3C.
Hope this helps.
Related
I am working on a project of mine and was playing around with the idea to make a custom cursor for my webpage.
Unfortunately, it seems that I can't get it to work.
Can someone tell me what I am doing wrong here?
I am using simple HTML, CSS and Javascript.
I think it is the Javascript that's not working, but I have tried to use a debugger but no luck.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
* {
box-sizing: border-box;
cursor: none;
}
body {
background: #000;
color: #fff;
}
a {
color: #fff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.custom-cursor {
position: fixed;
top: -18px;
left: -18px;
display: block;
width: 120px;
height: 120px;
pointer-events: none;
will-change: transform;
z-index: 998;
-webkit-transform: matrix(1, 0, 0, 1, -100, -100);
transform: matrix(1, 0, 0, 1, -100, -100);
opacity: 0;
mix-blend-mode: difference;
transition: transform 0.15s cubic-bezier(0, 0.89, 0.49, 0.92),
opacity 0.4s ease;
}
.custom-cursor .cursor {
transform: scale(0.45);
transition: transform 0.5s ease;
will-change: transform;
width: 120px;
height: 120px;
float: left;
border-radius: 100%;
margin-top: -40px;
margin-left: -40px;
background: #fff;
}
.custom-cursor.custom-cursor-active .cursor {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
.custom-cursor.custom-cursor-active-img {
z-index: 1010;
}
.custom-cursor.custom-cursor-active-img .cursor {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
background: #ff0;
}
body:hover .custom-cursor {
opacity: 1;
}
#media screen and (max-width: 1200px) {
.custom-cursor {
display: none !important;
}
}
.center {
padding: 30vh;
text-align: center;
width: 100%;
position: relative;
z-index: 9999;
}
.content {
padding: 1em;
font-family: sans-serif;
font-size: 3em;
background: #000;
min-height: 100vh;
}
.content::before {
position: fixed;
background: #ff0;
mix-blend-mode: multiply;
content: "";
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
pointer-events: none;
}
.img-wrapper {
max-width: 450px;
padding: 100px 0;
}
.img {
position: relative;
z-index: 1000;
}
</style>
</head>
<body>
<div class="content">
<div class="custom-cursor" data-custom-cursor>
<div class="cursor"></div>
</div>
<h1>hello world</h1>
link 0 / link 1 /
link 2 / link 3 /
link 4 / link 5 /
link 6 / link 7 /
link 8 .
</div>
<script>
const cursor = document.querySelector(".cursor");
document.addEventListener("mousemove", (e) => {
cursor.setAttribute(
"style",
"top: " + (e.pageY - 10) + "px; left: " + (e.pageX - 10) + "px;"
);
});
var $c = $("[data-custom-cursor]");
var $h = $("a, button");
var $i = $("img");
$(window).on("mousemove", function (e) {
x = e.clientX;
y = e.clientY;
console.log(x, y);
$c.css("transform", "matrix(1, 0, 0, 1, " + x + "," + y + ")");
});
$h.on("mouseenter", function (e) {
$c.addClass("custom-cursor-active");
});
$h.on("mouseleave", function (e) {
$c.removeClass("custom-cursor-active");
});
$i.on("mouseenter", function (e) {
$c.addClass("custom-cursor-active-img");
});
$i.on("mouseleave", function (e) {
$c.removeClass("custom-cursor-active-img");
});
//# sourceURL=pen.js
</script>
</body>
</html>
The code seems to work (at least, it does things though I don't know if they are the right things) as long as jquery is also loaded.
<html lang="en"><head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
* {
box-sizing: border-box;
cursor: none;
}
body {
background: #000;
color: #fff;
}
a {
color: #fff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.custom-cursor {
position: fixed;
top: -18px;
left: -18px;
display: block;
width: 120px;
height: 120px;
pointer-events: none;
will-change: transform;
z-index: 998;
-webkit-transform: matrix(1, 0, 0, 1, -100, -100);
transform: matrix(1, 0, 0, 1, -100, -100);
opacity: 0;
mix-blend-mode: difference;
transition: transform 0.15s cubic-bezier(0, 0.89, 0.49, 0.92),
opacity 0.4s ease;
}
.custom-cursor .cursor {
transform: scale(0.45);
transition: transform 0.5s ease;
will-change: transform;
width: 120px;
height: 120px;
float: left;
border-radius: 100%;
margin-top: -40px;
margin-left: -40px;
background: #fff;
}
.custom-cursor.custom-cursor-active .cursor {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
.custom-cursor.custom-cursor-active-img {
z-index: 1010;
}
.custom-cursor.custom-cursor-active-img .cursor {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
background: #ff0;
}
body:hover .custom-cursor {
opacity: 1;
}
#media screen and (max-width: 1200px) {
.custom-cursor {
display: none !important;
}
}
.center {
padding: 30vh;
text-align: center;
width: 100%;
position: relative;
z-index: 9999;
}
.content {
padding: 1em;
font-family: sans-serif;
font-size: 3em;
background: #000;
min-height: 100vh;
}
.content::before {
position: fixed;
background: #ff0;
mix-blend-mode: multiply;
content: "";
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
pointer-events: none;
}
.img-wrapper {
max-width: 450px;
padding: 100px 0;
}
.img {
position: relative;
z-index: 1000;
}
</style>
</head>
<body>
<div class="content">
<div class="custom-cursor" data-custom-cursor="" style="transform: matrix(1, 0, 0, 1, 1128, 590);">
<div class="cursor" style="top: 596px; left: 1118px;"></div>
</div>
<h1>hello world</h1>
link 0 / link 1 /
link 2 / link 3 /
link 4 / link 5 /
link 6 / link 7 /
link 8 .
</div>
<script>
const cursor = document.querySelector(".cursor");
document.addEventListener("mousemove", (e) => {
cursor.setAttribute(
"style",
"top: " + (e.pageY - 10) + "px; left: " + (e.pageX - 10) + "px;"
);
});
var $c = $("[data-custom-cursor]");
var $h = $("a, button");
var $i = $("img");
$(window).on("mousemove", function (e) {
x = e.clientX;
y = e.clientY;
console.log(x, y);
$c.css("transform", "matrix(1, 0, 0, 1, " + x + "," + y + ")");
});
$h.on("mouseenter", function (e) {
$c.addClass("custom-cursor-active");
});
$h.on("mouseleave", function (e) {
$c.removeClass("custom-cursor-active");
});
$i.on("mouseenter", function (e) {
$c.addClass("custom-cursor-active-img");
});
$i.on("mouseleave", function (e) {
$c.removeClass("custom-cursor-active-img");
});
//# sourceURL=pen.js
</script>
</body></html>
Note: run the snippet and select full screen mode
I was trying to create an animated hamburger nav menu. The functionality is simple. It will be in a fixed position & incorporate in a circle. When I click that circle the background will overlap the entire screen & nav links will be visible. I have used pseudo-class to create functionality. it works well, but a little mistake appeared. When I clicked the nav links the background should scale to 0. But it is nowhere can be done using CSS. So I used JS click event for it. It worked for the first try after that the menu keep scaled to 0 unit. I need to fix it so that the js click event functionality reset itself on every try. The link is given below.
codepen here
Code-
const navElement = document.querySelector('.navigation__nav');
const navBackground = document.querySelector('.navigation__background');
const navgationList = document.querySelectorAll('.navigation__item');
navgationList.forEach(function(items) {
let x = items;
items.addEventListener('click', closeNav);
function closeNav() {
navElement.style.transform = 'scale(0)';
navBackground.style.transform = 'scale(0)';
}
});
body {
background-color: cyan;
}
.navigation__checkbox {
display: none;
}
.navigation__button {
background-color: #fff;
height: 7rem;
width: 7rem;
position: fixed;
top: 6rem;
right: 6rem;
border-radius: 50%;
z-index: 2000;
box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.1);
text-align: center;
cursor: pointer;
}
#media only screen and (max-width: 56.25em) {
.navigation__button {
top: 4rem;
right: 4rem;
}
}
#media only screen and (max-width: 37.5em) {
.navigation__button {
top: 3rem;
right: 3rem;
}
}
.navigation__background {
height: 6rem;
width: 6rem;
border-radius: 50%;
position: fixed;
top: 6.5rem;
right: 6.5rem;
background-image: radial-gradient(#4ea5f7, #0400ff);
z-index: 1000;
transition: transform 0.8s cubic-bezier(0.86, 0, 0.07, 1);
}
#media only screen and (max-width: 56.25em) {
.navigation__background {
top: 4.5rem;
right: 4.5rem;
}
}
#media only screen and (max-width: 37.5em) {
.navigation__background {
top: 3.5rem;
right: 3.5rem;
}
}
.navigation__nav {
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 1500;
opacity: 0;
width: 0;
transition: all 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.navigation__list {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
list-style: none;
text-align: center;
width: 100%;
}
.navigation__item {
margin: 1rem;
}
.navigation__link:link,
.navigation__link:visited {
display: inline-block;
font-size: 3rem;
font-weight: 300;
padding: 1rem 2rem;
color: #fff;
text-decoration: none;
text-transform: uppercase;
background-image: linear-gradient(120deg, transparent 0%, transparent 50%, #fff 50%);
background-size: 220%;
transition: all .4s;
}
.navigation__link:link span,
.navigation__link:visited span {
margin-right: 1.5rem;
display: inline-block;
}
.navigation__link:hover,
.navigation__link:active {
background-position: 100%;
color: #0400ff;
transform: translateX(1rem);
}
.navigation__checkbox:checked~.navigation__background {
transform: scale(80);
}
.navigation__checkbox:checked~.navigation__nav {
opacity: 1;
width: 100%;
}
.navigation__icon {
position: relative;
margin-top: 3.5rem;
}
.navigation__icon,
.navigation__icon::before,
.navigation__icon::after {
width: 3rem;
height: 2px;
background-color: #333;
display: inline-block;
}
.navigation__icon::before,
.navigation__icon::after {
content: "";
position: absolute;
left: 0;
transition: all .2s;
}
.navigation__icon::before {
top: -.8rem;
}
.navigation__icon::after {
top: .8rem;
}
.navigation__button:hover .navigation__icon::before {
top: -1rem;
}
.navigation__button:hover .navigation__icon::after {
top: 1rem;
}
.navigation__checkbox:checked+.navigation__button .navigation__icon {
background-color: transparent;
}
.navigation__checkbox:checked+.navigation__button .navigation__icon::before {
top: 0;
transform: rotate(135deg);
}
.navigation__checkbox:checked+.navigation__button .navigation__icon::after {
top: 0;
transform: rotate(-135deg);
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Menu</title>
</head>
<body>
<div class="navigation">
<input type="checkbox" class="navigation__checkbox" id="navi-toggle">
<label for="navi-toggle" class="navigation__button">
<span class="navigation__icon"> </span>
</label>
<div class="navigation__background"> </div>
<nav class="navigation__nav">
<ul class="navigation__list">
<li class="navigation__item"><span>01</span> Our Works</li>
<li class="navigation__item"><span>02</span> Features</li>
<li class="navigation__item"><span>03</span> Our Services</li>
<li class="navigation__item"><span>04</span> Blogs</li>
<li class="navigation__item"><span>05</span> Contact Us</li>
<li class="navigation__item"><span>06</span> Know About Author</li>
</ul>
</nav>
</div>
</body>
</html>
[p.s.- comment out the js code first to see the working CSS.]
Although this is for practices hence any help will be a big help for me to understand js and dom.
I reworked a bit your closeNav function in order to get what you want working.
function closeNav(){
navElement.style.transform = 'scale(0)';
navBackground.style.transform = 'scale(0)';
// setTimeout will be useful for resetting our elements once they
// reached scale(0)
setTimeout(() => {
// You can check or uncheck a checkbox in javascript using .checked,
// here in order to set the styles back to normal.
document.querySelector('.navigation__checkbox').checked = false;
// Wait a bit more that the elements have been reset to remove the
// styles given in JS above.
setTimeout(() => {
navElement.style = '';
navBackground.style = '';
}, 500);
}, 1000);
}
You'll need to rework the timeouts so that they exactly meet your transition duration !
The CSS already handles what happens when the checkbox isn't checked. This works fine for me.
function closeNav(){
document.querySelector('.navigation__checkbox').checked = false;
}
I am trying to implement a notification system in my app without the use of a library. Here is a gif of the issue: https://imgur.com/oRc11dM
And here is the jsfiddle of the gif: https://jsfiddle.net/w9yk7n54/
When you click on new notification button, already displayed notifications jump up to make room for the new notification and new notification slides in. I was wondering how I could make it so that they all smoothly go up together.
The notifications wont all be the same dimensions so I cant set static values for height/etc.
Thank you!
let btn = document.querySelector('button')
let container = document.querySelector('.notifications-container')
let notif_contents = [
"<p>1</p><p>1</p><p>1</p><p>1</p>",
"<p>test</p>",
"<div><h1>testtesttest</h1><p>yoloalsdfasdf</p></div>"
]
let current = 0
btn.onclick = () => {
let notif = document.createElement('div')
notif.classList.add('notif')
notif.innerHTML = notif_contents[current]
notif.addEventListener('animationend', () => {
notif.parentElement.removeChild(notif)
})
current++
container.append(notif)
}
* {
box-sizing: border-box;
}
.container {
height: 300px;
width: 400px;
border: 1px solid black;
position: absolute;
}
.notifications-container {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 200px;
background: rgba( 0, 0, 0, 0.2);
display: flex;
flex-flow: column nowrap;
justify-content: flex-end;
overflow: hidden;
}
.notif {
position: relative;
width: 100%;
padding: 10px;
border: 1px solid black;
animation: notifAnim 5s forwards;
transition: all .2s;
background: white;
}
button {
z-index: 100;
background: lightcoral;
color: white;
border: none;
padding: 10px;
font-size: 20px;
margin: 5px;
}
#keyframes notifAnim {
0% {
transform: translateY( 100%)
}
20% {
transform: translateY( 0)
}
80% {
transform: translateY( 0)
}
100% {
transform: translateY( 100%)
}
}
<div class="container">
<button>New Notification</button>
<div class="notifications-container"></div>
</div>
Your notif container has justify-content: flex-end. This means that whenever you add a new one, the previous ones will be pushed up with the height of the new one.
The "fix" is to give each element a negative margin-top equal to its height and integrate in your current transition getting margin-top back to 0.
Example:
let btn = document.querySelector('button'),
container = document.querySelector('.notifications-container'),
notif_contents = [
"<p>1</p><p>1</p><p>1</p><p>1</p>",
"<p>test</p>",
"<div><h1>testtesttest</h1><p>yoloalsdfasdf</p></div>",
"<code>another.test()</code>",
"<strong>another</strong> <i>test</i>"
]
btn.onclick = () => {
let notif = document.createElement('div'),
index = Math.floor(Math.random() * notif_contents.length)
notif.classList.add('notif')
notif.innerHTML = notif_contents[index]
notif.addEventListener('animationend', () => {
notif.parentElement.removeChild(notif)
})
container.append(notif)
notif.style.marginTop = '-' + notif.offsetHeight + 'px'
}
* {
box-sizing: border-box;
}
.container {
height: 300px;
width: 400px;
border: 1px solid #888;
position: absolute;
}
.notifications-container {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 200px;
background: rgba( 0, 0, 0, 0.2);
display: flex;
flex-flow: column nowrap;
justify-content: flex-end;
overflow: hidden;
}
.notif {
position: relative;
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-bottom: none;
animation: notifAnim 5s forwards;
background: white;
}
button {
z-index: 100;
background: lightcoral;
color: white;
border: none;
padding: 10px;
font-size: 20px;
margin: 5px;
}
#keyframes notifAnim {
0%,
100% {
transform: translateY( 100%)
}
20%,
80% {
transform: translateY( 0);
margin-top: 0
}
}
<div class="container">
<button>New Notification</button>
<div class="notifications-container"></div>
</div>
An idea is to insert new element with a height equal to 0 and you animate the height in addition to translate. Of course, you should use max-height since height are unknown and we cannot animate to auto:
let btn = document.querySelector('button')
let container = document.querySelector('.notifications-container')
let notif_contents = [
"<p>1</p><p>1</p><p>1</p><p>1</p>",
"<p>test</p>",
"<div><h1>testtesttest</h1><p>yoloalsdfasdf</p></div>"
]
let current = 0
btn.onclick = () => {
let notif = document.createElement('div')
notif.classList.add('notif')
notif.innerHTML = notif_contents[current]
notif.addEventListener('animationend', () => {
notif.parentElement.removeChild(notif)
})
current++
container.append(notif)
}
* {
box-sizing: border-box;
}
.container {
height: 300px;
width: 400px;
border: 1px solid black;
position: absolute;
}
.notifications-container {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 200px;
background: rgba( 0, 0, 0, 0.2);
display: flex;
flex-flow: column nowrap;
justify-content: flex-end;
overflow: hidden;
}
.notif {
position: relative;
width: 100%;
padding:0 10px;
max-height:0px;
border: 1px solid black;
animation: notifAnim 5s forwards;
transition: all .2s;
background: white;
}
button {
z-index: 100;
background: lightcoral;
color: white;
border: none;
padding: 10px;
font-size: 20px;
margin: 5px;
}
#keyframes notifAnim {
0% {
transform: translateY( 100%);
max-height:0;
padding:0 10px;
}
30% {
transform: translateY( 0);
max-height:300px;
padding:10px;
}
80% {
transform: translateY( 0);
max-height:300px;
padding:10px;
}
100% {
transform: translateY( 100%);
max-height:300px;
padding:10px;
}
}
<div class="container">
<button>New Notification</button>
<div class="notifications-container"></div>
</div>
I watched the tutorial from Traversy Media for a Split Landing Page. (https://www.youtube.com/watch?v=oRmQN244Ir0)
I wanted to tweak the page to have three sections instead of two, but i can't get it done.
It doesn't show the content of the left section. Instead the middle section is overlapping the left, and if i hover over it, the left section transitions into the middle.
Also if i hover over the middle section, no transition at all is being performed.
const left = document.querySelector('.left');
const middle = document.querySelector('.middle');
const right = document.querySelector('.right');
const container = document.querySelector('.container');
left.addEventListener('mouseenter', () => {
container.classList.add('hover-left');
});
left.addEventListener('mouseleave', () => {
container.classList.remove('hover-left');
});
middle.addEventListener('mouseenter', () => {
container.classList.add('hover-middle');
});
middle.addEventListener('mouseleave', () => {
container.classList.remove('hover-middle');
});
right.addEventListener('mouseenter', () => {
container.classList.add('hover-right');
});
right.addEventListener('mouseleave', () => {
container.classList.remove('hover-right');
});
:root {
--container-bg-color: #333;
--left-bg-color: rgba(223, 39, 39, 0.7);
--left-button-hover-color: rgba(161, 11, 11, 0.3);
--middle-bg-color: #ededed;
--middle-button-hover-color: #ffba00;
--right-bg-color: rgba(43, 43, 43, 0.8);
--right-button-hover-color: rgba(92, 92, 92, 0.3);
--hover-width: 66%;
--other-width: 16.5%;
--speed: 1000ms;
}
html,
body {
padding: 0;
margin: 0;
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
width: 100%;
height: 100%;
overflow-x: hidden;
}
h1 {
font-size: 4rem;
color: #fff;
position: absolute;
left: 50%;
top: 20%;
transform: translateX(-50%);
white-space: nowrap;
}
.button {
display: block;
position: absolute;
left: 50%;
top: 40%;
height: 2.5rem;
padding-top: 1.3rem;
width: 15rem;
text-align: center;
color: #fff;
border: #fff solid 0.2rem;
font-size: 1rem;
font-weight: bold;
text-transform: uppercase;
text-decoration: none;
transform: translateX(-50%);
}
.split.left .button:hover {
background-color: var(--left-button-hover-color);
border-color: var(--left-button-hover-color);
}
.split.middle .button:hover {
background-color: var(--middle-button-hover-color);
border-color: var(--middle-button-hover-color);
}
.split.right .button:hover {
background-color: var(--right-button-hover-color);
border-color: var(--right-button-hover-color);
}
.container {
position: relative;
width: 100%;
height: 100%;
background: var(--container-bg-color);
}
.split {
position: absolute;
width: 33%;
height: 100%;
overflow: hidden;
}
.split.left {
left: 0;
background: url(/img/design.jpeg) center center no-repeat;
background-size: cover;
}
.split.left:before {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: var(--left-bg-color);
}
.split.middle {
left:33.3%;
background: url(/img/pexels.jpeg) center center no-repeat;
background-size: cover;
}
.split.middle:before {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: var(--middle-bg-color);
}
.split.right {
right: 0;
background: url(/img/code.png) center center no-repeat;
background-size: cover;
}
.split.right:before {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: var(--right-bg-color);
}
.split.left,
.split.right,
.split.middle,
.split.middle:before,
split.right:before,
split.left:before {
transition: var(--speed) all ease-in-out;
}
.hover-left .left {
width: var(--hover-width);
}
.hover-left .right {
width: var(--other-width);
}
.hover-left .middle {
width: var(--other-width)
}
.hover-left .right:before {
z-index: 1;
}
.hover-left .middle:before {
z-index: 2;
}
.hover-middle .middle {
width: var(--hover-width);
}
.hover-middle .left {
width: var(--other-width);
}
.hover-middle .right {
width: var(--other-width);
}
.hover-middle .right:before {
z-index: 1;
}
.hover-middle .left:before {
z-index: 2;
}
.hover-right .right {
width: var(--hover-width);
}
.hover-right .middle {
width: var(--other-width);
}
.hover-right .left {
width: var(--other-width);
}
.hover-right .left:before {
z-index: 1;
}
.hover-right .middle:before {
z-index: 2;
}
#media(max-width:800px) {
h1 {
font-size: 2rem;
}
.button {
width: 12rem;
}
}
#media(max-height:700px) {
.button {
top: 70%;
}
}
<div class="container">
<div class="split left">
<h1>The Designer</h1>
Read More
</div>
<div class="split middle">
<h1>The Noob</h1>
Read More
</div>
<div class="split right">
<h1>The Programmer</h1>
Read More
</div>
</div>
Couple of things.
First you'll want to move the middle div when hovering on the three divs and move it back when exiting:
left.addEventListener('mouseenter', () => {
container.classList.add('hover-left');
middle.style.left = "66.6666666%";
});
left.addEventListener('mouseleave', () => {
container.classList.remove('hover-left');
middle.style.left = "33.333333%";
});
middle.addEventListener('mouseenter', () => {
container.classList.add('hover-middle');
middle.style.left = "16.65%";
});
middle.addEventListener('mouseleave', () => {
container.classList.remove('hover-middle');
middle.style.left = "33.333333%";
});
right.addEventListener('mouseenter', () => {
container.classList.add('hover-right');
middle.style.left = "16.65%";
});
right.addEventListener('mouseleave', () => {
container.classList.remove('hover-right');
middle.style.left = "33.333333%";
});
Also, you'll want to change the --hover-width to be 66.6%.
:root {
--container-bg-color: #333;
--left-bg-color: rgba(223, 39, 39, 0.7);
--left-button-hover-color: rgba(161, 11, 11, 0.3);
--middle-bg-color: #ededed;
--middle-button-hover-color: #ffba00;
--right-bg-color: rgba(43, 43, 43, 0.8);
--right-button-hover-color: rgba(92, 92, 92, 0.3);
--hover-width: 66.6666666%;
--other-width: 16.65%;
--speed: 1000ms;
}
The problem with the space between the middle div and the right div is that 33.3 + 33.3 + 33.3 = 99.9. So, you'll have to make up the .1% somewhere. So, lets close the gap. Use 33.333333 instead.
View this codepen: https://codepen.io/bpuhnk/pen/wxWKjj
Here, I have a very small module. In which I have a timeline and slideshow.
In my timeline, Everything works fine. But when I going to the slideshow.
It also works fine using on click function on the class name.
But I want to use bind and unbind function on next and previous button click.
Here, is my code please review it and help will be appreaciated.
var divSlide = document.querySelectorAll('#slide');
var myNodeList = divSlide.length;
let slideNo = 1;
for(var i = 0; i < myNodeList; i++) {
var type = divSlide[i].getAttribute("type");
if (type == "timeline") {
} else if (type == "slideshow") {
var timeline = divSlide[i];
let sliderData = timeline.getElementsByTagName("section");
$("[type=slideshow] section").addClass('hide');
$("[type=slideshow]").each( function(i,ele){
$(ele).children("section:first").removeClass("hide").addClass('active');
});
timeline.insertAdjacentHTML("afterbegin",'<a class="left uc_prev color_arrow carousel-control" href="#myCarousel" data-slide="prev"><span class="glyphicon glyphicon-chevron-left"></span><span class="sr-only">Previous</span></a>');
timeline.insertAdjacentHTML('afterbegin','<a class="right uc_next color_arrows carousel-control" href="#myCarousel" data-slide="next"><span class="glyphicon glyphicon-chevron-right"></span><span class="sr-only">Next</span></a>');
}
}
$(document).on ('click','.uc_prev',function() {
let select = $(this).parent();
let totChild = select.children("section");
for(let i=0;i<totChild.length;i++){
if(totChild[i].getAttribute('class').indexOf('active')!=-1){
slideNo=i+1;
}
}
totChild.children('br').remove();
let current = select.children('.active');
let prevEl = current.prev('section');
if(slideNo === totChild.length || slideNo > 1){
select.children(".next").show();
if(prevEl.length !== 1){
prevEl = current.prev().prev();
current.removeClass('active');
current.addClass('hide');
prevEl.addClass('active');
prevEl.addClass('animated');
prevEl.addClass('fadeInLeft');
prevEl.removeClass('hide');
}
} else {
select.children(".prev").hide();
}
});
$(document).on ('click','.uc_next',function() {
let select = $(this).parent();
let totChild = select.children("section");
for(let i=0;i<totChild.length;i++){
if(totChild[i].getAttribute('class').indexOf('active')!=-1){
slideNo=i+1;
}
}
totChild.children('br').remove();
let current = select.children('.active');
let prevEl = current.next('section');
if(slideNo ===1 || slideNo < totChild.length){
select.children(".prev").show();
if(prevEl.length !== 1){
prevEl = current.next().next();
current.removeClass('active');
current.addClass('hide');
prevEl.addClass('animated');
prevEl.addClass('fadeInRight');
prevEl.addClass('active');
prevEl.removeClass('hide');
}
} else {
select.children(".next").hide();
}
});
}
div[type="slideshow"] {
height:471px;
position: relative;
top: 100px;
}
div[type="slideshow"] > section:not(.hide) {
margin: auto;
width: 900px;
max-height: 265px;
z-index: 100;
border-top: 1px solid grey;
border-left: 4px solid #00BCD4;
min-height:250px;
background-color: #b3e5fc2b;
border-radius: 4px;
margin-bottom: 55px;
position: absolute;
overflow-x: hidden;
top: 21.4%;
left: 168px;
box-shadow: rgb(136, 136, 136) 3px 3px 1px;
}
div[type="slideshow"] > section:not(.hide) > header {
font-weight: 600;
color: cadetblue;
transform: translate(93px, 32px);
font-size: 34px;
font-family: arial;
position: relative;
word-wrap: break-word;
}
div[type="slideshow"] > section:not(.hide) > article {
transform: translate(87px,39px);
max-width: 800px;
color: black;
font-size: 22px;
font-family: arial;
position: relative;
padding: 10px;
word-wrap: break-word;
}
.active{
opacity: 1 !important;
}
.hide {
opacity: 0;
min-height: 0 !important;
margin: 0 !important;
}
.hide header, .hide article {
display: none;
}
#keyframes fadein {
0% { opacity: 0 }
50% { opacity: 0.5 }
100% {opacity: 1}
}
br {
display:none;
}
progress {
height: 4px;
top: 46px;
left: 0px;
width: 100%;
position: fixed;
margin-left: -1px;
margin-top: -1px;
}
.color_arrow {
position: relative;
top: 228px;
color: #085153;
left: 93px;
}
.color_arrows {
position: relative;
top: 228px;
color: #085153;
left: 94% !important;
}
#media only screen and (max-width: 992px) {
div[type="timeline/slideshow"] > section , div[type="timeline"] > section {
width: 650px;
}
.color_arrow {
left: -18px;
}
div[type="slideshow"] > section:not(.hide) {
width: 640px;
left: 14px;
}
.color_arrows {
left: 99% !important;
}
}
#media only screen and (max-width: 992px) {
div[type="slideshow"] > section {
width: 650px;
}
div[type="slideshow"] > section:not(.hide) {
width: 640px;
left: 18px;
}
}
#media only screen and (min-width: 1201px) and (max-width: 1299px) {
div[type="slideshow"] > section:not(.hide) {
width: 845px;
left: 154px;
}
}
#media only screen and (min-width: 992px) and (max-width: 1200px) {
div[type="slideshow"] > section:not(.hide) {
width: 698px;
left: 136px;
}
}
<div type="slideshow" id="slide"><br />
<section><header>Title One</header><br />
<article>Content</article>
</section>
<br />
<section><header>Title Two</header><br />
<article>Content</article>
</section>
<br />
<section><header>Title Three</header><br />
<article>Content</article>
</section>
<br />
<section><header>Title Four</header><br />
<article>Content</article>
</section>
</div>