I need help trying to complete a JavaScript effect. I'm looking to accomplish the effect on this site https://www.lucidmotors.com/ - in the third section down on the home page you can see the text scroll/reveal is smooth over the other text.
I found this option on codepen https://codepen.io/Bes7weB/pen/zYKoexK similar to the effect I need, but its a little to choppy I need it to be smoother.
JS
var textWrapper = document.querySelector(".ml3");
textWrapper.innerHTML = textWrapper.textContent.replace(
/\S/g,
"<span class='letter'>$&</span>"
);
var letter = document.querySelectorAll(".letter");
var i = 0;
var currentID = 0;
var slideCount = letter.length;
document.addEventListener("scroll", (e) => {
let scrolled =
document.documentElement.scrollTop /
(document.documentElement.scrollHeight -
document.documentElement.clientHeight);
// var nextID = currentID + 1;
// if (nextID < slideCount) {
// letter[nextID].style.setProperty(
// "--percentage",
// `${scrolled / 1}` * nextID
// );
// }
// currentID = nextID;
letter.forEach(function (l, i) {
// console.log("====",i / letter.length, i, letter.length)
if (i / letter.length < scrolled) {
l.style.setProperty("--percentage", 1);
} else {
l.style.setProperty("--percentage", 0);
}
});
});
CSS
:root {
--percentage: 0;
}
body {
background-color: #000;
margin: 0;
height: 600vh;
}
.ml3 {
position: sticky;
top: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
span {
font-family: Helvetica;
margin: 0;
padding: 0;
font-size: 48px;
color: #fff;
letter-spacing: -0.3px;
}
.ml3 span {
opacity: var(--percentage);
}
HTML
<div class="ml3">
<h1>THIS IS MY TEXT THAT IT'S GOING TO SHOW IN SCROLL</h1>
</div>
Any assistance would be great
This is probably what you're looking for, find it quite interesting and I think my answer can be improved, if you're interested only in the vertical scroll you should check the window.scrollY variable as well.
var textWrapper = document.querySelector(".ml3");
textWrapper.innerHTML = textWrapper.textContent.replace(
/\S/g,
"<span class='letter'>$&</span>"
);
var letter = document.querySelectorAll(".letter");
document.addEventListener("scroll", (e) => {
let scrolled =
document.documentElement.scrollTop /
(document.documentElement.scrollHeight -
document.documentElement.clientHeight) *
letter.length;
letter.forEach(function(l, i) {
if ((scrolled - i) > 1)
l.style.setProperty("--percentage", 1);
else if ((scrolled - i) < 0.2)
l.style.setProperty("--percentage", 0.2);
else
l.style.setProperty("--percentage", (scrolled - i));
});
});
:root {
--percentage: 0.2;
}
body {
background-color: #000;
margin: 0;
height: 600vh;
}
.ml3 {
position: sticky;
top: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
span {
font-family: Helvetica;
margin: 0;
padding: 0;
font-size: 48px;
color: #fff;
letter-spacing: -0.3px;
}
.ml3 span {
opacity: var(--percentage);
}
<div class="ml3">
<h1>THIS IS MY TEXT THAT IT'S GOING TO SHOW IN SCROLL</h1>
</div>
I am using this typewriter effect made with JavaScript, HTML and CSS (method seen below) but I am wanting to take it a step further. Is there a way I can change the font of each word that is typed? I've looked around for solutions but I honestly don't even know what to search for. Please let me know if this is possible.
var words = ['Design','Create','Dream', 'Inspire'],
currentStep = 0,
textEl = document.querySelector('.change-text'),
oldWord = '';
setTimeout(changeWord, 2000);
function changeWord() {
oldWord = textEl.innerHTML;
// check if there is a word atm or not
if (oldWord.length < 1) {
if (currentStep !== words.length -1) {
currentStep ++;
}else {
currentStep = 0;
}
addNextWord();
} else {
setTimeout(deleteWord, 1400);
}
};
function deleteWord() {
var WordLength = oldWord.length,
currentWord = textEl.innerHTML,
currentLength = currentWord.length;
// The word is deleted so, start adding in the new one
if (currentLength < 1) {
changeWord();
return;
}
// Remove a charachter
textEl.innerHTML = currentWord.substring(0, currentLength - 1);
setTimeout(deleteWord, 140);
}
function addNextWord() {
var currentWord = textEl.innerHTML,
currentLength = currentWord.length,
nextWord = words[currentStep],
nextWordLength = nextWord.length;
if (currentLength === nextWordLength) {
changeWord();
return;
}
// add a charachter
textEl.innerHTML = nextWord.substring(0, currentLength + 1);
setTimeout(addNextWord, 240);
}
#first-section{
z-index: 4;
background-image: linear-gradient(to top, #205ba8 0%, #537895 100%);
position: relative;
width: 100%;
min-height: 100vh;
display: flex;
}
.inspire{
padding: 0;
margin: 0;
position: absolute;
top: 0;
left: 10%;
color: #fff;
font-size: 50px;
font-weight: 600;
font-family: sans-serif;
}
.change-text {
position: absolute;
bottom: 0;
left: 10%;
color: #fff;
line-height: 500px;
font-size: 70px;
font-weight: 900;
cursor: context-menu;
}
#keyframes blinking {
0% { opacity: 0; }
50% { opacity: 0; }
51% { opacity: 1; }
100% { opacity: 1; }
}
.change-text:after {
content: '_';
animation: blinking 1.2s infinite;
}
<section id="first-section">
<h1 class="inspire" data-aos="fade-right">
HERE TO:
</h1>
<div class="change-text" data-aos="fade-right">Design</div>
</section>
you can use array of objects for the words.
Add your custom fonts to each word.
And then change the font dynamically.
I have tweaked the timer to show it quick between.
var words = [
{
word: 'Design',
font: 'Cursive'
},
{
word: 'Create',
font: 'Serif'
},
{
word: 'Dream',
font: 'Sans-Serif'
},
{
word: 'Inspire',
font: `'Pangolin', cursive`
}
],
currentStep = 0,
textEl = document.querySelector('.change-text'),
oldWord = '';
setTimeout(changeWord, 2000);
function changeWord() {
oldWord = textEl.innerHTML;
// check if there is a word atm or not
if (oldWord.length < 1) {
if (currentStep !== words.length -1) {
currentStep ++;
}else {
currentStep = 0;
}
textEl.style.fontFamily = words[currentStep].font;
addNextWord();
} else {
setTimeout(deleteWord, 100);
}
};
function deleteWord() {
var WordLength = oldWord.length,
currentWord = textEl.innerHTML,
currentLength = currentWord.length;
// The word is deleted so, start adding in the new one
if (currentLength < 1) {
changeWord();
return;
}
// Remove a charachter
textEl.innerHTML = currentWord.substring(0, currentLength - 1);
setTimeout(deleteWord, 140);
}
function addNextWord() {
var currentWord = textEl.innerHTML,
currentLength = currentWord.length,
nextWord = words[currentStep].word,
nextWordLength = nextWord.length;
if (currentLength === nextWordLength) {
changeWord();
return;
}
// add a charachter
textEl.innerHTML = nextWord.substring(0, currentLength + 1);
setTimeout(addNextWord, 240);
}
#import url('https://fonts.googleapis.com/css2?family=Pangolin&display=swap');
#first-section{
z-index: 4;
background-image: linear-gradient(to top, #205ba8 0%, #537895 100%);
position: relative;
width: 100%;
min-height: 100vh;
display: flex;
}
.inspire{
padding: 0;
margin: 0;
position: absolute;
top: 0;
left: 10%;
color: #fff;
font-size: 50px;
font-weight: 600;
font-family: sans-serif;
}
.change-text {
position: absolute;
bottom: 0;
left: 10%;
color: #fff;
line-height: 500px;
font-size: 70px;
font-weight: 900;
cursor: context-menu;
}
#keyframes blinking {
0% { opacity: 0; }
50% { opacity: 0; }
51% { opacity: 1; }
100% { opacity: 1; }
}
.change-text:after {
content: '_';
animation: blinking 1.2s infinite;
}
<section id="first-section">
<h1 class="inspire" data-aos="fade-right">
HERE TO:
</h1>
<div class="change-text" data-aos="fade-right"></div>
</section>
Follow my example i add a simple if, engines the counter of array word and finally change font.
var words = ['Design','Create','Dream', 'Inspire'],
currentStep = 0,
textEl = document.querySelector('.change-text'),
oldWord = '';
setTimeout(changeWord, 2000);
function changeWord() {
oldWord = textEl.innerHTML;
// check if there is a word atm or not
if (oldWord.length < 1) {
if (currentStep !== words.length -1) {
currentStep ++;
}else {
currentStep = 0;
}
if(currentStep == 0){
textEl.style.fontFamily = "Impact,Charcoal,sans-serif";
}else if(currentStep== 1){
textEl.style.fontFamily = "Times New Roman";
}else if(currentStep == 2){
textEl.style.fontFamily = "Palatino Linotype";
}else if(currentStep == 3){
textEl.style.fontFamily = "Georgia";
}
addNextWord();
} else {
setTimeout(deleteWord, 1400);
}
};
function deleteWord() {
var WordLength = oldWord.length,
currentWord = textEl.innerHTML,
currentLength = currentWord.length;
// The word is deleted so, start adding in the new one
if (currentLength < 1) {
changeWord();
return;
}
// Remove a charachter
textEl.innerHTML = currentWord.substring(0, currentLength - 1);
setTimeout(deleteWord, 140);
}
function addNextWord() {
var currentWord = textEl.innerHTML,
currentLength = currentWord.length,
nextWord = words[currentStep],
nextWordLength = nextWord.length;
if (currentLength === nextWordLength) {
changeWord();
return;
}
// add a charachter
textEl.innerHTML = nextWord.substring(0, currentLength + 1);
setTimeout(addNextWord, 240);
}
#first-section{
z-index: 4;
background-image: linear-gradient(to top, #205ba8 0%, #537895 100%);
position: relative;
width: 100%;
min-height: 100vh;
display: flex;
}
.inspire{
padding: 0;
margin: 0;
position: absolute;
top: 0;
left: 10%;
color: #fff;
font-size: 50px;
font-weight: 600;
font-family: sans-serif;
}
.change-text {
position: absolute;
bottom: 0;
left: 10%;
color: #fff;
line-height: 500px;
font-size: 70px;
font-weight: 900;
cursor: context-menu;
}
#keyframes blinking {
0% { opacity: 0; }
50% { opacity: 0; }
51% { opacity: 1; }
100% { opacity: 1; }
}
.change-text:after {
content: '_';
animation: blinking 1.2s infinite;
}
<section id="first-section">
<h1 class="inspire" data-aos="fade-right">
HERE TO:
</h1>
<div class="change-text" data-aos="fade-right">Design</div>
</section>
You can add all the fonts that you wish to use to an array, then create a function that selects them randomly.
var fonts = ['verdana', 'arial', 'timesNewRoman'];
function changeFont() {
var font = fonts[Math.floor(Math.random() * fonts.length)];
textEl.style.fontFamily = font;
}
Then call this function right after you call addNextWord
function changeWord() {
oldWord = textEl.innerHTML;
// check if there is a word atm or not
if (oldWord.length < 1) {
if (currentStep !== words.length -1) {
currentStep ++;
}else {
currentStep = 0;
}
addNextWord();
changeFont(); // Call changeFont Here!!
} else {
setTimeout(deleteWord, 1400);
}
}
I'd like to do the fade in the other side : fadeIn from down to up and not like now, fadeOut down to up
var $elem = $('.test.fade');
for (var i = 0; i <= 5; i++) {
$elem.clone().appendTo('body');
}
$(window).scroll(function() {
$('.fade').each(function() {
var bounds = this.getBoundingClientRect(),
op = Math.max((bounds.height + Math.min(bounds.top, 0)) / bounds.height, 0);
$(this).css('opacity', op);
});
});
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.test {
height: 70vh;
width: 30%;
background-color: rgba(0, 0, 0, 0.6);
margin: 1em auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test fade"></div>
jsfiddle
Thank you for help.
Change the opacity calculation to this:
op = Math.max((bounds.height - Math.max(bounds.top, 0)) / bounds.height, 0);
So it becomes dependent on the bottom border of the boxes.
I have an animation with several span, I want them all to be separated and can be read completely.
window.horizontalScroller = function($elem) {
var left = parseInt($elem.css("left"));
var temp = -1 * $('#horizontalScroller > div').height();
if (left < temp) {
left = $('#horizontalScroller').height()
$elem.css("left", left);
}
$elem.animate({
left: (parseInt(left) - 60)
}, 11000, function() {
window.horizontalScroller($(this))
});
}
$(document).ready(function() {
var i = 0;
$("#horizontalScroller > span").each(function() {
$(this).css("left", i);
i += 60;
window.horizontalScroller($(this));
});
});
#horizontalScroller {
position: absolute;
width: 300px;
height: 300px;
border: 1px solid red;
overflow: hidden;
}
#horizontalScroller>span {
position: absolute;
border: 1px solid blue;
display: inline-block;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="horizontalScroller">
<span>100 characteres</span>
<span>110 characteres</span>
<span>120 characteres</span>
<span>130 characteres</span>
<span>140 characteres</span>
<span>150 characteres</span>
</div>
Try updating your $(document).ready to be like below:
$(document).ready(function() {
var i = 0;
$("#horizontalScroller > span").each(function () {
$(this).css("left", i);
i += 100;
window.horizontalScroller($(this));
});
});
If you only want to separate them then you can just increse the i:
$(document).ready(function() {
var i = 0;
$("#horizontalScroller > span").each(function () {
$(this).css("left", i);
i += 110;
window.horizontalScroller($(this));
});
});
But the whole animation breaks after some time, so I recommend a different approach or some heavy optimization.
I have this simple jsfiddle example: https://jsfiddle.net/fLp74gnu/
As the example says, the onlclick function shows/hides the download-icon element. How to show on click and hide on hover out?
var divs = document.getElementsByTagName("div");
var parents = document.getElementsByClassName("main-cell");
for (var i = 0; i < parents.length; i++) {
parents[i].onclick = function () {
toggleChildren(this);
};
}
function toggleChildren(elem) {
for (var i = 0; i < divs.length; i++) {
if (divs[i] == elem) {
for (var ii = 1; ii <= 5; ii++) {
if (divs[i + ii].style.display == "none") {
divs[i + ii].style.display = "block";
} else {
divs[i + ii].style.display = "none";
}
}
}
}
}
.main-cell {
background: #bbb;
width: 200px;
height: 130px;
border-radius: 7%;
}
.main-cell:hover {
background: #999;
}
.download-icon {
background: rgba(0, 0, 0, .8);
width: 100%;
height: 100%;
border-radius: 7%;
display: none;
}
<div class="main-cell">
<div class="download-icon"></div>
</div>
It is very easy.
.main-cell {
background:transparent;/*set to transparent so the user can't see it but the element will still have height and width*/
width: 200px;
height: 130px;
border-radius: 7%;
}
.main-cell:hover {
background: #999;/*the element is visible but when the user hovers over it it will take a color and reappear*/
}
Do you mean something like following:
jsfiddle
var divs = document.getElementsByTagName("div");
var parents = document.getElementsByClassName("main-cell");
for (var i=0; i<parents.length; i++) {
parents[i].onclick = function() { toggleChildren(this); console.log(this);};
parents[i].onmouseleave = function(){
this.removeChild(document.getElementById('DELETEME'));
};
}
function toggleChildren(elem) {
for (var i=0; i<divs.length;i++) {
if (divs[i] == elem) {
for (var ii=1; ii<=5; ii++) {
if (divs[i+ii].style.display == "none") {
divs[i+ii].style.display = "block";
} else {
divs[i+ii].style.display = "none";
}
}
}
}
}
.main-cell {
background: #bbb;
width: 200px;
height: 130px;
border-radius: 7%;
}
.main-cell:hover {
background: #999;
}
.download-icon {
background: rgba(0,0,0,.8);
width: 100%;
height: 100%;
border-radius: 7%;
display: none;
}
<div class="main-cell"><div ID="DELETEME" class="download-icon"></div></div>
Is that the behaviour ? ( may be you only want to remove the class ? )
Edit:
parents[i].onmouseleave = function(){
var el = this.getElementsByTagName('div');
el[0].classList.remove('download-icon');
};
parents[i].onmouseover = function(){
var el = this.getElementsByTagName('div');
el[0].classList.add('download-icon');
// el[0].style.display = "none"; if you want ed to appear in that way
};
In this way you are not removing the element but the class. ( and adding it again ).