Transition not applying to div - vanilla js accordion - javascript

I have some simple vanilla accordion and I'm not really sure why the CSS transition is not applying here? The divs have correct height, what is going on here?
(Cannot post because apparently my issue is mostly code, so this text is a dirty fix, sorry).
HTML (simplified version)
<div class="container">
<ul>
<li class="accordion-item">
<button class="accordion-item__title">
Title
</button>
<div class="accordion-item__body not-active">
Body
</div>
</li>
</ul>
</div>
JS
document.addEventListener('DOMContentLoaded', function () {
const accordions = document.querySelectorAll('.block-accordion');
if (typeof (accordions) !== 'undefined' && accordions != null) {
//loop thorugh all acordions
for (let a = 0; a < accordions.length; a++) {
const accordion = accordions[a];
const accordionItems = accordion.querySelectorAll('.accordion-item');
//loop through all accordiond's items
for (let i = 0; i < accordionItems.length; i++) {
const accordionItem = accordionItems[i];
//show first by default
accordionItems[0].querySelector('.accordion-item__body').classList.remove('not-active');
accordionItems[0].querySelector('.accordion-item__body').parentElement.classList.add('active');
accordionItems[0].querySelector('.accordion-item__title').setAttribute("aria-expanded", true);
//hide each accordion on click
const accordionItemTitle = accordionItem.firstElementChild;
accordionItemTitle.addEventListener('click', function toggleAccordion(e) {
const accordionContent = accordionItem.querySelector('.accordion-item__body');
accordionContent.style.height = "auto";
if (accordionContent.previousElementSibling === e.target) {
accordionContent.classList.toggle('not-active');
accordionContent.parentElement.classList.toggle('active');
if (accordionContent.classList.contains('not-active')) {
accordionContent.style.height = '0px';
accordionContent.previousElementSibling.setAttribute("aria-expanded", false);
} else {
accordionContent.style.height = accordionContent.clientHeight + 'px';
accordionContent.previousElementSibling.setAttribute("aria-expanded", true);
}
}
});
}
}
}
});
SASS
.block-accordion {
.active {
display: block;
}
.not-active {
display: none;
transition: height 0.35s ease-in-out;
overflow: hidden;
}
}

Related

Tabs component in javascript class should be reusable

I have a component that should be reusable within a page. And it should be called only when in view.
I've added an extra class function outside class Tabs which is called class Pagination.
this class is not within class Tabs which is breaking the component if reused within the page (multiple times).
Would anyone help me to move the class Pagination inside Tabs? My goal is having a unique class, so I can reuse the component multiple times and only when is in view. I really hope it makes sense,
here you have a Pen demo, as you can see the pagination is not in the right constuctor. I brake the function everytime I try to move it.
class Pagination {
constructor(tabComponent, prevBtnId, nextBtnId) {
this.arrayUtils = new ArrayUtils();
this.tabComponent = tabComponent;
this.prevBtn = document.querySelector(prevBtnId);
this.nextBtn = document.querySelector(nextBtnId);
// listen to tabComponents newly created Toggle event
// in which we wanna make sure to disable Btns or something..
this.tabComponent.onTabsToggle((tabs, tabIndex) => {
this.applyPaginationRules(tabs, tabIndex);
});
}
setDisabled(btn, value) {
if (value) {
btn.setAttribute("disabled", "true");
} else {
btn.removeAttribute("disabled");
}
}
applyPaginationRules(tabs, newActiveIndex) {
const nextBtnDisabled = newActiveIndex === tabs.length - 1;
const prevBtnDisabled = newActiveIndex === 0;
this.setDisabled(this.nextBtn, nextBtnDisabled);
this.setDisabled(this.prevBtn, prevBtnDisabled);
}
paginate(btn, action) {
const block = btn.closest(".tabs-block");
const panels = block.querySelectorAll(".panel");
const tabs = block.querySelectorAll(".tab-wrapper > li > button");
const activeIndex = Array.from(tabs).findIndex(
(t) => t.getAttribute("data-open") === "true"
);
if (tabs.length < 2) {
console.log("0 OR 1 tabs to toggle so no action.");
return;
}
var newActiveIndex;
if (action === "next") {
newActiveIndex = this.arrayUtils.nextIndex(activeIndex, tabs);
} else if (action === "prev") {
newActiveIndex = this.arrayUtils.previousIndex(activeIndex, tabs);
} else {
throw "Invalid toggle action " + action;
}
// enable / disable next and previous btns..
this.applyPaginationRules(tabs, newActiveIndex);
this.tabComponent.toggleTabs(tabs[newActiveIndex], panels);
}
addPaginationListener(btn, action) {
btn.addEventListener("click", (e) => {
this.paginate(btn, action);
});
}
init() {
this.addPaginationListener(this.prevBtn, "prev");
this.addPaginationListener(this.nextBtn, "next");
// disable prev button on beggining since we start at 0..
this.setDisabled(this.prevBtn, true);
}
}
class ArrayUtils {
// getting next index in array
nextIndex(currentIndex, array) {
// if 0 OR 1 elements, index stays the same..
if (array.length < 2) return currentIndex;
// if possible increment.
if (currentIndex < array.length - 1) {
return currentIndex + 1;
}
// if index would exceed array size go to start.
return 0;
}
// getting previous INdex in array:
previousIndex(currentIndex, array) {
// if 0 OR 1 elements, index stays the same..
if (array.length < 2) return currentIndex;
// if possible decrement!
if (currentIndex > 0) {
return currentIndex - 1;
}
// start at the end of array when end is reached ofc.
return array.length - 1;
}
}
class Tabs {
constructor() {
this.tabsBlocks = document.querySelectorAll(".tabs-block");
this.onToggleHandlers = [];
}
onTabsToggle(fn) {
this.onToggleHandlers.push(fn);
}
emitTabsToggle(tabs, tabIndex) {
this.onToggleHandlers.forEach((fn) => fn(tabs, tabIndex));
}
init() {
if (this.tabsBlocks.length > 0) {
Array.prototype.forEach.call(this.tabsBlocks, (tabBlock, index) => {
const tabContainer = tabBlock.querySelector(".tab-wrapper");
const tabs = tabBlock.querySelectorAll(".tab-wrapper li button");
const panels = tabBlock.querySelectorAll(".panel");
tabContainer.setAttribute("role", "tablist");
Array.prototype.forEach.call(tabs, (tab, tabIndex) => {
if (tab.dataset.open === "true") this.toggleTabs(tab, panels);
tab.setAttribute("role", "tab");
tab.setAttribute(
"aria-controls",
`panel-${tab.dataset.target}-block-${index + 1}`
);
const associatedPanel = tabBlock.querySelector(
`[data-panel="${tab.dataset.target}"]`
);
if (associatedPanel !== null) {
associatedPanel.id = `panel-${tab.dataset.target}-block-${
index + 1
}`;
tab.id = `tab-${tab.dataset.target}-block-${index + 1}`;
}
tab.addEventListener("click", () => {
this.toggleTabs(tab, panels);
this.emitTabsToggle(tabs, tabIndex);
});
});
Array.prototype.forEach.call(panels, (panel) => {
const associatedTab = tabBlock.querySelector(
`[data-target="${panel.dataset.panel}"]`
);
panel.setAttribute("role", "tabpanel");
panel.setAttribute("aria-labelledby", `${associatedTab.id}`);
});
});
}
}
toggleTabs = (currentTab, panels) => {
const tabs = currentTab.closest(".tabs-block").querySelectorAll("button");
const target = currentTab.dataset.target;
Array.prototype.forEach.call(tabs, (tab) => {
if (tab.dataset.target !== target) {
tab.classList.remove("is-active");
tab.setAttribute("data-open", "false");
tab.setAttribute("aria-selected", "false");
}
});
Array.prototype.forEach.call(panels, (panel) => {
if (panel.dataset.panel !== target) {
panel.classList.remove("is-active");
} else {
panel.classList.add("is-active");
}
});
/// activate tab..
currentTab.classList.add("is-active");
currentTab.setAttribute("data-open", "true");
currentTab.setAttribute("aria-selected", "true");
};
}
const components = {
Tabs: new Tabs()
};
components.Tabs.init();
// have the pagination more decoupled from tabs!
// it uses tabs component but you can remove it OR apply it to other
// classes like so more easily..
const prevBtnId = ".pagination-prev";
const nextBtnId = ".pagination-next";
const pagination = new Pagination(components.Tabs, prevBtnId, nextBtnId);
pagination.init();
.tabs-block {
border: 1px solid red;
}
.tabs-block .tab-wrapper li {
flex: 1 1 0%;
text-align: center;
}
.tabs-block .tab-wrapper li button {
font-weight: lighter;
font-size: rem(20px);
}
.tabs-block .tab-wrapper li button.is-active {
font-weight: normal;
}
.tabs-block .panel {
display: none;
}
.tabs-block .panel.is-active {
display: block;
}
.is-active {
color: red;
}
<section class="tabs-block">
<ul class="tab-wrapper">
<li><button data-target="1" data-open="true">Tab title 1</button></li>
<li><button data-target="2">Tab title 2</button></li>
<li><button data-target="3">Tab title 3</button></li>
</ul>
<div class="panel-wrapper">
<div data-panel="1" class="panel">
<p>Panel 1 content</p>
</div>
<div data-panel="2" class="panel">
<p>Panel 2 content</p>
</div>
<div data-panel="3" class="panel">
<p>Panel 3 content</p>
</div>
</div>
<button class="buttonPrev pagination-prev">
<< Prev</button>
<button class="buttonNext pagination-next">Next >></button>
</section>

Box styling seemingly not applied when adding new elements with button

Refer to link. Link is to the project "Scroll-Animation" I am cloning in local browser to practice front-end.
I have two buttons, +, -. The '+' adds new boxes, the '-' removes boxes from the body. I implemented the '+' but it seems the styling for boxes is not working. That is, it seems to add the "div" elements I created to body but the div's are not style like I have them in .css file for .box { ... } Any help with how to fix this is greatly appreciated. Thanks!
style.css
...
.box {
height: 200px;
width: 400px;
border-radius: 10px;
background-color: steelblue;
margin: 10px;
color: white;
display: grid;
place-items: center;
box-shadow: 2px 4px 5px rgba(0,0,0,.3);
transform: translateX(-400%);
transition: transform .5s ease;
}
.box:nth-of-type(even) {
transform: translateX(400%);
}
.box.show {
transform: translateX(0);
}
...
app.js
const boxes = document.querySelectorAll('.box');
const btns = document.querySelectorAll('.btn');
window.addEventListener('scroll', slideBox);
slideBox();
// NOTE: Need to fix.
btns.forEach(btn => {
btn.addEventListener('click', (e) => {
const cList = e.currentTarget.classList;
if (cList.contains('add')) {
console.log('Work');
var h2 = document.createElement('h2');
h2.innerHTML = 'Content';
var newBox = document.createElement("div");
var attr = document.createAttribute("class");
attr.value = "box";
newBox.setAttributeNode(attr);
newBox.appendChild(h2);
document.body.appendChild(newBox);
}
})
})
// NOTE: This function works!!!
function slideBox() {
const pageBot = window.innerHeight / 5 * 4;
const pageTop = window.innerHeight / 5 * 1;
boxes.forEach(box => {
const boxTop = box.getBoundingClientRect().top;
const boxBot = box.getBoundingClientRect().bottom;
if (boxTop < pageBot && boxBot > pageTop) {
box.classList.add('show');
} else {
box.classList.remove('show');
}
})
}
index.html
<body>
<h1>Scroll to see the animation</h1>
<div class="button-container">
<button class="btn add">+</button>
<button class="btn minus">-</button>
</div>
<!-- <div class="box"><h2>Content</h2></div>
<div class="box"><h2>Content</h2></div>
...
<div class="box"><h2>Content</h2></div> -->
<script src="app.js"></script>
</body>
I think the problem is after you add a new box, but afterward you don't query all boxes again in slideBox. You can check the fix here
The full modification in Javascript with some comments
const btns = document.querySelectorAll('.btn');
window.addEventListener('scroll', slideBox)
slideBox();
btns.forEach(btn => {
btn.addEventListener('click', (e) => {
const cList = e.currentTarget.classList;
if (cList.contains('add')) {
console.log('Work');
var h2 = document.createElement('h2');
h2.innerHTML = 'Content';
var newBox = document.createElement("div");
var attr = document.createAttribute("class");
attr.value = "box";
newBox.setAttributeNode(attr);
newBox.appendChild(h2);
document.body.appendChild(newBox);
}
})
})
function slideBox() {
//query all boxes every time you scroll because of new boxes
const boxes = document.querySelectorAll('.box')
const triggerBottom = window.innerHeight / 5 * 4
boxes.forEach(box => {
const boxTop = box.getBoundingClientRect().top
if (boxTop < triggerBottom) {
box.classList.add('show')
} else {
box.classList.remove('show')
}
})
}

PhotoSwipe overlayed button click causes gallery to open

I'm trying to add a delete button overlayed on my thumbnails but when I click it the gallery is opened.
I tried adding this to try to stop the click propagating to the figure element but it didn't work:
$('body').on('click', '.delete-file-btn', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
});
var initPhotoSwipeFromDOM = function(gallerySelector) {
// parse slide data (url, title, size ...) from DOM elements
var parseThumbnailElements = function(el) {
var thumbElements = el.childNodes,
numNodes = thumbElements.length,
items = [],
figureEl,
linkEl,
size,
item;
for(var i = 0; i < numNodes; i++) {
figureEl = thumbElements[i]; // <figure> element
// include only element nodes
if(figureEl.nodeType !== 1) {
continue;
}
linkEl = figureEl.children[0]; // <a> element
size = linkEl.getAttribute('data-size').split('x');
// create slide object
item = {
src: linkEl.getAttribute('href'),
w: parseInt(size[0], 10),
h: parseInt(size[1], 10)
};
if(figureEl.children.length > 1) {
// <figcaption> content
item.title = figureEl.children[1].innerHTML;
}
if(linkEl.children.length > 0) {
// <img> thumbnail element, retrieving thumbnail url
item.msrc = linkEl.children[0].getAttribute('src');
}
item.el = figureEl; // save link to element for getThumbBoundsFn
items.push(item);
}
return items;
};
// find nearest parent element
var closest = function closest(el, fn) {
return el && ( fn(el) ? el : closest(el.parentNode, fn) );
};
// triggers when user clicks on thumbnail
var onThumbnailsClick = function(e) {
e = e || window.event;
e.preventDefault ? e.preventDefault() : e.returnValue = false;
var eTarget = e.target || e.srcElement;
// find root element of slide
var clickedListItem = closest(eTarget, function(el) {
return (el.tagName && el.tagName.toUpperCase() === 'FIGURE');
});
if(!clickedListItem) {
return;
}
// find index of clicked item by looping through all child nodes
// alternatively, you may define index via data- attribute
var clickedGallery = clickedListItem.parentNode,
childNodes = clickedListItem.parentNode.childNodes,
numChildNodes = childNodes.length,
nodeIndex = 0,
index;
for (var i = 0; i < numChildNodes; i++) {
if(childNodes[i].nodeType !== 1) {
continue;
}
if(childNodes[i] === clickedListItem) {
index = nodeIndex;
break;
}
nodeIndex++;
}
if(index >= 0) {
// open PhotoSwipe if valid index found
openPhotoSwipe( index, clickedGallery );
}
return false;
};
// parse picture index and gallery index from URL (#&pid=1&gid=2)
var photoswipeParseHash = function() {
var hash = window.location.hash.substring(1),
params = {};
if(hash.length < 5) {
return params;
}
var vars = hash.split('&');
for (var i = 0; i < vars.length; i++) {
if(!vars[i]) {
continue;
}
var pair = vars[i].split('=');
if(pair.length < 2) {
continue;
}
params[pair[0]] = pair[1];
}
if(params.gid) {
params.gid = parseInt(params.gid, 10);
}
return params;
};
var openPhotoSwipe = function(index, galleryElement, disableAnimation, fromURL) {
var pswpElement = document.querySelectorAll('.pswp')[0],
gallery,
options,
items;
items = parseThumbnailElements(galleryElement);
// define options (if needed)
options = {
// define gallery index (for URL)
galleryUID: galleryElement.getAttribute('data-pswp-uid'),
getThumbBoundsFn: function(index) {
// See Options -> getThumbBoundsFn section of documentation for more info
var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail
pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
rect = thumbnail.getBoundingClientRect();
return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
}
};
// PhotoSwipe opened from URL
if(fromURL) {
if(options.galleryPIDs) {
// parse real index when custom PIDs are used
// http://photoswipe.com/documentation/faq.html#custom-pid-in-url
for(var j = 0; j < items.length; j++) {
if(items[j].pid == index) {
options.index = j;
break;
}
}
} else {
// in URL indexes start from 1
options.index = parseInt(index, 10) - 1;
}
} else {
options.index = parseInt(index, 10);
}
// exit if index not found
if( isNaN(options.index) ) {
return;
}
if(disableAnimation) {
options.showAnimationDuration = 0;
}
// Pass data to PhotoSwipe and initialize it
gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options);
gallery.init();
};
// loop through all gallery elements and bind events
var galleryElements = document.querySelectorAll( gallerySelector );
for(var i = 0, l = galleryElements.length; i < l; i++) {
galleryElements[i].setAttribute('data-pswp-uid', i+1);
galleryElements[i].onclick = onThumbnailsClick;
}
// Parse URL and open gallery if it contains #&pid=3&gid=1
var hashData = photoswipeParseHash();
if(hashData.pid && hashData.gid) {
openPhotoSwipe( hashData.pid, galleryElements[ hashData.gid - 1 ], true, true );
}
};
initPhotoSwipeFromDOM('.existing-files');
.existing-files {
margin: 1rem -.5rem;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.existing-files .file-container {
padding: .5rem;
text-align: center;
display: inline-block;
position: relative;
}
.delete-file-btn {
font-size: 0;
position: absolute;
display: block;
transform: scale(1);
width: 22px;
height: 22px;
border-radius: 40px;
background-color: #E2E8F0;
top: -1px;
right: -5px;
z-index: 100;
box-shadow: -2px 2px 6px 1px rgba(0, 0, 0, 0.25);
transition: background-color .15s ease-in-out,box-shadow .15s ease-in-out;
}
.delete-file-btn::after, .delete-file-btn::before {
content: "";
display: block;
position: absolute;
width: 12px;
height: 2px;
background-color: #000000;
transform: rotate(45deg);
border-radius: 5px;
top: 10px;
left: 5px;
transition: background-color .15s ease-in-out;
}
.delete-file-btn::after {
transform: rotate(-45deg);
}
.delete-file-btn:hover, .delete-file-btn:focus, .delete-file-btn:active {
box-shadow: none;
background-color: #A0AEC0;
}
.delete-file-btn:hover::after, .delete-file-btn:hover::before, .delete-file-btn:focus::after, .delete-file-btn:focus::before, .delete-file-btn:active::after, .delete-file-btn:active::before {
background-color: #FFFFFF;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/default-skin/default-skin.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.3/photoswipe-ui-default.js"></script>
<div class="existing-files">
<figure class="file-container">
<a data-size="304x171" data-turbolinks="false" class="gal" href="https://placeimg.com/304/171/nature"><img src="https://placeimg.com/304/171/nature"></a>
<a class="delete-file-btn" rel="nofollow" data-method="delete" href="#"></a>
</figure>
<figure class="file-container">
<a data-size="304x171" data-turbolinks="false" class="gal" href="https://placeimg.com/304/171/nature"><img src="https://placeimg.com/304/171/nature"></a>
<a class="delete-file-btn" rel="nofollow" data-method="delete" href="#"></a>
</figure>
</div>
<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
<!-- Background of PhotoSwipe.
It's a separate element as animating opacity is faster than rgba(). -->
<div class="pswp__bg"></div>
<!-- Slides wrapper with overflow:hidden. -->
<div class="pswp__scroll-wrap">
<!-- Container that holds slides.
PhotoSwipe keeps only 3 of them in the DOM to save memory.
Don't modify these 3 pswp__item elements, data is added later on. -->
<div class="pswp__container">
<div class="pswp__item"></div>
<div class="pswp__item"></div>
<div class="pswp__item"></div>
</div>
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
<div class="pswp__ui pswp__ui--hidden">
<div class="pswp__top-bar">
<!-- Controls are self-explanatory. Order can be changed. -->
<div class="pswp__counter"></div>
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
<button class="pswp__button pswp__button--share" title="Share"></button>
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
<!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
<!-- element will get class pswp__preloader--active when preloader is running -->
<div class="pswp__preloader">
<div class="pswp__preloader__icn">
<div class="pswp__preloader__cut">
<div class="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class="pswp__share-tooltip"></div>
</div>
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
</button>
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
</button>
<div class="pswp__caption">
<div class="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
Instead of preventing the click from propagating on elements it shouldn't I changed the script to only allow clicks on my gallery image anchor element class="gal" above. Here's the edited function from the script above.
var onThumbnailsClick = function(e) {
e = e || window.event;
e.preventDefault ? e.preventDefault() : e.returnValue = false;
var eTarget = e.target || e.srcElement;
// find root element of slide
var clickedListItem = closest(eTarget, function(el) {
return (el.tagName && el.tagName.toUpperCase() === 'A' && el.className == 'gal');
});
if(!clickedListItem) {
return;
}
// find index of clicked item by looping through all child nodes
// alternatively, you may define index via data- attribute
var clickedGallery = clickedListItem.parentNode.parentNode,
childNodes = clickedListItem.parentNode.parentNode.childNodes,
numChildNodes = childNodes.length,
nodeIndex = 0,
index;
for (var i = 0; i < numChildNodes; i++) {
if(childNodes[i].nodeType !== 1) {
continue;
}
if(childNodes[i] === clickedListItem.parentNode) {
index = nodeIndex;
break;
}
nodeIndex++;
}
if(index >= 0) {
// open PhotoSwipe if valid index found
openPhotoSwipe( index, clickedGallery );
}
return false;
};

Javascript only add a class to an element on an interval after it's come into viewport

I have a series of images I want to transition from 0 opacity to 1 opacity when they come into the view port. I have the viewport check part done and the adding classes, however I would like them to be on an interval, so once the first 3 images come into the view port they appear 1, 2, 3 every .5seconds or so. Instead of all 3 at the same time.
here's a JS fiddle of how it works currently
reveal();
function reveal() {
var reveal = document.querySelectorAll(".reveal");
window.onscroll = function() {
for(var i = 0; i < reveal.length; i++) {
if(checkVisible(reveal[i]) === true) {
reveal[i].classList.add("fade");
}
}
}
};
function checkVisible(elm) {
var rect = elm.getBoundingClientRect();
var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
return !(rect.bottom < 0 || rect.top - viewHeight >= -200);
}
https://jsfiddle.net/u04sy7jb/
I've modified your code to add a transition-delay of an additional .5 seconds for each element after the first one, in each "group" that is revealed as you scroll. I left comments in the JavaScript so you can understand the changes.
Let me know if you have any questions!
Live demo:
reveal();
function reveal() {
var reveal = document.querySelectorAll(".reveal");
window.onscroll = function() {
// start a new count each time user scrolls
count = 0;
for (var i = 0; i < reveal.length; i++) {
// also check here if the element has already been faded in
if (checkVisible(reveal[i]) && !reveal[i].classList.contains("fade")) {
// add .5 seconds to the transition for each
// additional element currently being revealed
reveal[i].style.transitionDelay = count * 500 + "ms";
reveal[i].classList.add("fade");
// increment count
count++;
}
}
}
};
function checkVisible(elm) {
var rect = elm.getBoundingClientRect();
var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
return !(rect.bottom < 0 || rect.top - viewHeight >= -200);
}
.container {
width: 100%;
height: 1200px;
background-color: orange;
}
.reveal {
display: inline-block;
width: 32%;
margin: 0 auto;
height: 400px;
background-color: pink;
border: 1px solid black;
opacity: 0;
}
.fade {
opacity: 1;
transition: 1s;
}
<div class="container">
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
<div class="reveal"></div>
</div>
You could be able to stick your reveal[i].classList.add("fade"); inside of a setTimeout that executes as a function of your ith element so they show up how you're describing. Here is an example of adding short function to add the class and using it in a setTimeout to make this happen, although you could change it up to meet any additional needs.
function reveal() {
var reveal = document.querySelectorAll(".reveal");
window.onscroll = function() {
for(var i = 0; i < reveal.length; i++) {
if(checkVisible(reveal[i]) === true) {
addMyFadeClass(reveal[i], i)
}
}
}
};
function addMyFadeClass(element, i) {
setTimeout(function() {
element.classList.add("fade");
}, i * 500)
}
You can also use :nth-child CSS selectors without the need to change the JS:
.reveal:nth-child(3n+1).fade {
opacity: 1;
transition: 1s;
}
.reveal:nth-child(3n+2).fade {
opacity: 1;
transition: 1.5s;
}
.reveal:nth-child(3n).fade {
opacity: 1;
transition: 2s;
}
JSFiddle: https://jsfiddle.net/u04sy7jb/8/

Jquery script modification to add fade in/out features

Ok so I found this script from a different part of this site:
var divs = ["wrap20", "wrap21", "wrap22"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
I was able to successfully implement this code to a site which will show various groups of pictures whenever I click on an independent hyperlink.
What part of this code needs to be manipulated in order for the different elements to fade in or out?
Try something like this:
if(visibleDivId === divId) {
$(div).fadeIn(500);
} else {
$(div).fadeOut(500);
}
500 is the number of milliseconds the fading should take.
Here's a working example with Jquery on JSFiddle.
Another possibility would be to use show(500) and hide(500).
UPDATE:
Based on the OP's comments here's a version to achieve such an effect with CSS transitions (another Fiddle):
HTML
Click1
Click2
Click3
<div>
<div class="wraps on" id="wrap20">
Image #1
</div>
<div class="wraps off" id="wrap21">
Image #2
</div>
<div class="wraps off" id="wrap22">
Image #3
</div>
</div>
Javascript
var divs = ["wrap20", "wrap21", "wrap22"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.className = "wraps on";
} else {
div.className = "wraps off";
}
}
}
CSS
.wraps {
width:100px;
height:100px;
display: block;
position: absolute;
top: 60px;
left: 10px;
}
.on {
opacity: 1;
transition: opacity 2s;
z-index: 999;
}
.off {
opacity: 0;
transition: opacity 2s;
z-index: 100;
}
#wrap20 {
background-color:green;
}
#wrap21 {
background-color:blue;
}
#wrap22 {
background-color:red;
}
You don't need the display property here, it's not fit for transitions anyway. You just display all the divs like you want them and use the opacity property to hide and show them. opacity works well with transitions. Transition and opacity for the two states are rolled up in classes so you don't have to set them separately in your javascript.
some-non-descript-user Ok I tried your Jquery fiddle, and that is EXACTLY what I was looking for! Thanks for your patience and time.

Categories

Resources