How do you get an element's inner height, without padding and borders?
No jQuery, just pure JS, and a cross-browser solution (IE7 included)
var style = window.getComputedStyle(document.getElementById("Example"), null);
style.getPropertyValue("height");
The above version will work in modern browsers. Please check currentStyle for IE browsers.
clientHeight - give the height including padding but without the
borders.
getComputedStyle - a way to tap into the CSS rules of an element and retrieve a property's value (padding)
Using parseInt is a way to strip away units and leave only the numeric value (which is in pixels)
parseFloat can also be used for more precise sub-pixel measurements
Note that all values will automatically be converted by the DOM API to pixels
function getInnerHeight( elm ){
var computed = getComputedStyle(elm),
padding = parseInt(computed.paddingTop) + parseInt(computed.paddingBottom);
return elm.clientHeight - padding
}
DEMO:
// main method
function getInnerHeight( elm ){
var computed = getComputedStyle(elm),
padding = parseInt(computed.paddingTop) + parseInt(computed.paddingBottom);
return elm.clientHeight - padding
}
// demo utility function
function printInnerHeight( selector ){
console.clear()
console.log(
getInnerHeight( document.querySelector(selector) )
)
}
body{ display: flex; padding:0; margin: 0; }
div{ flex: 1; }
.demo1{
padding-top: 2vh;
padding-bottom: 1vh;
margin: 30px;
border: 10px solid salmon;
box-sizing: border-box;
outline: 1px solid red;
}
.demo2{
padding-top: 2vh;
padding-bottom: 4vh;
margin: 30px;
border: 10px solid salmon;
border-bottom-width: 0;
height: 150px;
outline: 1px solid red;
}
p::before{
content: '';
display: block;
height: 100%;
min-height: 50px;
background: lightgreen;
}
<div>
<h2>inner height should be ~50px</h2>
<button onclick="printInnerHeight('.demo1')">Get Inner Height</button>
<p class='demo1'></p>
</div>
<div>
<h2>inner height should be ~150px</h2>
<button onclick="printInnerHeight('.demo2')">Get Inner Height</button>
<p class='demo2'></p>
</div>
EDIT from comments:
http://jsfiddle.net/hTGCE/1/ (a bit more code then expected)
in the internet you find functions like this:
function getRectangle(obj) {
var r = { top: 0, left: 0, width: 0, height: 0 };
if(!obj)
return r;
else if(typeof obj == "string")
obj = document.getElementById(obj);
if(typeof obj != "object")
return r;
if(typeof obj.offsetTop != "undefined") {
r.height = parseInt(obj.offsetHeight);
r.width = parseInt(obj.offsetWidth);
r.left = r.top = 0;
while(obj && obj.tagName != "BODY") {
r.top += parseInt(obj.offsetTop);
r.left += parseInt(obj.offsetLeft);
obj = obj.offsetParent;
}
}
return r;
}
if you want to subtract the padding / border-width is set in the css-file and not dynamic in the style attribute:
var elem = document.getElementById(id);
var borderWidth = 0;
try {
borderWidth = getComputedStyle(elem).getPropertyValue('border-top-width');
} catch(e) {
borderWidth = elem.currentStyle.borderWidth;
}
borderWidth = parseInt(borderWidth.replace("px", ""), 10);
and with the padding the same. then you calculate it.
You can simply use the clientHeight and clientWidth properties.
MDN web doc for Element.clientHeight — clientWidth works exactly the same way.
i had the same problem and found out there is no native cross plattform solution but the solution is easy though
var actual_h = element.offsetHeight;
if(parseInt(element.style.paddingTop.replace('px','')) > 0){
actual_h=actual_h - parseInt(element.style.paddingTop.replace('px',''));
}
if(parseInt(element.style.paddingBottom.replace('px','')) > 0){
actual_h=actual_h - parseInt(element.style.paddingBottom.replace('px',''));
}
Related
I would like to change the position of a circle when it's parent section is scrolled into view.
While scrolling down after the parent is in view, it should move to the right and when scrolling up, it should move back to where it was originally. (-200px to the left) It should only be moved while the user is actively scrolling.
If the user scrolls all the way down to the very bottom of the circle's parent section, or if they have already scrolled down to the bottom and reload the page, the circle should appear in it's fully-revealed position.
My current code partially works, but I'm having trouble with getting the entire element to appear based on how much of the parent element is visible and also getting it to display in it's final position when reloading the page after having scrolled to the very bottom.
JSFiddle: https://jsfiddle.net/thebluehorse/gu2rvnsw/
var $window = $(window),
$sectionFour = $('.section-four'),
$circle = $sectionFour.find('.circle'),
lastScrollTop = 0,
position = -200;
function revealCircle() {
var isVisible,
st = $window.scrollTop();
isVisible = isInView($sectionFour);
if (isVisible) {
// console.log('section four is in view, so lets do stuff!');
if (st > lastScrollTop) {
if (position === 0) {
return false
}
$circle.css('transform', 'translateX(' + position + 'px')
position++;
} else {
if (position === -200) {
return false
}
$circle.css('transform', 'translateX(' + position + 'px')
position--;
}
}
}
function isInView(node) {
var rect;
if (typeof jQuery === 'function' && node instanceof jQuery) {
node = node[0];
}
rect = node.getBoundingClientRect();
return (
(rect.height > 0 || rect.width > 0) &&
rect.bottom >= 0 &&
rect.right >= 0 &&
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.left <= (window.innerWidth || document.documentElement.clientWidth)
);
}
$window.on('scroll', revealCircle);
.circle {
width: 400px;
height: 400px;
background: #fff;
-webkit-border-radius: 200px;
-moz-border-radius: 200px;
border-radius: 200px;
transform: translateX(-200px); }
.section {
min-height: 400px; }
.section-one {
background-color: red; }
.section-two {
background-color: orange; }
.section-three {
background-color: yellow; }
.section-four {
background-color: green; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="section section-one"></section>
<section class="section section-two"></section>
<section class="section section-three"></section>
<section class="section section-four">
<div class="circle"></div>
</section>
Your code can be simplified a bit. The only value you need to keep track of as the page is scrolled is scrollTop(). Because the geometry of $sectionFour never changes, you can cache its getBoundingClientRect() right away.
Once you know that $sectionFour is in view, you want to figure out how many pixels of its total height are in view, convert that to a percentage, and then apply that percentage to the initial position of -200. Essentially, when only a few pixels are showing, that's a small percentage, such as 10% and -200 becomes -180. When the element is fully in view, the percentage should be near 100%, and -200 becomes 0. This means you're not keeping track of the last position or which direction the scroll was, you're just computing what the value should be based on the current viewport (scrollTop).
var $window = $(window),
$sectionFour = $('.section-four'),
$circle = $sectionFour.find('.circle');
rect = $sectionFour[0].getBoundingClientRect();
function revealCircle() {
var scrollTop = $window.scrollTop();
var windowHeight = $window[0].innerHeight;
if (scrollTop + windowHeight > rect.top) {
var percentVisible = (scrollTop - (rect.top - windowHeight)) / rect.height;
var position = 200 - (percentVisible * 200);
$circle.css('transform', 'translateX(-' + position + 'px');
}
}
$window.on('scroll', revealCircle);
body { margin:0;}
.circle {
width: 400px;
height: 400px;
background: #fff;
-webkit-border-radius: 200px;
-moz-border-radius: 200px;
border-radius: 200px;
transform: translateX(-200px); }
.section {
min-height: 400px; }
.section-one {
background-color: red; }
.section-two {
background-color: orange; }
.section-three {
background-color: yellow; }
.section-four {
background-color: green; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="section section-one"></section>
<section class="section section-two"></section>
<section class="section section-three"></section>
<section class="section section-four">
<div class="circle"></div>
</section>
It could be more simpler to use css variables for pure JS solution :
const sectFour = document.querySelector('#section-four')
, divCircle = sectFour.querySelector('.circle')
function percentVisible(elm)
{
let rect = elm.getBoundingClientRect()
, viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight)
, visu = viewHeight-rect.top
return (visu<0) ? -1 : Math.min( 100, (visu/rect.height*100))
// return !(rect.bottom < 0 || rect.top - viewHeight >= 0) => checkVisible
}
window.onscroll=_=>
{
let circlePos = percentVisible(sectFour) *2
if (circlePos>=0)
{
divCircle.style.setProperty('--circle-pos', `-${200-circlePos}px`)
// IE 11 : // divCircle.style=('transform:translateX(-'+(200-circlePos)+'px')
}
}
* { margin: 0 }
.circle {
--circle-pos :-200px;
width : 400px;
height : 400px;
background-color : #fff;
-webkit-border-radius: 200px;
-moz-border-radius: 200px;
border-radius: 200px;
transform : translateX(var(--circle-pos));
/* IE 11 ........... : translateX(-200px); */
}
section { min-height: 400px; }
section:nth-of-type(1) { background-color: red; }
section:nth-of-type(2) { background-color: orange; }
section:nth-of-type(3) { background-color: yellow; }
section:nth-of-type(4) { background-color: green; }
<section></section>
<section></section>
<section></section>
<section id="section-four"> <div class="circle"></div> </section>
You should have a look at Intersection Observer (IO), this was designed to solve problems like yours. Listening to scroll event and calculating the position can result in bad performance.
First, you have to define the options for the IO:
let options = {
root: document.querySelectorAll('.section-four'),
rootMargin: '0px',
threshold: 1.0
}
let observer = new IntersectionObserver(callback, options);
After defining the options you have to tell the observer which elements to observe, I guess in your case this would be .section-four:
let targets = document.querySelectorAll('.section-four');
targets.forEach(target => {
observer.observe(target) }
)
Final step is to define the callback function that should be executed once .section-four is getting into view:
let callback = (entries, observer) => {
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// target element
// here you can do something like $(entry.target).find('circle') to get your circle
});
};
Have a look at this demo, depending on how much the element is visible the background-color changes. I think this comes close to your problem, you just don't change the bg-color you animate the circle inside the element.
There is also another demo on the site that displays how much of an element is visible on the screen, maybe this suits you better.
You can also use this polyfill from w3c to support older browsers.
I've tried to setup a very "vanilla" approach to this but cannot get the result.
I'm trying to reach into the DOM and the associated div styles using JS and effectively change the "display" property of the CSS.
The JS is error free but the CSS doesn't change.
(function() {
var singleCard = document.getElementById('card-container');
var manyCard = document.getElementById('card-container-many');
var allCard = document.getElementById('card-container') && document.getElementById('card-container-many');
var singleCardCss = document.querySelector('#card-container');
var manyCardCss = document.querySelector('#card-container-many');
var allCardCss = document.querySelector('#card-container') && document.querySelector('#card-container-many');
if (singleCardCss.display && manyCardCss.display === 'none') {
allCardCss.display = 'block';
} else {
allCardCss.display = 'none';
}
}());
#card-container {
position: relative;
display: none;
width: 280px;
height: 310px;
background-size: 640px 360px;
background-repeat: no-repeat;
border: 1px solid #222;
border-radius: 10px;
margin: 10px;
cursor: pointer;
}
#card-container-many {
position: relative;
display: none;
width: 280px;
height: 310px;
background-size: 640px 360px;
background-repeat: no-repeat;
border: 1px solid #222;
border-radius: 10px;
margin: 10px;
cursor: pointer;
}
<div class="container-fluid text-center">
<div id="card-container"></div>
</div>
<div class="container-fluid text-center">
<div id="card-container-many"></div>
</div>
The .style property is missing. For example:
allCardCss.style.display = 'block';
Also, the use of the AND operator is wrong I believe. It should be used in the if condition like so:
if (singleCardCss.style.display === "none" && manyCardCss.style.display === 'none') {...
Each side of the operand must be complete in a conditional even when it's a comparison between 2 objects (singleCardCSS and manyCardCSS) vs. the same condition ("none").
I took a third look and saw that allCardCSS is wrong as well, it should be:
var allCardCSS = document.querySelectorAll('div > div');
The result will be a NodeList of all divs that are a child of another div (singleCardCSS and manyCardCSS). This NodeList is an array-like object which you can do simple iterations upon in order to access the objects within. Notice how the for loop goes through the NodeList allCardCss.
Finally on the last statement has been eliminated because the else isn't needed since they are already .style.display="none". The first statements have been eliminated as well because .getElementById('ID') is identical to querySelector('#ID');
One last thing, I almost forgot about the parenthesis business:
Either of the following two patterns can be used to immediately invoke
a function expression, utilizing the function's execution context to
create "privacy."
(function(){ /* code */ }()); // Crockford recommends this one
(function(){ /* code */ })(); // But this one works just as well
-Ben Alman
So you are ok. The point is that if you have a set of extra parenthesis at the end then that'll be interpreted by the browser as an Expression Function which causes an Immediate Invocation*. The mention of privacy is referring to the IIFE with a closure which doesn't apply in your circumstance unless you make the latter part of the code into a function in which case you have a closure. In your case it's not needed since you aren't passing any variables from the outside of your function.
To those more knowledgeable. If there's anything I've said that to the contrary or omitted, please leave a comment with your downvote.
*it's IIFE a little mixed up in order in sentence but you get the picture 😉
Demo
(function() {
var singleCardCss = document.querySelector('#card-container');
var manyCardCss = document.querySelector('#card-container-many');
var allCardCss = document.querySelectorAll('div > div');
if (singleCardCss.style.display === "none" && manyCardCss.style.display === 'none') {
for (let i = 0; i < allCardCSS.length; i++) {
allCardCss[i].style.display = 'block';
}
}
}());
#card-container {
position: relative;
display: none;
width: 280px;
height: 310px;
background-size: 640px 360px;
background-repeat: no-repeat;
border: 1px solid #222;
border-radius: 10px;
margin: 10px;
cursor: pointer;
}
#card-container-many {
position: relative;
display: none;
width: 280px;
height: 310px;
background-size: 640px 360px;
background-repeat: no-repeat;
border: 1px solid #222;
border-radius: 10px;
margin: 10px;
cursor: pointer;
}
<div class="container-fluid text-center">
<div id="card-container"></div>
</div>
<div class="container-fluid text-center">
<div id="card-container-many"></div>
</div>
Your error is very common. You have to remove the last ) after your function. You close your IIFE after calling it. You can try but your function will be never call! You also can try to delete your variable allCardCss and allCard. I do not understand why do you initialize them with &&.
Replace:
(function() {
var singleCard = document.getElementById('card-container');
var manyCard = document.getElementById('card-container-many');
var allCard = document.getElementById('card-container') && document.getElementById('card-container-many');
var singleCardCss = document.querySelector('#card-container');
var manyCardCss = document.querySelector('#card-container-many');
var allCardCss = document.querySelector('#card-container') && document.querySelector('#card-container-many');
if (singleCardCss.display && manyCardCss.display === 'none') {
singleCardCss.display = 'block';
} else {
allCardCss.display = 'none';
}
}());
By:
(function() {
var singleCard = document.getElementById('card-container');
var manyCard = document.getElementById('card-container-many');
var singleCardCss = document.querySelector('#card-container');
var manyCardCss = document.querySelector('#card-container-many');
if (singleCardCss.display && manyCardCss.display === 'none') {
singleCardCss.display = 'block';
manyCardCss.display = 'block';
} else {
singleCardCss.display = 'none';
manyCardCss.display = 'none';
}
})();
I write JavaScript/TypeScript function:
function setElementsHeightsEqual(el1: HTMLElement, el2: HTMLElement) {
...
}
This is typical situation when you want to attach some button (el2) to some input (el1) dynamically.
I want to make el2's height equal to el1, but I am unable to do it.
There are two problems:
All possible calls returning height are helpless for me:
el1.offsetWidth; // will return 0 if document is not rendered yet
el1.style.height; // will return "" if it is set inside external CSS
el1.style.paddingTop; // the same
el1.style.paddingBottom; // the same
In other words is there any possibility to calculate height of some specified element?
How to set height of el2? We do not know even its "box-sizing", the same problem as in (1).
Are these tasks impossible in JS + HTML DOM?
offsetHeight is a safe way to go. If the element is not loaded, move your function call to window.onload.
Here you have a working example:
function setMaxHeight(...elements) {
console.log(elements);
// Get max height
var height = 0;
for(let element of elements) {
console.log(element.offsetHeight);
if(element.offsetHeight > height) height = element.offsetHeight;
}
// Change all elements height to max.
for(let element of elements) {
element.style.height = height + 'px';
}
}
window.onload = function() {
var object1 = document.querySelector('.object1');
var object2 = document.querySelector('.object2');
var object3 = document.querySelector('.object3');
setMaxHeight(object1, object2, object3);
};
.object1 {
border: 1px solid #000;
display: block;
float: left;
height: 50px;
width: 20%;
}
.object2 {
border: 1px solid #0cc;
display: block;
float: left;
height: 120px;
width: 30%;
}
.object3 {
border: 1px solid #afc;
display: block;
float: left;
height: 20px;
width: 10%;
}
<div id="container">
<div class="object1">Text</div>
<div class="object2">Text2</div>
<div class="object3">Text3</div>
</div>
Compare running with and without the Javascript portion.
I hope this helps.
It is the way I set the equal height to elements I want.
Give a class name to your elements which you want to make their height the same.
<div class="sameElementHeight">
<img src="/path/to/Image" class="sameImageHeight">
<p>YOUR TEXT</p>
</div>
<div class="sameElementHeight">
<img src="/path/to/Image" class="sameImageHeight">
<p>YOUR TEXT</p>
</div>
<div class="sameElementHeight">
<img src="/path/to/Image" class="sameImageHeight">
<p>YOUR TEXT</p>
</div>
First, create a function like this:
equalheight = function(container){
var currentTallest = 0,
currentRowStart = 0,
rowDivs = new Array(),
$el,
topPosition = 0;
jQuery(container).each(function() {
$el = jQuery(this);
jQuery($el).height('auto')
topPostion = $el.position().top;
if (currentRowStart != topPostion) {
for (currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) {
rowDivs[currentDiv].height(currentTallest);
}
rowDivs.length = 0; // empty the array
currentRowStart = topPostion;
currentTallest = $el.height();
rowDivs.push($el);
} else {
rowDivs.push($el);
currentTallest = (currentTallest < $el.height()) ? ($el.height()) : (currentTallest);
}
for (currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) {
rowDivs[currentDiv].height(currentTallest);
}
});
}
Then call it before closing body tag:
<script>
equalheight(".sameElementHeight");
equalheight(".sameImageHeight");
</script>
</body>
You also may call this function when you add new elements to your document.
It will calculate the height of the element and set the same height to them and also does the same with images.
I hope it helps.
I have a div with margin auto, in the center (horizontal).
I want to check with jQuery if the div has margin auto.
I tried to get the margin-left with .css(). Mozilla Firefox shows 0px, and Chrome shows a number of pixels... So with this method I cannot check if the div has margin auto...
What I've tried:
$( document ).ready(function() {
$("#the_margin").append( $("#example").css("margin-left") );
});
// Check with Chrome and Firefox...
// Firefox returns 0px, but Chrome returns a number of pixels
#example {
margin: 0 auto 0;
width: 300px;
border: 1px solid #CCC;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="example">
Some Content
</div>
<div id="the_margin" style="font-weight: bold;">
The left margin is:
</div>
What can I do?
Thanks a lot!
EDIT
More clear: HOW CAN I CHECK IF DIV HAS MARGIN AUTO IN JQUERY?
Created a function which reads the css and check the specified id if has margin with auto.
JS (JQuery)
function check_center( the_id ) {
var result = "";
var sheets = document.styleSheets;
var attribute_style = $(the_id).attr( "style" );
if(attribute_style.match(/margin:([a-z0-9- ]+?)auto/) || attribute_style.match(/margin:auto/) || (attribute_style.match(/margin-left:auto/) && attribute_style.match(/margin-right:auto/)) || (attribute_style.match(/margin-left: auto/) && attribute_style.match(/margin-right: auto/)) ) {
result = "true";
} else {
the_id.matches = the_id.matches || the_id.webkitMatchesSelector || the_id.mozMatchesSelector || the_id.msMatchesSelector || the_id.oMatchesSelector;
for (var i in sheets) {
var rules = sheets[i].rules || sheets[i].cssRules;
for (var r in rules) {
if (the_id.matches(rules[r].selectorText)) {
if(result != "true") {
if(rules[r].cssText.match(/margin:([a-z0-9- ]+?)auto/) || rules[r].cssText.match(/margin:auto/) || (rules[r].cssText.match(/margin-left:auto/) && rules[r].cssText.match(/margin-right:auto/)) || (rules[r].cssText.match(/margin-left: auto/) && rules[r].cssText.match(/margin-right: auto/)) ) {
result = "true";
} else {
result = "false";
}
}
}
}
}
}
if(result == "") {
result = "false";
}
return result;
}
$( document ).ready(function() {
$("#the_margin").append( check_center(document.getElementById('example')) );
});
HTML
<div id="example" style="width: 300px;">
Some Content
</div>
<div id="the_margin" style="font-weight: bold;">
The div is centered?
</div>
CSS
#example {
margin: 0 auto 0;
border: 1px solid #CCC;
}
Fiddle http://jsfiddle.net/vn6ajt6r/6/
It works for:
External style sheet
Internal style sheet
Inline style
I think your problem Mozilla Firefox shows 0px, and Chrome shows a number of pixels can be fixed this way :-
#example {
-webkit-margin: 0 auto 0;
-moz-margin: 0 auto 0;
width: 300px;
border: 1px solid #CCC;
}
FIDDLE:
You need to specify the browser while setting margin css
i think the other way can be calculated.
only top example for calculated margin-left value:
$('#example').offset().left - $('#example').position().left
$(document).ready(function() {
$("#the_margin").append(
$('#example').offset().left - $('#example').position().left
);
});
#example {
margin-top: 0;
margin-left: auto;
margin-right: auto;
margin-bottom: 0;
position: relative;
width: 300px;
border: 1px solid #CCC;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="example">
Some Content
</div>
<div id="the_margin" style="font-weight: bold;">
The left margin is:
</div>
I am trying to make a webpage where when you click a link, the link moves diagonally every 100 milliseconds.
So I have my Javascript, but right now when I click the link nothing happens
Also, does anyone know of a Javascript IDE I can use to make sure I have no errors in my code?
PS: Does anyone know why my elements dont stretch to fit the whole 200px by 200px of the div element? The links are only small when they should be the same width as their parent div element.
Edited with new advice, although still wont move.
<script LANGUAGE="JavaScript" type = "text/javascript">
<!--
var block = null;
var clockStep = null;
var index = 0;
var maxIndex = 6;
var x = 0;
var y = 0;
var timerInterval = 100; // milliseconds
var xPos = null;
var yPos = null;
function moveBlock()
{
if ( index < 0 || index >= maxIndex || block == null || clockStep == null )
{
clearInterval( clockStep );
return;
}
block.style.left = xPos[index] + "px";
block.style.top = yPos[index] + "px";
index++;
}
function onBlockClick( blockID )
{
if ( clockStep != null )
{
return;
}
block = document.getElementById( blockID );
index = 0;
x = parseInt( block.style.left, 10 );
y = parseInt( block.style.top, 10 );
xPos = new Array( x+10, x+20, x+30, x+40, x+50, x+60 );
yPos = new Array( y-10, y-20, y-30, y-40, y-50, y-60 );
clockStep = self.SetInterval( moveBlock(), timerInterval );
}
-->
</script>
<style type="text/css" media="all">
<!--
#import url("styles.css");
#blockMenu { z-index: 0; width: 650px; height: 600px; background-color: blue; padding: 0; }
#block1 { z-index: 30; position: relative; top: 10px; left: 10px; background-color: red; width: 200px; height: 200px;
margin: 0; padding: 0; /* background-image: url("images/block1.png"); */ }
#block2 { z-index: 30; position: relative; top: 50px; left: 220px; background-color: red; width: 200px; height: 200px;
margin: 0; padding: 0; /* background-image: url("images/block1.png"); */ }
#block3 { z-index: 30; position: relative; top: 50px; left: 440px; background-color: red; width: 200px; height: 200px;
margin: 0; padding: 0; /* background-image: url("images/block1.png"); */ }
#block4 { z-index: 30; position: relative; top: 0px; left: 600px; background-color: red; width: 200px; height: 200px;
margin: 0; padding: 0; /* background-image: url("images/block1.png"); */ }
#block1 a { display: block; width: 100%; height: 100%; }
#block2 a { display: block; width: 100%; height: 100%; }
#block3 a { display: block; width: 100%; height: 100%; }
#block4 a { display: block; width: 100%; height: 100%; }
#block1 a:hover { background-color: green; }
#block2 a:hover { background-color: green; }
#block3 a:hover { background-color: green; }
#block4 a:hover { background-color: green; }
#block1 a:active { background-color: yellow; }
#block2 a:active { background-color: yellow; }
#block3 a:active { background-color: yellow; }
#block4 a:active { background-color: yellow; }
-->
</style>
Errors needed to fix
To fill the width of the div elements, the a elements need to be display: block; not their default display: inline;.
Knowing runtime errors is more important in my opinion, and IDEs don't catch DOM errors or anything more complex than syntax; use the error logging in your browser (Firefox's is called Error Console). That'll also catch in-development errors like syntax errors.
This is the most important point to stress: block.style.left and block.style.top are not just numbers with implicit pixel values in them. Setting it to a number without a unit suffix will do absolutely nothing. You need to add % or px or whatever unit when setting left and top.
When getting the current value, as in var x = ... and var y = ..., you need to Number() manually to get the numeric portion of the string.
Also, I believe you meant || block == null, not =, which would set block to null.
Tips
You can use moveBlock instead of "moveBlock();" as an argument to setTimeout. This avoids parsing the string into code, and avoids scope problems (though not in this example as moveBlock is global).
I know that you have an array of values, where both x and y move 10 each time. I assume you want to move at a 45 degree angle. If so, this won't work as you expect even after fixing all the errors as x is percentage and y is in pixels.
You should declare your x and y above like your other variables. It may work but its confusing.
in your setTimeout, use moveBlock, not "moveBlock()" - it will save the step of evaluating your string into code.
block.style.left will return a string that includes "px" - it won't be a number. You can do:
x = Number(x);
//or
x = parseInt(x, 10);
When you set the position, remember to add the "px":
block.style.left = xPos[index] + "px";
EDIT:
Ok, the key problem is 'style.left' is not reading because it was set with CSS and not the style object. I use my library to get the style which runs through a few scenarios and catches that automatically. So change these lines to (this may not be exactly correct but will get things moving):
x = parseInt( node.style.left, 10 ) || 0;
y = parseInt( node.style.top, 10 ) || 0;
Also, this is wrong (you never declared 'self', and you don't need it here anyway; JS is case sensitive, SetInterval is not capped; pass the function, not the function result):
clockStep = self.SetInterval( moveBlock(), timerInterval ); // <-- result of moveBlock
// change to:
clockStep = setInterval( moveBlock, timerInterval ); // <-- the function moveBlock
During dev, you should remove the if() statements that could have been blocking the code and just put a simple count--; in there. It's really hard to debug code when you have literally 20 things wrong. Write a line, test. Write a line, test.
You have HTML comments in the script and style blocks. This is from 1998. While they don't hurt anything intact, in the past I've accidentally edited my code and removed one of them, and this will throw everything out of whack - your IDE, the browser - because they won't know what's wrong and you won't get a good error message.
LANGUAGE="JavaScript" is no longer used and is a waste of bytes.
To help speed development add this line:
window.onloadfunction(){
onBlockClick('block1')
}
That will execute your code right away for testing and you don't have to click every time.
Finally, I highly recommend you use Firefox and Firebug. Developing without it is like trying to build a ship in a bottle with boxing gloves. Using console.log(block.style.left) would have shown you it was not set. The error messages would have told you SetInterval and moveBlock() was incorrect. You do need to remember to remove the console.logs before production though. or... (shameless plug)... use my JavaScript Console Fix library which will do that for you: http://clubajax.org/javascript-console-fix-v2-now-with-ios/