working on a way of displaying information, 8 panels (when each is clicked it expands content below) - however I am trying to add styling so that when one panel is clicked (active) - the background color updates to green and is removed when a new element is clicked. I can't seem to pass the tabName parameter to getElementById so for now the parameter is hardcoded as banking-tab (which does update to green when clicked). Does anyone have any advice for the best possible solution and a potential approach to explore for the remove function?
function onExpandFuncs(tabName) {
openTab(tabName);
styleTab(tabName);
}
function openTab(tabName) {
var i, x;
x = document.getElementsByClassName('containerTab');
for (i = 0; i < x.length; i++) {
x[i].style.display = 'none';
}
document.getElementById(tabName).style.display = 'block';
}
function styleTab(tabName) {
document.getElementById('banking-tab').classList.add('active-column');
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
/* The grid: Four equal columns that floats next to each other */
.column {
background-color: black;
float: left;
width: 25%;
height: 226px;
padding: 50px;
text-align: center;
font-size: 16px;
cursor: pointer;
color: white;
}
.active-column {
background-color: green;
float: left;
width: 25%;
height: 226px;
padding: 50px;
text-align: center;
font-size: 16px;
cursor: pointer;
color: white;
}
.containerTab {
padding: 20px;
color: white;
}
/* Clear floats after the columns */
.row:after {
content: '';
display: table;
clear: both;
}
/* Closable button inside the container tab */
.closebtn {
float: right;
color: white;
font-size: 35px;
cursor: pointer;
}
.arrow-down {
width: 25px;
height: 25px;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="styles.css" />
<script src="index.js"></script>
</head>
<body>
<div style="text-align: center">
<h2>Expanding Grid</h2>
<p>Click on the boxes below:</p>
</div>
<!-- Four columns -->
<div class="row">
<div id="banking-tab" class="column" onclick="onExpandFuncs('b1');">
<img src="./Icons/Banking.svg" />
<p>Banking</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div id="regtech-tab" class="column" onclick="onExpandFuncs('b2');">
<img src="./Icons/Regtech.svg" />
<p>RegTech</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div id="insurtech-tab" class="column" onclick="onExpandFuncs('b3');">
<img src="./Icons/InsurTech.svg" />
<p>InsurTech</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div id="lending-tab" class="column" onclick="onExpandFuncs('b4');">
<img src="./Icons/Lending.svg" />
<p>Lending</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
</div>
<!-- Full-width columns: (hidden by default) -->
<div id="b1" class="containerTab" style="display: none; background: black">
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h3>Banking</h3>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b2"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>RegTech</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b3"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>InsurTech</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b4"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>Lending</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<!-- Bottom four columns -->
<div class="row">
<div class="column" onclick="openTab('b5');">
<img src="./Icons/Accounting.svg" />
<p>Accounting</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div class="column" onclick="openTab('b6');">
<img src="./Icons/Payments.svg" />
<p>Payments</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div class="column" onclick="openTab('b7');">
<img src="./Icons/Quote.svg" />
<p>Quote Aggregators</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div class="column" onclick="openTab('b8');">
<img src="./Icons/WealthTech.svg" />
<p>WealthTech</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
</div>
<div
id="b5"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>Accounting</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b6"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>Payments</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b7"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>Quote</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b8"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>WealthTech</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
</body>
</html>
Any help would be really appreciated!
All you need to do is loop over all the tab elements and set up a click handler on the each that will set the background color of this, which will represent the element that is handling the event. No need to know or use an id (which should be avoided when possible as their use creates brittle code).
Also don't use .getElementsByClassName().
I've removed all the onclick attributes that aren't relevant to this question to avoid errors from their callbacks not being included in the code here.
// Get all the tabs into a collection
// (don't use .getElementsByClassName()!)
let tabs = document.querySelectorAll(".column");
// Loop over all the tabs
tabs.forEach(function(tab){
// Set up a click event handler on each of the tabs
tab.addEventListener("click", function(event){
// Loop over all the tabs and remove the active class
tabs.forEach(function(tab){
tab.classList.remove("active-column");
});
// Set the background of the clicked tab
this.classList.add("active-column");
});
});
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
/* The grid: Four equal columns that floats next to each other */
.column {
background-color: black;
float: left;
width: 25%;
height: 226px;
padding: 50px;
text-align: center;
font-size: 16px;
cursor: pointer;
color: white;
}
.active-column {
background-color: green;
float: left;
width: 25%;
height: 226px;
padding: 50px;
text-align: center;
font-size: 16px;
cursor: pointer;
color: white;
}
.containerTab {
padding: 20px;
color: white;
}
/* Clear floats after the columns */
.row:after {
content: '';
display: table;
clear: both;
}
/* Closable button inside the container tab */
.closebtn {
float: right;
color: white;
font-size: 35px;
cursor: pointer;
}
.arrow-down {
width: 25px;
height: 25px;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="styles.css" />
<script src="index.js"></script>
</head>
<body>
<div style="text-align: center">
<h2>Expanding Grid</h2>
<p>Click on the boxes below:</p>
</div>
<!-- Four columns -->
<div class="row">
<div id="banking-tab" class="column">
<img src="./Icons/Banking.svg" />
<p>Banking</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div id="regtech-tab" class="column">
<img src="./Icons/Regtech.svg" />
<p>RegTech</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div class="column">
<img src="./Icons/InsurTech.svg" />
<p>InsurTech</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div class="column">
<img src="./Icons/Lending.svg" />
<p>Lending</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
</div>
<!-- Full-width columns: (hidden by default) -->
<div id="b1" class="containerTab" style="display: none; background: black">
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h3>Banking</h3>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b2"
class="containerTab"
style="display: none; background: lightgrey"
>
<span class="closebtn"
>×</span
>
<h2>RegTech</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b3"
class="containerTab"
style="display: none; background: lightgrey"
>
<span class="closebtn"
>×</span
>
<h2>InsurTech</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b4"
class="containerTab"
style="display: none; background: lightgrey"
>
<span class="closebtn"
>×</span
>
<h2>Lending</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<!-- Bottom four columns -->
<div class="row">
<div class="column" >
<img src="./Icons/Accounting.svg" />
<p>Accounting</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div class="column" >
<img src="./Icons/Payments.svg" />
<p>Payments</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div class="column" >
<img src="./Icons/Quote.svg" />
<p>Quote Aggregators</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
<div class="column" >
<img src="./Icons/WealthTech.svg" />
<p>WealthTech</p>
<img class="arrow-down" src="./Icons/arrow-down.png" />
</div>
</div>
<div
id="b5"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>Accounting</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b6"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>Payments</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b7"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>Quote</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
<div
id="b8"
class="containerTab"
style="display: none; background: lightgrey"
>
<span onclick="this.parentElement.style.display='none'" class="closebtn"
>×</span
>
<h2>WealthTech</h2>
<p>
Lorem ipsum dolor sit amet, te quo doctus abhorreant, et pri deleniti
intellegat, te sanctus inermis ullamcorper nam. Ius error diceret
deseruisse ad
</p>
</div>
</body>
</html>
You are trying to work with two different elements.
Hence, you need to pass two different id's in click function. Something like below
function onExpandFuncs(tabName, clickedTab) {
openTab(tabName);
genericStyleTab(clickedTab);
}
function genericStyleTab(clickedTab) {
document.getElementById(clickedTab).classList.add('active-column');
}
<div id="banking-tab" class="column" onclick="onExpandFuncs('b1', 'banking-tab');">
Related
I have a site and I want each section to take up the screen and as you scroll down the page the sections fade out as the next section comes into view. I'm struggling on how this math needs to work.
For one section it's easy which is basically the height of the element and it's distance from the top to get the opacity percentage. However, I just can't quite figure out the math for other sections. I need section 2 to start fading in as section 1 is fading out.
I do not want to scrolljack. I just want a scrolling effect. Rather than override default scrolling behavior I just want to animate in/out as you scroll where a certain Y scroll value = a certain CSS value rather than a sort of "breakpoint" where it animates to a new "slide".
For the proper effect, for example, my math divides the height of the row by 2 so that it's 50% faded out as the next section should be fading in 50%. But, as of now, the math just doesn't work for the other sections.
This site is using vanilla JS as it's supposed to be a simple one pager.
Example below:
(function () {
window.addEventListener('scroll', () => {
const rows = document.querySelectorAll('.row');
rows.forEach(function (row, index) {
const distanceToTop = window.pageYOffset;
const elementHeight = row.offsetHeight * (index + 1) / 2;
row.style.opacity = ((elementHeight - distanceToTop) / elementHeight * 100) / 100;
});
});
})();
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0 0 0 0;
font-family: sans-serif;
font-family: 'Manrope', helvetiva, sans-serif;
transition: background-color 1s;
color:#fff;
background: linear-gradient(0deg, #100521 0%, #50357c 50%, #878290 100%);
}
header {
position: fixed;
top: 0;
width: 100%;
background: #fff;
z-index: 999;
}
header h1 {
font-family: 'Lack';
font-size: 4em;
text-align: center;
padding: 10px;
color: #100521;
}
.row-container .row:first-child {
opacity: 1;
}
.row {
opacity: 0;
height: 100vh;
display: flex;
flex-direction:column;
}
.row-inner {
display: grid;
grid-template-columns: 1fr 1fr;
position: sticky;
top: 0;
/* border: 1px solid yellow; */
padding: 0;
height: 100vh;
}
.column {
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
flex: 50%;
padding: 10px;
}
.left-column {
background-color: transparent;
}
.right-column {
background-color: transparent;
}
h1 {
font-family: 'Unbounded', helvetica, sans-serif;
}
h1 {
margin: 0;
font-size: 36px;
}
h2 {
margin: 0;
font-size: 24px;
}
p {
margin: 10px 0;
font-size: 18px;
line-height: 1.5;
}
img {
width: 100%;
height: auto;
}
<!DOCTYPE html>
<html>
<head>
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Manrope&family=Unbounded&family=Lack&display=swap" rel="stylesheet">
</head>
<body>
<header>
<h1>My App</h1>
</header>
<!-- First row -->
<div class="row-container">
<div class="row section-1">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline 1</h1>
<h2>Subhead 1</h2>
<p>Lorem Ipsum dolar Gamet</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-1.jpg" alt="Image 1">
</div>
</div>
</div>
</div>
<!-- Second row -->
<div class="row section-2">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline 2</h1>
<h2>Subhead 2</h2>
<p>Lorem Ipsum dolar Gamet</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-2.jpg" alt="Image 2">
</div>
</div>
</div>
</div>
<!-- Third row -->
<div class="row section-3">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline 3</h1>
<h2>Subhead 3</h2>
<p>Lorem Ipsum dolar Gamet</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-3.jpg" alt="Image 3">
</div>
</div>
</div>
</div>
<!-- Fourth row -->
<div class="row section-4">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline 4</h1>
<h2>Subhead 4</h2>
<p>Lorem Ipsum dolar Gamet</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-4.jpg" alt="Image 4">
</div>
</div>
</div>
</div>
</div>
</body>
</html>
As suggested in one of the comments to your question, it's more effective to use IntersectionObserver rather than the 'scroll' event listener.
If I'm correct, this snippet should help you achieve what you're looking for:
window.addEventListener("load", (event) => {
let options = {
rootMargin: "0px",
threshold: 0.8
};
const intersectionHandler = function(entries, observer) {
entries.forEach((entry) => {
if (entry.isIntersecting && entry.intersectionRatio > 0.8) {
entry.target.classList.remove("fadeOut");
entry.target.classList.add("fadeIn");
} else {
entry.target.classList.remove("fadeIn");
entry.target.classList.add("fadeOut");
}
});
};
let observer = new IntersectionObserver(intersectionHandler, options);
document.querySelectorAll(".section").forEach((row, index) => {
observer.observe(row);
});
});
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0 0 0 0;
font-family: sans-serif;
font-family: "Manrope", helvetiva, sans-serif;
transition: background-color 1s;
color: #fff;
background: linear-gradient(0deg, #100521 0%, #50357c 50%, #878290 100%);
}
header {
position: fixed;
top: 0;
width: 100%;
background: #fff;
z-index: 999;
}
header h1 {
font-family: "Lack";
font-size: 4em;
text-align: center;
padding: 10px;
color: #100521;
}
.row-container .row:first-child {
opacity: 1;
}
.row {
opacity: 0;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.row-inner {
display: grid;
grid-template-columns: 1fr 1fr;
position: sticky;
top: 0;
/* border: 1px solid yellow; */
padding: 0;
height: 100vh;
}
.column {
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
flex: 50%;
padding: 10px;
height: 100vh;
box-sizing: border-box;
}
.left-column {
background-color: transparent;
}
.right-column {
background-color: transparent;
}
h1 {
font-family: "Unbounded", helvetica, sans-serif;
}
h1 {
margin: 0;
font-size: 36px;
}
h2 {
margin: 0;
font-size: 24px;
}
p {
margin: 10px 0;
font-size: 18px;
line-height: 1.5;
}
img {
width: 100%;
height: auto;
}
.fadeIn {
animation-name: fadeIn;
animation-duration: 1s;
animation-fill-mode: forwards;
}
.fadeOut {
animation-name: fadeOut;
animation-duration: .5s;
animation-fill-mode: forwards;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
<!-- First row -->
<div class="row-container">
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline 1</h1>
<h2>Subhead 1</h2>
<p>Lorem Ipsum dolar Gamet</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-1.jpg" alt="Image 1">
</div>
</div>
</div>
</div>
<!-- Second row -->
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline 2</h1>
<h2>Subhead 2</h2>
<p>Lorem Ipsum dolar Gamet</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-2.jpg" alt="Image 2">
</div>
</div>
</div>
</div>
<!-- Third row -->
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline 3</h1>
<h2>Subhead 3</h2>
<p>Lorem Ipsum dolar Gamet</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-3.jpg" alt="Image 3">
</div>
</div>
</div>
</div>
<!-- Fourth row -->
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline 4</h1>
<h2>Subhead 4</h2>
<p>Lorem Ipsum dolar Gamet</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-4.jpg" alt="Image 4">
</div>
</div>
</div>
</div>
</div>
You'll notice I've made some minor modifications to your HTML and CSS, but the magic happens in the Javascript.
I've also used the window "load" event listener to create the observer options, object and callback function when the page is loaded.
You can check the IntersectionObserver API docs for more details on how it works and how to tweak the options or the callback to suit your needs.
Let me know if you have any questions for modifying my code. (I've also had to change your css a bit - the content of the row element was higher than the row element itself what led to some weird issues.)
I have rewritten most of it and it should now work for large row heights. The math for it is just a quadratic formula (Opacity of offset from center of the screen) with it's roots at the height of the row and a maximum at 0 offset with a value of 1.
/** #format */
const calculateOpacity = () => {
const ROW_CONTAINER = document.querySelector(".row-container");
const rows = ROW_CONTAINER.children;
const rowContainerBBox = ROW_CONTAINER.getBoundingClientRect();
console.log("calc")
for (const row of rows) {
const rowBBox = row.getBoundingClientRect();
const top = rowBBox.top - rowContainerBBox.top;
const bottom = rowBBox.bottom - rowContainerBBox.bottom;
if (rowBBox.height > rowContainerBBox.height) {
const opacityOfOffset = (offset) => {
const a = -1 / Math.pow(rowBBox.height, 2);
return Math.max(0, a * Math.pow(offset, 2) + 1);
};
row.style.opacity = opacityOfOffset(top + bottom);
continue;
}
const unvisibleHeightTop = -Math.min(0, top);
const unvisibleHeightBottom = Math.max(0, bottom);
const visibleHeight = rowBBox.height - unvisibleHeightTop - unvisibleHeightBottom;
row.style.opacity = visibleHeight / rowBBox.height;
}
};
document.querySelector(".row-container").addEventListener("scroll", calculateOpacity);
/** #format */
body {
height: 100%;
margin: 0;
padding: 0;
font-family: sans-serif;
font-family: "Manrope", helvetiva, sans-serif;
color: #fff;
}
header {
height: max(70px, 10vh);
position: fixed;
background-color: black;
width: 100%;
display: flex;
align-items: center;
}
header h1 {
margin: 0;
}
main {
padding-top: max(70px, 10vh);
height: 100%;
box-sizing: border-box;
}
.row-container {
background: linear-gradient(0deg, #100521 0%, #50357c 50%, #878290 100%);
height: calc(100vh - max(70px, 10vh));
overflow-y: auto;
}
.row {
height: 150vh;
display: flex;
align-items: center;
padding: 10vh 0;
}
.row .row-inner {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
}
.row .row-inner .col {
margin-inline: 10px;
display: flex;
align-items: center;
height: 100%;
}
.row img {
width: 100%;
height: auto;
}
.row h2 {
margin: 0;
font-family: "Unbounded", helvetica, sans-serif;
font-size: 36px;
}
.row h3 {
margin: 0;
font-size: 24px;
}
.row p {
margin: 10px 0;
font-size: 18px;
line-height: 1.5;
}
<!-- #format -->
<html>
<head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Manrope&family=Unbounded&family=Lack&display=swap" rel="stylesheet" />
</head>
<body>
<header>
<h1>My App</h1>
</header>
<main>
<div class="row-container">
<div class="row row-1">
<div class="row-inner">
<div class="col left">
<div class="col-inner">
<h2>Headline 1</h2>
<h3>Subhead 1</h3>
<p>Lorem ipsum dolor sit</p>
</div>
</div>
<div class="col right">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-1.jpg" alt="Image 1" />
</div>
</div>
</div>
<div class="row row-1">
<div class="row-inner">
<div class="col left">
<div class="col-inner">
<h2>Headline 1</h2>
<h3>Subhead 1</h3>
<p>Lorem ipsum dolor sit</p>
</div>
</div>
<div class="col right">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-1.jpg" alt="Image 1" />
</div>
</div>
</div>
<div class="row row-1">
<div class="row-inner">
<div class="col left">
<div class="col-inner">
<h2>Headline 1</h2>
<h3>Subhead 1</h3>
<p>Lorem ipsum dolor sit</p>
</div>
</div>
<div class="col right">
<img src="https://avatars.dicebear.com/api/adventurer/team-member-1.jpg" alt="Image 1" />
</div>
</div>
</div>
</div>
</main>
</body>
</html>
You didn't really ask for a web component, I just got carried away. This is a fun challenge! Anyway, here's a version that is NOT a web component. I also realized that I missed all the css that you provided. So I added that as well. I'm not sure if tweaking the css a little is verbotten ... but I did it. I also added a single [section] tag, which wraps everything but the app header, to make it more bullet proof ... Please let me know if I need to use your code exactly as you posted it.
I had a lot of trouble finding settings that provide a dramatic enough effect on both large screens and phones without some ugly hacks, so I opted for a compromise. You can optimize for either large or small by changing the rootMargin option for the IntersectionObserver. Smaller values make the fade effect more dramatic, but values that are too small cause the content to look washed out on smaller devices. As I'm posting this, rootMargin is set to "-25px". Apparantly you can use negative values, but as far as I can tell, you can only use "px" as the measurement. Other measurements don't seem to work.
Sooooo...
I used IntersectionObserver
const observer = new IntersectionObserver(fadeInOut, options);
One of the options IntersectionObserver takes is something called "threshold". I don't totally understand it, but MDN suggested that if you want to poll the viewport to determine element visibility, you should set the value of "threshold" as an array with many numbers ranging from 0 to 1. The example provided a function that generates 20 of them, so that's what I used.
function buildThresholds() {
const steps = 20;
const thresholds = [];
for (let i = 0; i <= steps; i++) {
let ratio = i/steps;
thresholds.push(ratio);
}
thresholds.push(0);
return thresholds;
}
Then I grabbed the collection of elements to watch using querySelectorAll(".row-container").
Then I looped through the elements and added each one to the observer's watch list.
observer.observe(elem);
Then, in the callback you provide when you create a new instance of IntersectionObserver, I set each element's opacity to the the intersectionRatio, which is a property provided by the instance of the IntersectionObserverEntry which is passed to the callback.
function fadeInOut(items, observer) {
items.forEach( (item) => {
item.target.style.opacity = item.intersectionRatio;
});
}
function buildThresholds() {
const steps = 20;
const thresholds = [];
for (let i = 0; i <= steps; i++) {
let ratio = i/steps;
thresholds.push(ratio);
}
thresholds.push(0);
return thresholds;
}
function fadeInOut(items, observer) {
items.forEach( (item) => {
item.target.style.opacity = item.intersectionRatio;
});
}
function scrollFade() {
const elems = document.querySelectorAll('.row-container');
const options = {
root: null,
rootMargin: "-25px",
threshold: buildThresholds()
};
const observer = new IntersectionObserver(fadeInOut, options);
for (let elem of elems) {
observer.observe(elem);
}
}
document.addEventListener('DOMContentLoaded', scrollFade);
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0 0 0 0;
font-family: sans-serif;
font-family: 'Manrope', helvetiva, sans-serif;
transition: background-color 1s;
color:#fff;
background: linear-gradient(0deg, #100521 0%, #50357c 50%, #878290 100%);
}
header {
position: fixed;
top: 0;
width: 100%;
background: #fff;
z-index: 999;
}
header h1 {
font-family: 'Lack';
font-size: 4em;
text-align: center;
padding: 10px;
color: #100521;
}
section {
margin-top: 6em;
}
h1 {
font-family: 'Unbounded', helvetica, sans-serif;
}
h1 {
margin: 0;
font-size: 36px;
}
h2 {
margin: 0;
font-size: 24px;
}
p {
margin: 10px 0;
font-size: 18px;
line-height: 1.5;
}
img {
width: 100%;
height: auto;
}
.row-container {
background-color: rgb(16, 5, 33);
min-height: 50vh;
}
.row-inner {
align-content: center;
align-items: center;
display: flex;
flex-direction: row;
flex-wrap: wrap-reverse;
padding: 10px;
gap: 10px;
}
.left-column {
flex: 1 1 70vw;
}
.right-column {
flex: 1 1 100px;
text-align: center;
}
<header>
<h1>My App</h1>
</header>
<section>
<div class="row-container">
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline One</h1>
<h2>Subhead One</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img slot="avatar" src="https://avatars.dicebear.com/api/adventurer/team-member-1.jpg" alt="Image 1">
</div>
</div>
</div>
</div>
</div>
<div class="row-container">
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline Two</h1>
<h2>Subhead Two</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img slot="avatar" src="https://avatars.dicebear.com/api/adventurer/team-member-2.jpg" alt="Image 1">
</div>
</div>
</div>
</div>
</div>
<div class="row-container">
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline Three</h1>
<h2>Subhead Three</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img slot="avatar" src="https://avatars.dicebear.com/api/adventurer/team-member-3.jpg" alt="Image 1">
</div>
</div>
</div>
</div>
</div>
<div class="row-container">
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline Four</h1>
<h2>Subhead Four</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img slot="avatar" src="https://avatars.dicebear.com/api/adventurer/team-member-4.jpg" alt="Image 1">
</div>
</div>
</div>
</div>
</div>
<div class="row-container">
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline Five</h1>
<h2>Subhead Five</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img slot="avatar" src="https://avatars.dicebear.com/api/adventurer/team-member-5.jpg" alt="Image 1">
</div>
</div>
</div>
</div>
</div>
<div class="row-container">
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<h1>Headline Six</h1>
<h2>Subhead Six</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<img slot="avatar" src="https://avatars.dicebear.com/api/adventurer/team-member-6.jpg" alt="Image 1">
</div>
</div>
</div>
</div>
</div>
</section>
Will this work? I used IntersectionObserver and set the opacity of the sections based on the intersection ratio of each section with the viewport. I pretty much took the idea straight from MDN.
MDN Intersection Observer API
class ScrollFade extends HTMLElement {
template;
shadow;
static observer = false;
constructor() {
super();
this.shadow = this.attachShadow({mode: 'open'});
if (!ScrollFade.observer) {
const buildThresholds = function() {
const steps = 20;
const thresholds = [];
for (let i = 0; i <= steps; i++) {
let ratio = i/steps;
thresholds.push(ratio);
}
thresholds.push(0);
return thresholds;
}
const options = {
root: null,
rootMargin: "0px",
threshold: buildThresholds()
};
ScrollFade.observer = new IntersectionObserver(ScrollFade.fadeInOut, options);
}
}
connectedCallback() {
const tmpl = document.querySelector('#scroll-fade-template').cloneNode(true);
const template = tmpl.content;
ScrollFade.observer.observe(this.shadow.host);
this.shadow.append(template);
}
disconnectedCallback() {
ScrollFade.observer.unobserve(this.shadow.host);
}
static fadeInOut(items, observer) {
items.forEach( (item) => {
item.target.style.opacity = item.intersectionRatio;
});
}
}
document.addEventListener('DOMContentLoaded', customElements.define('scroll-fade', ScrollFade));
body { margin: 0 }
img { width: 100%; }
<scroll-fade>
<h1 slot="headline">Headline One</h1>
<h2 slot="subhead">Subhead One</h2>
<img slot="avatar" src="https://avatars.dicebear.com/api/adventurer/team-member-1.jpg" alt="Image 1">
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip </p>
</div>
</scroll-fade>
<scroll-fade>
<h1 slot="headline">Headline Two</h1>
<h2 slot="subhead">Subhead Two</h2>
<img slot="avatar" src="https://avatars.dicebear.com/api/adventurer/team-member-2.jpg" alt="Image 2">
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip </p>
</div>
</scroll-fade>
<scroll-fade>
<h1 slot="headline">Headline Three</h1>
<h2 slot="subhead">Subhead Three</h2>
<img slot="avatar" src="https://avatars.dicebear.com/api/adventurer/team-member-3.jpg" alt="Image 1">
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip </p>
</div>
</scroll-fade>
<template id="scroll-fade-template">
<style>
.row-container {
background-color: seagreen;
height: 100vh;
overflow: auto;
}
.row-inner {
align-content: center;
display: flex;
flex-direction: row;
flex-wrap: wrap-reverse;
padding: 10px;
gap: 10px;
}
.left-column {
flex: 1 1 70vw;
}
.right-column {
flex: 1 1 100px;
text-align: center;
}
</style>
<div class="row-container">
<div class="row section">
<div class="row-inner">
<div class="column left-column">
<div class="column-inner">
<slot name="headline">Need Headline</slot>
<slot name="subhead">Need Subhead</slot>
<slot>Need Content</slot>
</div>
</div>
<div class="column right-column">
<div class="column-inner">
<slot name="avatar">Need Avatar</slot>
</div>
</div>
</div>
</div>
</div>
</template>
I had trouble wording my question, but here's the detail ! I've been struggling with how to get my navigation bullets (spans) to be highlighted when the current element is in viewport. I've initially tried using the same logic as a sidemenu tutorial I previously used elsewhere (by Web Cifar on youtube), but it doesn't quite work here.
If I console(log) the .bullet-slider class, they correctly show up. What the problem is, from what I gather, is the offsetTop of my const bulletSlide can't be calculated because the parentElement is another div and not the document (is this right?). I've looked into using an Intersection Observer instead, but being new to javascript I'm struggling in how I could implement it into my existing structure.
Any help and/or tips would be greatly appreciated ! Thank you !
/**
* By Alvaro Trigo - horizontal scroll
*/(function(){
init();
var g_containerInViewport;
function init(){
setStickyContainersSize();
bindEvents();
}
function bindEvents(){
window.addEventListener("wheel", wheelHandler);
}
function setStickyContainersSize(){
document.querySelectorAll('.sticky-container').forEach(function(container){
const stikyContainerHeight = container.querySelector('.main').scrollWidth;
container.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');
});
}
function isElementInViewport (el) {
const rect = el.getBoundingClientRect();
return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight;
}
function wheelHandler(evt){
const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container){
return isElementInViewport(container);
})[0];
if(!containerInViewPort){
return;
}
var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop;
var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop;
let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom;
if(g_canScrollHorizontally){
containerInViewPort.querySelector('.main').scrollLeft += evt.deltaY;
}
}
})();
const bulletSlide = document.querySelectorAll('.bullet-slide');
const bulletGreen = document.querySelectorAll('.bullet-grn');
const bulletPink = document.querySelectorAll('.bullet-pink');
/*bullet highlight */
window.addEventListener('scroll', ()=> {
let current = '';
bulletSlide.forEach(bulletSlide => {
const sectionTop = bulletSlide.offsetTop;
const sectionHeight = bulletSlide.clientHeight;
if (scrollY >= (sectionTop - sectionHeight / 3)) {
current = bulletSlide.getAttribute('id');
}
;
})
bulletGreen.forEach( span => {
span.classList.remove('.bullet-grn-active');
if(span.classList.contains(current)){
span.classList.add('.bullet-grn-active');
}
})
bulletPink.forEach( span => {
span.classList.remove('.bullet-pink-active');
if(span.classList.contains(current)){
span.classList.add('.bullet-pink-active');
}
})
})
html {
scroll-behavior: smooth;
}
body {
min-height: 100%;
overflow-x: hidden;
}
.frame {
min-height: 100vh;
min-width: 100vw;
padding-top: 20px;
}
.bg-grn {
background: #CCD5AE;
}
.bg-lp {
background: #E6C2CB;
}
.main {
overflow-x: hidden;
display: flex;
position: sticky;
top:0;
}
.main-slide {
min-width: 100vw;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper {
max-width: 600px;
margin: 0 auto;
}
.col-2 {
display: grid;
grid-template-columns: repeat(2, 1fr);
justify-content: space-between;
align-items: center;
gap: 80px;
}
.left-div {
display: flex;
flex-direction: column;
gap: 20px;
justify-content: center;
}
.col-1-3 {
display: grid;
grid-template-columns: 1fr 2fr;
align-items: center;
height: 100%;
gap: 60px;
}
.bullets {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
background-color: white;
margin-right: 10px;
cursor: pointer;
}
/* divider */
.divider {
height: 40vh;
width: 100vw;
background-color: #FFD6C2;
display: flex;
align-items: center;
}
.div-wrapper {
max-width: 600px;
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
gap: 20px;
}
<section>
<div class="sticky-container frame bg-grn">
<div class="main">
<div id="etudes" class="main-slide bullet-slide">
<div class="col-2 wrapper">
<div class="left-div">
<div class="slide-bullets">
<span class="etudes bullets bullet-grn"></span>
<span class="micro bullets bullet-grn"></span>
</div>
<h2 class="title bk">Les études</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. At hic esse iusto excepturi. Rerum assumenda obcaecati voluptas velit, hic autem!</p>
</div>
<div>
<div id="dates-etudes">
<p><span class="date">2017</span>Master en Marketing et Vente</p>
<p><span class="date">2015</span>Licence Langues Étrangères Appliquées</p>
<p><span class="date">2014</span>DUETI Business and Administration</p>
<p><span class="date">2013</span>DUT Techniques de Commercialisation</p>
</div>
</div>
</div>
</div>
<div id="micro" class="main-slide bullet-slide">
<div class="col-2 wrapper">
<div class="left-div">
<div class="slide-bullets">
<span class="etudes bullets bullet-grn"></span>
<span class="micro bullets bullet-grn"></span>
</div>
<h2 class="title bk">La micro-entreprise</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quos error hic totam provident delectus! Aliquid error debitis amet quos eaque?</p>
</div>
<div id="paper-container">
<p class="div-title">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Itaque, corporis! !</p>
</div>
</div>
</div>
</div>
</div>
</section>
<div class="divider">
<div class="div-wrapper">
<h3 class="div-title">Depuis janvier 2022</h3>
<p class="div-p">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Nisi ipsum eveniet voluptatem quis est nulla soluta ipsam voluptas fugiat odit..</p>
</div>
</div>
<section>
<div class="sticky-container frame bg-lp">
<div class="main">
<div id="pas1" class="main-slide bullet-slide">
<div class="col-1-3 wrapper">
<div class="left-div">
<div class="slide-bullets">
<span class="pas1 bullets bullet-pink"></span>
<span class="pas2 bullets bullet-pink"></span>
<span class="pas3 bullets bullet-pink"></span>
<span class="pas4 bullets bullet-pink"></span>
</div>
<h2 class="title">Mes premiers pas dans le web design</h2>
</div>
<div>
<div class="title-para">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Enim numquam vero recusandae provident, sapiente tempora sequi modi laboriosam velit dolorum!</p>
<div class="bg-pink-ptn">
<h4>Les axes de réflexion</h4>
<div class="list col-2">
<ul>
<li>l'aspect graphique et esthétique</li>
<li>l'objectif du site</li>
<li>le contenu & son organisation</li>
</ul>
<ul>
<li>les fonctionnalités</li>
<li>l'évolution prévue</li>
<li>la gestion du site</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="pas2" class="main-slide bullet-slide">
<div class="col-1-3 wrapper">
<div class="left-div">
<div class="slide-bullets">
<span class="pas1 bullets bullet-pink"></span>
<span class="pas2 bullets bullet-pink"></span>
<span class="pas3 bullets bullet-pink"></span>
<span class="pas4 bullets bullet-pink"></span>
</div>
<h2 class="title">Mes premiers pas dans le web design</h2>
</div>
<div class="title-para">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati consequatur molestias ab maxime, dolor dolorum esse incidunt dolores nulla alias?</p>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Atque ex perferendis molestias sequi et aliquid nam corrupti quis voluptatum enim.</span></p>
</div>
</div>
</div>
<div id="pas3" class="main-slide bullet-slide">
<div class="col-1-3 wrapper">
<div class="left-div">
<div class="slide-bullets">
<span class="pas1 bullets bullet-pink"></span>
<span class="pas2 bullets bullet-pink"></span>
<span class="pas3 bullets bullet-pink"></span>
<span class="pas4 bullets bullet-pink"></span>
</div>
<h2 class="title">Mes premiers pas dans le web design</h2>
</div>
<div class="title-para">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos, ratione? Iure deleniti mollitia ea provident labore alias quo minus placeat? Voluptates veritatis praesentium debitis officiis ducimus quae consectetur, qui laudantium modi eveniet aspernatur fugit, veniam rerum dolorum id temporibus provident!</p>
</div>
</div>
</div>
<div id="pas4" class="main-slide bullet-slide">
<div class="col-1-3 wrapper">
<div class="left-div">
<div class="slide-bullets">
<span class="pas1 bullets bullet-pink"></span>
<span class="pas2 bullets bullet-pink"></span>
<span class="pas3 bullets bullet-pink"></span>
<span class="pas4 bullets bullet-pink"></span>
</div>
<h2 class="title">Mes premiers pas dans le web design</h2>
</div>
<div class="title-para">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Numquam molestiae, minima quo voluptas deleniti aliquid blanditiis beatae! Officiis, eos commodi!</p>
</div>
</div>
</div>
</div>
</div>
I like to access content from sub drop down menu immediately without using scroll bar on left hand side as shown in the figure using html
Here is the code I used
<div class="col-sm-12">
<br/>
<button class="collapsible">Drop Down Main</button>
<div class="content"><p></p>
<ul>
<button class="collapsible">Drop Down-1</button>
<div class="content"><p></p>
<p>Line1 </p>
<p>Line 2</p>
<p><b>Line 3</b></p>
</div>
</ul>
<ul>
<button class="collapsible">Drop Down-2</button>
<div class="content"><p></p>
<p>Line1 </p>
<p>Line 2</p>
<p> <b>Line 3</b></p>
</div>
</ul>
<ul>
<button class="collapsible">Drop Down-3</button>
<div class="content"><p></p>
<p>Line1 </p>
<p>Line 2</p>
<p> <b>Line 3</b></p>
</div>
</ul>
<ul>
<button class="collapsible">Drop Down-4</button>
<div class="content"><p></p>
<p>Line1 </p>
<p>Line 2</p>
<p> <b>Line 3</b></p>
</div>
</ul>
</div>
<br/>
This is the style code I used for drop down and sub drop downs.
.collapsible {
background-color: #01579b;
color: white;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 20px;
}
.active, .collapsible:hover {
background-color: #0043b3;
}
.content {
padding: 0 18px;
max-height: 0px;
overflow: auto;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
Please let me know how we can use html to achieve this. Thanks in advance.
We can use the standard <details> HTML element:
let details = document.querySelectorAll('details>details');
// add toggle event on all sub sections
details.forEach(d => {
d.addEventListener("toggle", event => {
let current = event.target;
// close all others
if (current.open){
details.forEach(e => {
if (current !== e) e.open = false;
});
current.scrollIntoView({behavior: "smooth", block: "center", inline: "nearest"});
}
});
});
body{
padding: 1rem;
}
summary {
background-color: rgb(46, 46, 255);
color: white;
padding: 0.3rem;
cursor: pointer;
}
details>details {
margin-left: 1rem;
}
details>details>summary {
background-color: rgb(86, 86, 245);
}
details>details[open]>summary {
background-color: rgb(105, 166, 245);
}
details .info {
padding: .5rem;
border: 1px solid gray;
}
<details>
<summary>Drop down main</summary>
<details>
<summary>Drop down 1</summary>
<div class="info">ONE Lorem ipsum dolor sit amet, consectetur adipisicing elit. Commodi, sunt.</div>
</details>
<details>
<summary>Drop down 2</summary>
<div class="info">TWO Lorem ipsum dolor sit amet consectetur adipisicing elit. Aspernatur, illo exercitationem sequi voluptatum tempora minus rem amet magnam. Necessitatibus nihil dolores eaque sed quaerat ducimus aliquid cupiditate impedit quam laboriosam odit sequi,
numquam fuga neque! Optio aut at, omnis quasi amet cum rem id fuga velit error cupiditate commodi neque.</div>
</details>
<details>
<summary>Drop down 3</summary>
<div class="info">THREE Lorem ipsum dolor sit amet consectetur adipisicing elit. Iusto ad saepe ex obcaecati expedita nulla, nihil laborum esse excepturi natus amet non eligendi atque sint. Tenetur molestias perspiciatis libero perferendis, autem earum et eius numquam
repellat commodi sint dignissimos veritatis eaque ratione voluptatum nam molestiae voluptatibus ipsum illum! Id dolor quos consequuntur vero cumque tenetur, quaerat quam odit non illum exercitationem voluptates! Minima, quia dolore? Accusamus libero?</div>
</details>
<details>
<summary>Drop down 4</summary>
<div class="info">FOUR Lorem, ipsum dolor sit amet consectetur adipisicing elit. Alias cupiditate nobis odio iusto, ratione laborum ipsa tempora eos porro repellat recusandae dolore quasi adipisci explicabo consequuntur omnis eveniet asperiores culpa!</div>
</details>
</details>
We can use Element.scrollIntoView() to bring element in view. Play with the method arguments to get desired results.
You can use html as an anchor tag
like for me a navbar:
html:
<nav class="navbar background h-nav-resp">
<ul class=" navlist v-class-resp">
<li>Home</li>
<li>about</li>
<li>services</li>
<li>contact</li>
</ul>
<div class="rightNav v-class-resp">
<input type="text" name="search" id="search" />
<button class="btn btn-sm">search</button>
</div>
<div class="burger">
<div class="line"></div>
<div class="line"></div>
<div class="line"></div>
</div>
</nav>
and then I will just give the ID to every place as In I gave in my nav:
<section class="background firstSection" id="home">
<div class="box-main">
<div class="firsthalf">
<p class="text-big">The future of education is here!</p>
<p class="text-small">
In this country of 7 Billion we need to educate each and all of them
and we are proud to say that The future of education is here.
</p>
<div class="buttons">
<button class="btn">subscribe</button>
<button class="btn">watch video</button>
</div>
<div class="secondhalf">
<img src="img/Laptop.jpg" alt="laptop image" />
</div>
</div>
</div>
</section>
<section class="section" id="about">
<div class="paras">
<p class="SectionTag text-big">The end of your search is here.</p>
<p class="SectionSubTag text-small">
Education is about learning skills and knowledge. It also means
helping people to learn how to do things and support them to think
about what they learn. It's also important for educators to teach ways
to find and use information. Education needs research to find out how
to make it better. It helps people become better citizens, get a
better-paid job, shows the difference between good and bad. Education
shows us the importance of hard work and, at the same time, helps us
grow and develop. Thus, we are able to shape a better society to live
in by knowing and respecting rights, laws, and regulations.
</p>
</div>
<div class="thumbnail">
<img
src="https://source.unsplash.com/random/900×700/?Html"
alt="laptop image"
class="imgfluid"
/>
</div>
</section>
<hr />
<section class="section left" id="services">
<div class="paras">
<p class="SectionTag text-big">When coding meets children in India</p>
<p class="SectionSubTag text-small">
Through coding, students build essential literacy skills, gain an
understanding of logic and sequence, and learn the mechanics of
iteration. These tools support project-based learning and give
students the freedom to create, collaborate, hack, remix, and tinker
with their own unique designs.Coding classes are currently limited to
people with a laptop, internet connection, and paying capacity.
Further, very little content is available in the field which is
suitable for children and apt from the Indian context.
</p>
</div>
<div class="thumbnail">
<img
src="https://source.unsplash.com/random/900×700/?Javascript"
alt="laptop image"
class="imgfluid"
/>
</div>
</section>
<hr />
<section class="section">
<div class="paras">
<p class="SectionTag text-big">Why is programming useful?</p>
<p class="SectionSubTag text-small">
Programming also teaches them how software engineers use math in order
to solve problems in a logical and creative way. This is an important
reason that coding should be taught in schools, so children learn
these skills while they are young.Coding, to put it simply, is using
computer language to tell a computer what to do. The skills necessary
for coding include being able to analyze a problem, break it down,
engage critical thinking, and logic. This “thinking” element is often
referred to as computational thinking.
</p>
</div>
<div class="thumbnail">
<img
src="https://source.unsplash.com/random/900×700/?laptop"
alt="laptop image"
class="imgfluid"
/>
</div>
</section>
<section class="contact" >
<h1 class="text-center" id="contact">Contact Us</h1>
<div class="form">
<input
class="form-input"
type="name"
name="name"
id="name"
placeholder="enter your name"
/>
<input
class="form-input"
type="phone"
name="Phone"
id="phone"
placeholder="enter your phone"
/>
<input
class="form-input"
type="email"
name="email"
id="email"
placeholder="enter your email"
/>
<textarea class="form-input" name="text" id="text" cols="30" rows="10" maxlength="290" wrap="soft" placeholder="Elaborate your concern"></textarea>
<button class="btn btn-dark">Submit</button>
</div>
</section>
<footer class="background">
<p class="text-footer">
Copyright saraswati education-giving eduction online.com © 2022 - All rights reserved
</p>
<div class="designer"><p>Designed and developed by pranjal Rai</p></div>
</footer>
If you click on the link it will scroll at that position but!
add this
css:
html{
scroll-behavior: smooth;
}
It makes it good!
I'm creating toggle buttons that need some specific functions:
1) Show content on the first click (this works)
2) Hide content when you click on a different button (this works)
3) Hide content on the second click (this doesn't work)
Right now, if you click the same button twice it first slidesUp (because if you do click a different button, the previous content needs to be closed). Once it's up it then slidesDown, making it very jumpy.
Is there a way to make all 3 functions work??
Removing the " $(".assortiment").slideUp();" line fixes this jumpy problem, but that also stops function 2 from working...
function assortiment(e){
var assortimentid = e.id + "__js";
if ($("#" + assortimentid).display = "block"){
$(".assortiment").slideUp();
$("#" + assortimentid).slideToggle();
} else if ($("#" + assortimentid).display = "none"){
$("#" + assortimentid).slideToggle();
}
}
.assortiment {
display: none;
}
.btn {
border: 1px solid black;
border-radius: 10px;
padding: 10px;
width: 100px;
margin: 5px;
background-color: lightblue;
}
.btn:hover {
cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="btn" id="section1" onclick="assortiment(this)">Section 1</div>
<div class="btn" id="section2" onclick="assortiment(this)">Section 2</div>
<div class="btn" id="section3" onclick="assortiment(this)">Section 3</div>
<div class="assortiment" id="section1__js">
<p>SOME CONTENT 1</p>
<p>Lorem ipsum dolor sit amet, aliquip apeirian dissentiunt ex pro. Ad choro facilis offendit mel, et quo quot democritum. Aliquip quaestio periculis ad eam, legere altera reprehendunt eu his. Cu has virtute pericula definitionem, cu facete conclusionemque has, cu errem accusamus duo.
</p>
</div>
<div class="assortiment" id="section2__js">
<p>SOME CONTENT 2</p>
<p>Lorem ipsum dolor sit amet, aliquip apeirian dissentiunt ex pro. Ad choro facilis offendit mel, et quo quot democritum. Aliquip quaestio periculis ad eam, legere altera reprehendunt eu his. Cu has virtute pericula definitionem, cu facete conclusionemque has, cu errem accusamus duo.
</p>
</div>
<div class="assortiment" id="section3__js">
<p>SOME CONTENT 3</p>
<p>Lorem ipsum dolor sit amet, aliquip apeirian dissentiunt ex pro. Ad choro facilis offendit mel, et quo quot democritum. Aliquip quaestio periculis ad eam, legere altera reprehendunt eu his. Cu has virtute pericula definitionem, cu facete conclusionemque has, cu errem accusamus duo.
</p>
</div>
Well try to avoid inline javascript..Write a separate function for .btn click to toggle display...use slideToggle() jQuery to toggle the same element...and slideUp() with not() to hide other elements
Also use === for comparison in condition,...= is used to assigned a value...
Also the element.display = "none" is not a valid statement, it should be like element.css("display") === "none"
$(".btn").on("click", function() {
var item = "#" + $(this).attr("id") + "__js"
$(".assortiment").not(item).stop().slideUp();
$(item).stop().slideToggle();
})
.assortiment {
display: none;
}
.btn {
border: 1px solid black;
border-radius: 10px;
padding: 10px;
width: 100px;
margin: 5px;
background-color: lightblue;
}
.btn:hover {
cursor: pointer
}
p {
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="btn" id="section1">Section 1</div>
<div class="btn" id="section2">Section 2</div>
<div class="btn" id="section3">Section 3</div>
<div class="assortiment" id="section1__js">
<p>SOME CONTENT 1</p>
</div>
<div class="assortiment" id="section2__js">
<p>SOME CONTENT 2</p>
</div>
<div class="assortiment" id="section3__js">
<p>SOME CONTENT 3</p>
</div>
You are missing the .stop() method which stops the currently-running animation on the matched element or in other words, prevents repetition:
function assortiment(e){
var assortimentid = e.id + "__js";
if ($("#" + assortimentid).display = "block"){
$(".assortiment").stop().slideUp();
$("#" + assortimentid).stop().slideToggle();
} else if ($("#" + assortimentid).display = "none"){
$("#" + assortimentid).stop().slideToggle();
}
}
* {margin: 0; box-sizing: border-box} /* addition; more "fluent" */
.assortiment {
display: none;
}
.btn {
border: 1px solid black;
border-radius: 10px;
padding: 10px;
width: 100px;
margin: 5px;
background-color: lightblue;
}
.btn:hover {
cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="btn" id="section1" onclick="assortiment(this)">Section 1</div>
<div class="btn" id="section2" onclick="assortiment(this)">Section 2</div>
<div class="btn" id="section3" onclick="assortiment(this)">Section 3</div>
<div class="assortiment" id="section1__js">
<p>SOME CONTENT 1</p>
</div>
<div class="assortiment" id="section2__js">
<p>SOME CONTENT 2</p>
</div>
<div class="assortiment" id="section3__js">
<p>SOME CONTENT 3</p>
</div>
Try this
function assortiment(e){
var assortimentid = e.id + "__js";
if ($("#" + assortimentid).display == "block"){
$(".assortiment").hide();
$("#" + assortimentid).slideToggle();
} else if ($("#" + assortimentid).display == "none"){
$("#" + assortimentid).slideToggle();
}
Update your JS function defination to :
function assortiment(e){
var assortimentid = e.id + "__js";
$(".assortiment").not("#" + assortimentid).slideUp();
$("#" + assortimentid).slideToggle();
}
Full Snippet: and jsFiddle
function assortiment(e){
var assortimentid = e.id + "__js";
$(".assortiment").not("#" + assortimentid).slideUp();
$("#" + assortimentid).slideToggle();
}
.assortiment {
display: none;
}
.btn {
border: 1px solid black;
border-radius: 10px;
padding: 10px;
width: 100px;
margin: 5px;
background-color: lightblue;
}
.btn:hover {
cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="btn" id="section1" onclick="assortiment(this)">Section 1</div>
<div class="btn" id="section2" onclick="assortiment(this)">Section 2</div>
<div class="btn" id="section3" onclick="assortiment(this)">Section 3</div>
<div class="assortiment" id="section1__js">
<p>SOME CONTENT 1</p>
<p>Lorem ipsum dolor sit amet, aliquip apeirian dissentiunt ex pro. Ad choro facilis offendit mel, et quo quot democritum. Aliquip quaestio periculis ad eam, legere altera reprehendunt eu his. Cu has virtute pericula definitionem, cu facete conclusionemque has, cu errem accusamus duo.
</p>
</div>
<div class="assortiment" id="section2__js">
<p>SOME CONTENT 2</p>
<p>Lorem ipsum dolor sit amet, aliquip apeirian dissentiunt ex pro. Ad choro facilis offendit mel, et quo quot democritum. Aliquip quaestio periculis ad eam, legere altera reprehendunt eu his. Cu has virtute pericula definitionem, cu facete conclusionemque has, cu errem accusamus duo.
</p>
</div>
<div class="assortiment" id="section3__js">
<p>SOME CONTENT 3</p>
<p>Lorem ipsum dolor sit amet, aliquip apeirian dissentiunt ex pro. Ad choro facilis offendit mel, et quo quot democritum. Aliquip quaestio periculis ad eam, legere altera reprehendunt eu his. Cu has virtute pericula definitionem, cu facete conclusionemque has, cu errem accusamus duo.
</p>
</div>
I'm getting stuck on two things here that I'd appreciate the help with.
Background:
The banner displays a photo and some information. However this is not supposed to be everpresent. The banner has to, but not all the information. So there is an option to collapse it and expand it with an icon (like an accordion).
Problems
Because the panel has to be fixed, I had to position relative the content below it. Problem is, when I collapse it, the content is still respecting the position given. I'd like that content to respect the distance between each other instead so that if there is 20px between them, that would still be true on a collapsed view. (I tried margin and top) but no cigar.
And my main issue which I have no idea how to get it done is, I'd like the banner to collapse automatically on scroll. I know there is a scroll function out there, I just never used it before.
Here is my HTML:
<div id="header" class="header navbar navbar-fixed-top navbar-inverse" data-current-theme="navbar-inverse">
<p>menu & logo</p>
</div>
<div class="row">
<div class="col-xs-12">
<div class="banner clearfix">
<div class="collapser">
<i class="fa fa-chevron-up fa-fw collapse-icon"></i>
</div>
<div class="banner-info clearfix">
<div class="col-sm-12 col-md-2">
<div class="circle-container">
<img class="img-responsive" src="https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcTGjucaoN3fabOcumnr7RKTB3ICTJFLuLClnpiQUIR9oW4a11wb" alt="offender-img">
</div>
</div>
<div class="col-sm-12 col-md-10">
<div class="col-sm-12 col-md-3">
<div class="form-group">
<label class="control-label">Full Name</label>
<span>Floyd "Money" Mayweather</span>
</div>
<div class="form-group">
<label class="control-label">Some Label</label>
<span>Something Here</span>
</div>
</div>
<div class="col-sm-12 col-md-3">
<div class="form-group">
<label class="control-label">Offender ID#</label>
<span>123569863</span>
</div>
<div class="form-group">
<label class="control-label">Longer Label Example</label>
<span>Something Here with an ellipsis</span>
</div>
</div>
<div class="col-sm-12 col-md-3">
<div class="form-group">
<label class="control-label">Institution</label>
<span>Graterford</span>
</div>
<div class="form-group">
<label class="control-label">Some Link</label>
<span>Something Here</span>
</div>
</div>
<div class="col-sm-12 col-md-3">
<div class="form-group">
<label class="control-label">Institution</label>
<span>Graterford</span>
</div>
<div class="form-group">
<label class="control-label">Some Link</label>
<span href="#"><p>Something Here</p></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="container martop65">
<div class="row">
<div class="col-xs-12">
<p>Lorem ipsum dolor sit amet, et meis definitiones cum, audire iisque alterum no ius. Semper luptatum democritum has no, at sea audire inermis suscipiantur. Ei regione adipiscing ius. An est nonumy habemus, movet probatus recusabo eu eum. Hinc offendit te est, at his falli euripidis.
<br><br>
Pertinax scribentur ullamcorper in nec, sit dolor fastidii ei. Cetero pericula iudicabit no est, tale elitr ad has, eos sumo harum interesset eu. His ne fierent appareat. Vel paulo fierent eleifend id. Pri ut conceptam repudiandae theophrastus, enim periculis ius ex, te est numquam inimicus.
<br><br>
Congue deleniti deseruisse te eos, usu no brute laoreet. Nisl lorem zril eu qui. Vix tempor inimicus an, partem minimum cotidieque mel eu. Aperiam discere an mea, ea graecis scribentur mel, minim ludus saperet no vix. Has at sint sanctus. Eu docendi hendrerit liberavisse mel, ut eum viris voluptaria, eum error voluptua principes ex.
<br><br>
Vis te accumsan lucilius platonem. Possit prodesset eum in. No duo agam nullam detracto. At homero scaevola electram vel.</p>
</div>
</div>
</div>
CSS
body {
background-color: #dddddd;
}
.navbar {
border: none;
border-bottom: 2px solid #30373e;
font-size: 14px;
-webkit-box-shadow: 0 1px rgba(0,0,0,0.025);
box-shadow: 0 1px rgba(0,0,0,0.025);
z-index: 1040;
margin-bottom: 0;
height: 55px;
text-align:center;
color:#ccc;
}
.banner {
border: none;
-webkit-box-shadow: 0 2px 0 rgba(0,0,0,0.07);
box-shadow: 0 2px 0 rgba(0,0,0,0.07);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
border-radius: 5px;
margin-bottom: 20px;
position: fixed;
width: 100%;
background: #101113;
padding: 20px;
display: block;
top: 55px;
border-radius:0;
z-index: 1;
}
.banner .collapser {
position: absolute;
bottom: 10px;
color: #bbb;
}
.banner .circle-container {
position: relative;
left: 35px;
text-align: center;
width: 110px;
height: 110px;
display: flex;
overflow: hidden;
-webkit-border-radius: 100%;
-moz-border-radius: 100%;
-ms-border-radius: 100%;
border-radius: 100%;
border: 3px solid #bbb;
}
.banner .banner-info label {
color: rgba(248,151,29,0.77);
}
.banner .banner-info span {
display: block;
color: #bbb;
white-space: nowrap;
width: 85%;
overflow: hidden;
text-overflow: ellipsis;
}
.martop65 {
/* margin-top: 240px;*/
position:relative;
top:240px;
}
JQUERY
$('.collapser').click(function() {
$collapser = $(this);
$banner = $collapser.parent().find('.banner-info .circle-container').add($collapser.parent().find(".col-md-10 > .col-md-3 > .form-group:nth-of-type(2)"));
$banner.slideToggle(500, function() {
$collapser.find('.collapse-icon').toggleClass('fa-chevron-up fa-chevron-down');
});
});
Here is a CODEPEN
Thanks!