the javascript only works when some css rules are inline - javascript

I am trying to make an interactive web page with the css part and javascript separated from the html document.
sandbox.html (part of it):
<body>
<nav class="unify-bg">
<ul>
<li><a id="ipsum" style="top:-90px">Ipsum</a></li>
</ul>
</nav>
</body>
sandbox.css (part of it):
nav li a{
float:left;
margin: 0 5px;
color: #e4b05c;
color: white;
font-weight: bold;
width: 120px;
height: 100px;
background-color:#e4b05c;
position: relative;
top:-90px;
}
sandbox.js (part of it):
window.onload = function () {
document.getElementById("ipsum").addEventListener("mouseover", function () {
ipsum = this;
var t = setInterval(function () {
move(ipsum, t);
}, 10);
}, false);
}
function move(element, interval) {
var pos = element.style.top.replace("px", "");
if (pos > -10) clearInterval(interval);
else {
pos = parseInt(pos) + 10;
element.style.top = pos + "px";
}
}
somehow if I remove the inline style "top:-90px" from the list element (since the style is already in the *.css anyway), the javascript stops working. Can anyone explain why please and help me solve the problem? Thank you!

element.style only returns inline styles. Hence, without an inline top, it is an empty string,
If you want all applied styles, use getComputedStyle: window.getComputedStyle(element).top.

Related

How to change the text color of a transparent header on scroll, depending on the div it overlaps

I have a header with a transparent backgrounsd, and I am trying to get the text of the header to change colour between white and black depending on the background of the div it's overlapping.
So far I have managed to add a class of .color-menu to all the divs where I want the header to be black.
I then have it add a class of .dark-menu to the header when the .color-menu div reaches the top of the page.
The problem is that it only works for the first .colour-menu div. It will change to black when it is in the viewport and back to white for the next div but then when the next .color-menu div gets to the top it doesn't change.
So, it seems like the .each function isn't working but I am not sure how to fix it.
$(window).scroll(function() {
$('.color-menu').each(function(i){
var top_of_element = $(".color-menu").offset().top;
var bottom_of_element = $(".color-menu").offset().top + $(".color-menu").outerHeight();
var top_of_screen = $(window).scrollTop();
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
});
});
UPDATE: I have also tried using $(this) but it really throws off when it changes color.
$(window).scroll(function() {
$('.color-menu').each(function(i){
var top_of_element = $(this).offset().top;
var bottom_of_element = $(this).offset().top + $(this).outerHeight();
var top_of_screen = $(window).scrollTop();
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
});
});
Here is a simplified version of my code as an example:
$(document).ready(function() {
$(".white").addClass("color-menu");
$(".white-bold").addClass("color-menu");
$(".light").addClass("color-menu");
$(".light-bold").addClass("color-menu");
$(".bright").addClass("color-menu");
});
$(window).scroll(function() {
$('.color-menu').each(function(i){
var top_of_element = $(".color-menu").offset().top;
var bottom_of_element = $(".color-menu").offset().top + $(".color-menu").outerHeight();
var top_of_screen = $(window).scrollTop();
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
});
});
.header {
width: 100%;
background: rgba(0,0,0,0);
margin: 0;
padding:10px;
position: fixed;
text-align: center;
}
.header a {
color: white;
font-size: 2rem;
text-transform: uppercase;
}
.dark-menu a{
color: black;
}
.black {
background-color: black;
height: 200px;
}
.white, .white-bold, .light, .light-bold, .bright {
background-color: white;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header">
<a>This is the header</a>
</div>
<div class ="black"></div>
<div class ="white"></div>
<div class ="black"></div>
<div class ="white-bold"></div>
<div class ="black"></div>
<div class ="light"></div>
<div class ="black"></div>
<div class ="light-bold"></div>
<div class ="black"></div>
<div class ="bright"></div>
What is happening in your code is that on scroll, you loop through every color-menu div and add the class if it is the current one... but then the code continues to loop though the remaining elements in the array and removes it again because the page is not in the other div.
I've explained step-by-step the changes you need to get this to work after the example, but first you can see it working here:
Working Example:
$(document).ready(function() {
$(".white").addClass("color-menu");
$(".white-bold").addClass("color-menu");
$(".light").addClass("color-menu");
$(".light-bold").addClass("color-menu");
$(".bright").addClass("color-menu");
$(window).scroll(function() {
var inColorMenu = false; /* initialise var to store if we are in color-menu */
var top_of_screen = $(window).scrollTop(); /* just get this once outside loop */
/* Loop through each color-menu element and check if we are in one */
$('.color-menu').each(function(i) {
var top_of_element = $(this).offset().top;
var bottom_of_element = top_of_element + $(this).outerHeight();
/* if we are in a color-menu element, set our var to true and stop processing */
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
inColorMenu = true;
return false; /* N.B. need to return "false" to break from the "each" loop */
}
});
if (inColorMenu) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
});
});
.header {
width: 100%;
background: rgba(0, 0, 0, 0);
margin: 0;
padding: 10px;
position: fixed;
text-align: center;
}
.header a {
color: white;
font-size: 2rem;
text-transform: uppercase;
}
.header.dark-menu a {
color: black;
}
.black {
background-color: black;
height: 200px;
}
.white,
.white-bold,
.light,
.light-bold,
.bright {
background-color: white;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header">
<a>This is the header</a>
</div>
<div class="black"></div>
<div class="white"></div>
<div class="black"></div>
<div class="white-bold"></div>
<div class="black"></div>
<div class="light"></div>
<div class="black"></div>
<div class="light-bold"></div>
<div class="black"></div>
<div class="bright"></div>
How this works:
Declare a variable to record whether we are in a "color-menu" class or not, and initialise this to false, e.g.:
var inColorMenu = false;
When looping through $('.color-menu').each, if we are between the top and bottom of one of divs (which your code is already detecting), then set our variable to true to record this.
We can also return false to break the each loop and stop processing the rest of the elements (it will still work without this, we are just reducing the amount of processing required):
if ((top_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
inColorMenu = true;
return false; /* N.B. need to return "false" to break from the "each" loop */
}
Finally, after we finish our $('.color-menu').each loop, if inColorMenu is true, we know we are in a color-menu div so we add the dark-menu class to the header, otherwise we remove it:
if (inColorMenu) {
$(".header").addClass("dark-menu");
} else {
$(".header").removeClass("dark-menu");
}
Note: You need to use $(this) when getting the offset().top and outerHeight() so that you are getting the values for the current element in the loop. $(".color-menu") gets the values for an unspecified element with this class so will not work.

How to add width to an element using jquery each function?

I want to build a loading bar effect using two seperate divs inside each other. I got it all positioned and all that but how can I make one of them increase its width from %1 to %100 with transition? I want it to be filled in 10 sec.
Thanks.
<div class="loading-container">
<div class="outside-loading"></div>
<div class="inside-loading"></div>
</div>
Fairly simple with jQuery animate() which you can customize for step or easing and also use callbacks for start or complete as needed
$('.outside-loading').animate({width: '100%'}, 3000);// using 3 sec for demo
.outside-loading {
background: blue;
width: 0;
height: .5em
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="loading-container">
<div class="outside-loading"></div>
<div class="inside-loading"></div>
</div>
Vanilla Javascript
Create a function and increase the width with your set interval function. Add a conditional that checks if the width is 100% and if it is, then clear the interval. I also moved the divs within each other and set the display of the inner span tag to inline-block...
You can also target the elements textContent and display the widths progress in percent as well...
var i = 0;
function move() {
if (i == 0) {
i = 1;
var elem = document.getElementsByClassName("inside-loading");
var width = 1;
var id = setInterval(frame, 100);
function frame() {
if (width >= 100) {
clearInterval(id);
i = 0;
} else {
width++;
elem[0].style.width = width + "%";
elem[0].textContent = width + "%";
}
}
}
}
move();
.outside-loading {
width: 100%;
height: 30px;
background-color: grey;
}
.inside-loading {
display: inline-block;
width: 1%;
height: 100%;
background-color: red;
text-align: right;
vertical-align: middle;
font-size: 30px;
font-weight: bold;
font-family: Arial, Helvetica, sans-serif;
}
<br><br><br>
<div class="loading-container">
<div class="outside-loading">
<span class="inside-loading">
</span>
</div>
</div>

How to make jquery scrolling effect work on multiple element/classes?

I'm trying to make a very light script for multiple classes class"demo" that can work on my onScrollDown responsive animation.
I don't really understand about writing arrays. but, I believe that if I use document.getElementsByClassName("demo")[i] , i < 0 and some function(i) I can implement it for individual classes. Because I use getBoundingClientRect() instead of fixed value.
So, how can I write it correctly using i as arrays?
Thank you..
Here is my working script :
<script>
var e = document.getElementById("demo");
var rect = e.getBoundingClientRect();
var x = rect.top;
$(window).bind('scroll', function () {
if ($(window).scrollTop() > x-300) {
$('#demo').addClass('animate');
} else {
$('#demo').removeClass('animate');
}
});
</script>
*work only for a single element.
Here is what I'm trying to do, that not working yet
<script>
var e = document.getElementsClassName("test")[i];
var rect = e.getBoundingClientRect();
var x = rect.top;
var i;
for (i = 0; i < e.length; i++) {
$(window).bind('scroll', function (i) {
if ($(window).scrollTop() > x-300) {
$e.addClass('animate');
} else {
$e.removeClass('animate');
}
});
}
</script>
CSS :
<style>
.test {
background:#345;
color:#FFF;
height:2em;
padding:.5em;
top:50px;
margin-top: 100px;
width:100%;
}
.animate {
width: 60px;
}
</style>
HTML
<div style="color: red; margin-bottom: 400px;">(Top!)</div>
<div class="test" id="demo">Menu</div>
<div class="test" id="demo">Menu</div>
<div class="test" id="demo">Menu</div>
<div style="color: red; margin-top: 400px;">(Bottom!)</div>
Okay so I've achieved what you're trying to do. Here are the changes I made:
Used the JQuery each function. This will loop all of the demo elements every time a scroll is detected. There are other ways of looping the elements but because you've already imported JQuery we may as well use it's functions.
Changed #demo to .demo. In other words, I've changed id to class. id should only be used when working with elements that are completely unique. In this case, there are multiple demos so we use class instead.
Final code (as you scroll each element will turn red showing that the animate class has been added:
$(window).on('scroll', function() {
$('.demo').each(function(i, obj) {
var rect = obj.getBoundingClientRect();
var x = rect.top;
if ($(window).scrollTop() > x - 300) {
$(obj).addClass('animate');
} else {
$(obj).removeClass('animate');
}
});
});
.body {
height: 200vh;
background-color: #f1f1f1;
}
.demo {
height: 200px;
width: 100%;
background-color: #f9f9f9;
}
.demo.animate {
background-color: #ff0000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="body">
<div class="demo"></div>
<div class="demo"></div>
<div class="demo"></div>
<div class="demo"></div>
</div>
There are few notes in regards to your code:
In jQuery you can get elements offset by using .offset() function.
you should not use the same id more than once per page.
.bind() has been deprecated since jQuery 3.0. Use .on() instead.
To toggle class you can use .toggleClass(className, state). State is used to determine if you want to remove or add the class.
See this example:
$(window).on('scroll', function() {
jQuery(".test").each(function() {
let isTop = $(window).scrollTop() > jQuery(this).offset().top - 300;
jQuery(this).toggleClass('animate', isTop);
});
});
.test {
background: #345;
color: #FFF;
height: 2em;
padding: .5em;
top: 50px;
margin-top: 100px;
width: 100%;
}
.animate {
width: 60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="color: red; margin-bottom: 400px;">(Top!)</div>
<div class="test">Menu</div>
<div class="test">Menu</div>
<div class="test">Menu</div>
<div style="color: red; margin-top: 400px;">(Bottom!)</div>

How can I get and set style properties of an object that come from a class?

I have a simple animation function that simulates a button being pushed, by varying the width:
function bPress(b) {
var w = (parseFloat(b.style.width)*0.96);
if (b.style.width.substr(-1)=="%") {
var s ="%";
}
else {
var s = "em";
}
b.style.width = w +s;
b.onmouseup = function () {
w = (parseFloat(b.style.width)/0.96);
b.style.width = w+s;
// etc.
}
This was working well until I started cleaning up my code and changed inline CSS style declarations to classes. I previously had, for example:
<div style= 'height: 1.5em; width: 100%; margin: 0 auto; margin-top: 0.2em; font: inherit; font-weight:bold' onclick='checkSave("continue")' onmousedown='bPress(this)'>Continue</div>
I moved the CSS parts to a new class:
.response_button {
height: 1.5em;
width: 100%;
margin: 0 auto;
margin-top: 0.2em;
font: inherit;
font-weight:bold
}
... avoiding repetition and of course simplifying the div tags.
But the animations stopped working. After some experimenting, I eventually came up with a temporary solution by moving the width back into an inline style declaration. But this seems wrong.
So 2 questions:
Why does this.style.width not work if the width is declared inside a class?
Is there a way to get and set a div's properties if they are declared inside a class?
Edit: For completeness, using nick zoum's answer, here is the modified bPress function:
function bPress(b) {
var w_px = window.getComputedStyle(b).width;
var w_int = (parseInt(w_px));
b.style.width = Math.round(w_int * 0.96) + "px";
b.onmouseup = function () {
b.style.width = w_px;
}
}
You can use getComputedStyle to get all of the calculated style properties of an element.
var dom = document.querySelector("#foo");
console.log(getComputedStyle(dom).backgroundColor);
#foo {
background-color: red;
width: 10px;
height: 10px;
}
<div id="foo"></div>

Using JS to cycle list while keeping in line with text

Related to my question seen here: Keeping list inline with text while keeping list vertically positioned
Having trouble cycling through a list using js while keeping the list in-line with some text. Floating the text left solves the problem, until i have to format and center the text/list.
what i have so far: http://jsfiddle.net/pthbK/
trying to achieve something similar to: https://www.youeye.com/
The list appends up for some reason, causing the text to appear slightly below the list. Goal is to get list appearing directly beside the list (to the left in my case).
<center>
<div id = "text">Sometext </div>
<ul id = "ticker">
<li>3</li>
<li>2</li>
<li>1</li>
</ul>
#ticker {
height: 40px;
overflow: hidden;
list-style-type: none;
list-style-position: oustide;
padding: 0;
display:inline-block;
}
#ticker li {
height: 40px;
}
#text {
display: inline;
}
function tick(){
$('#ticker li:first').animate({'opacity':0}, 200, function () { $(this).appendTo($('#ticker')).css('opacity', 1); });
}
setInterval(function(){ tick () }, 4000);
HTML:
<div class="center">You ate an <span id="text"></span>.</div>
JavaScript:
var i = 0,
texts = ['apple', 'banana', 'orange'];
function cycleText() {
$("#text").text(texts[i]);
if ((i += 1) === texts.length) {
i = 0;
}
}
cycleText();
setInterval(cycleText, 1000);
FIDDLE

Categories