I am trying to find the highest z-index on a page. I am using this
var getStyleProp = function(el, prop){
return window.getComputedStyle(el, null).getPropertyValue(prop);
}
var getHighestZIndex = function(){
var highestZIndex = 0,
HTMLElems = ["a","abbr","acronym","address","applet","area","article","audio","b","base","basefont","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","embed","fieldset","figcaption","figure","footer","form","frame","frameset","h1, h2, h3, h4, h5, h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","isindex","kbd","keygen","label","legend","li","link","listing","main","map","mark","menu","menuitem","meta","meter","nav","noembed","noscript","object","ol","optgroup","option","output","p","param","plaintext","pre","progress","q","rp","rt","rtc","ruby","s","samp","script","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr","xmp"],
tags,
zIndex;
for (var i = 0; i < HTMLElems.length; i++){
tags = document.getElementsByTagName(HTMLElems[i]);
if (tags){
for (var c = 0; c < tags.length; c++){
zIndex =getStyleProp(tags[c], "z-index");
console.log(tags[c], "zIndex=", zIndex);
if (zIndex > highestZIndex){
highestZIndex = zIndex;
}
}
}
}
return highestZIndex;
}
console.log(getHighestZIndex());
But everything is coming back as "auto". This ancient article explains how a "bug" is causing this behavior. I've tried to make clones of each node, set the position to relative, and then get the z-index,
cl.style.display = "none";
cl.style.position = "absolute";
zIndex = (getStyleProp(cl, "z-index"));
but that is not working either. What is wrong here? Is there a cheaper way to do this than recreating everything on the page?
JSBIN
The node's clone does not seem to get the z-index, while the node itself returns the right value. You could try using it instead (not sure how it might react on a page with lots of content):
var getHighestZIndex = function () {
var highestZIndex = 0,
zIndex,
pos,
tags = document.body.getElementsByTagName('*');
for (var c = 0; c < tags.length; c++) {
// Get the original 'position' property
pos = getComputedStyle(tags[c]).position;
// Set it temporarily to 'relative'
tags[c].style.position = "relative";
// Grab the z-index
zIndex = getComputedStyle(tags[c]).zIndex;
// Reset the 'position'
tags[c].style.position = pos;
console.log(tags[c], "zIndex=", zIndex);
if (zIndex > highestZIndex) { highestZIndex = zIndex; }
}
return highestZIndex;
};
console.log(getHighestZIndex());
JS Fiddle Demo
Changing the element's position temporarily might produce a glitch. You'll need to test that on a page with lots of contents and elements that are position:absolute; or position:fixed;.
If this doesn't fit your use-case, just let me know, and I'll remove it. However, as a thought.
Can you loop through all the tags, and if the value is "auto" assume it's 999. If it's >= 1000, take that as your "highest" value. Then, increment your zIndex up from your highest number that way. This way, the first tag you place will be 1000, the next will be 1001.
var elements = document.getElementsByTagName("*"),
maxZIndex = 999;
for( var i=0; i < elements.length; i++ ) {
var zIndex = parseInt(elements[0].style.zIndex) || 999;
maxZIndex = zIndex > maxZIndex ? zIndex : maxZIndex;
}
return maxZIndex;
This would fit a use case where you are just trying to make sure that the tag you are placing is greater than anything on the page...such as placing a modal.
999 is overkill...somewhat of a "just in case" I missed something because anything with z-index:auto is equivalent to zero. See the following "proof" where even though my z-index is only "1" it overlaps boxes that are 3-deep of "auto".
<div style='position:absolute;background-color:white;z-index:1;width:94px;height:94px;'>
</div>
<div style='position:absolute;background-color:red;width:100px;height:100px;'>
<div style='position:absolute;background-color:blue;width:98px;height:98px;'>
<div style='position:absolute;background-color:green;width:96px;height:96px;'>
</div>
</div>
</div>
I apologize for the clunky wording of the question. English is not my first language.
I am creating a scrollable list. Each element of this list consists of a column with two rows. I don't want to offset the column until each row is filled. I basically only want to increment the offset counter every two cycles of the for loop. My code for this is as follows:
var j = 0;
for(var i=0;i<localArray.length;i++){
var iconLeft = 145 * j;
var div = document.createElement('div');
div.id = "page_icon_" + i;
div.style.position = "absolute";
div.style.height = "45px";
div.style.width = "145px";
div.style.left = iconLeft + "px";
var item = fishListItem(localArray[i].info);
div.appendChild(item);
var parent = document.getElementById('tut_icons_scroll');
if(i%2){
item.style.top = "40px";
parent.appendChild(div);
}else{
parent.appendChild(div);
}
if (i%2) {
j++;
}
Is there a way to do with without introducing the variable 'j'?
You could just do:
Math.floor(i/2)
in place of j.
In this case, you can replace all instances of j with Math.floor(i/2).
I would like to use pure css nth-child to accomplish this requirement
if(i%2){
item.style.top = "40px";
parent.appendChild(div);
}
to replace this, in your css div:nth-child(even) { top: 40px; }
to replace j, just create a class for the column, set the margin for it, and position set to relative, float set to left.
can you provide your code in jsbin or jsfiddler so I can help you out. I thought this solution is much clear and easy to maintain.
Would it be easy to use a pass element i and then (i+1) to a function and then count up by 2s?
Something like:
function appendFunction(elementToAdd, addItTo) {}
for (var i = 0; i < localArray.length; i+=2) {
var iconLeft = 145*(i%2); // at 0
var iconRight = 145*(i%2 + 1); // at 145
appendFunction(elementToAdd[i], addItTo}
appendFunction(elementToAdd[i+1], addItTo}
}
Not sure if the function helps a lot, but anyways, adding by twos and treating the cases of (x) and (x+1) within the for loop should allow you to increment a counter once every other time. You have to say what to happen twice each time, but one you make a function for it, it's about as long and leaves you with an easily reusable bit to append the elements in the way to place the text.
You can use Math.floor as stated in a couple of answers. Or bit-shift right by one:
i>>1;
Either substitute j with this expression, or use: var j=i>>1;. i>>1 will have the following values for each loop with an incrementing i:
0,0,1,1,2,2,3,3,4,4,...
Try this:
for(var i=0, j=0; i < 10; i++%2 && ++j) {
console.log(i,j);
}
I'm attempting to create a 'Pick your hero' thing. There are a total of 113 heroes, each are given tags respective to them, for example: wizard, fighter etc.
The way I've done it so far is create a container and add 114 total div's to that container. I have this:
.heroPics {
background-image: url(newHeroes.jpg);
background-size: 792px 792px;
width: 72px;
height: 72px;
float: left;
margin-left: 5px;
margin-top: 20px;
text-align: center;
line-height: 11;
font-size: 15px;
position: relative;
}
for (var i = 1; i < 114; i++) {
srsHeroes[i] = document.createElement("div");
srsHeroes[i].textContent = theNames[i];
srsHeroes[i].className = "championPics " + theNames[i] + "-sprite";
srsHeroes[i].draggable = false;
srsHeroes[i].name = theNames[i];
srsHeroes[i].num = i;
heroSelection.appendChild(srsHeroes[i]);
}
I was thinking of creating an array, for example
wizard = [ 14, 17, 28, 34, 69, 90, 101 ];
and once they click on a checkbox to show only wizard heroes it would do a for loop to hide all 113 divs and then do:
for (var i = 50; i < 70; i++) {
heroSelection.insertBefore(srsHeroes[wizard[i]], srsHeroes[115]);
//and also do style.visiblity = "visible";
}
But it just seems like this is a bad approach to it, or really messy/ugly. I don't really like using library's, including jquery. Is using div's even the right approach? Can anyone with experience give me some advice or links to follow since I must be searching the wrong terms for this.
Also can someone give me some intro on how to create a search bar where they can write hero names and it does the same thing? Reordering and hiding everything properly. Could be cool to have a transition too but not necessary lol. Thanks in advance for reading and all your help.
EDIT: Added my own post since it would have made this too long, let me know what you think
Using classes and jQuery, you can easily match all the divs with that class. If you give all your divs with wizard picts in them a class name of "wizard", then you can select all of them like this:
$("div[class='wizard']").show();
Then to hide the others, you could just do this:
$("div[class!='wizard']").hide();
Also, as you know you can use multiple classes, so you can have a div like this:
<div class="heroPics wizard">
This will first apply the heroPics class styles, then the wizard styles. the latter doesn't have to have anything in it, you can just use it to classify your divs.
for (var i = 1; i < 114; i++) {
srsHeroes[i].style.visibility = "hidden";
}
var test = heroSelection.getElementsByClassName( 'fighter' );
var gg = 1;
var bg = 0;
for (var i = 0, j = test.length; i < j; i++ ) {
test[i].style.visibility = "visible";
test[i].style.transitionDuration= "1.5s";
test[i].style.transitionTimingFunction="ease"
test[i].style.left = -73 + (77 * gg) + "px";
test[i].style.top = -10 + (90 * bg) + "px";
gg ++;
if(gg > 10) {
gg = 1;
bg ++;
}
}
This actually ended up working perfectly. Although I have to reset transitionDuration each time I believe since even to hide divs it would do a 1.5 sec delay if left like that. The insertNode actually fine too, but I couldn't find a way to animate it, here's the code for that if you are interested:
var test = heroSelection.getElementsByClassName( 'wizard' );
for (var i = 0, j = test.length; i < j; i++) {
test[i].style.visibility = "visible";
heroSelection.insertBefore(test[i], heroSelection.firstChild);
the firstChild syntax is awesome, but no animation I ended up switching everything to absolute position, adding a transition duration and just setting the left and top every time.
I need 100 small divs for my chart, every time I generate them, I they all appear as the same height; the last value from the array.
var valuesG = new Array(100);
for (i = 0; i < valuesG.length; i++ ) {
valuesG[i] = Math.floor(Math.random() * 101);
$("#second").append("<div class='single'></div>");
$(".single").css('height', valuesG[i])
}
Any ideas why this is happening?
You are applying the new height to ALL the .single elements in every iteration. In the last iteration, they end up having the same height.
You could do it like this:
$('<div class="single">')
.css('height', valuesG[i])
.appendTo($('#second'));
Also, your code is not very efficient, take a look at this:
var valuesG = [], //array literal
$elements = $(); //empty jQuery object
for (var i = 0; i < 100; i++) { //we don't have to query array length each iteration
valuesG[i] = Math.floor(Math.random()*101);
//collect the elements into a jQuery object
$elements = $elements.add($('<div class="single">').css('height', valuesG[i]));
}
$elements.appendTo($("#second")); //insert to DOM once - much quicker
jsFiddle Demo
Currently, you're selecting all elements with class single. To get the desired effect, use the appendTo method in the way as shown below.
Side note, the generated heights are not unique, but random. It's possible that two elements exist with, say, height 50. See this question for a method to generate unique random numbers.
var valuesG = new Array(100), i;
for ( i=0; i < valuesG.length; i++ )
{
valuesG[i] = Math.floor(Math.random()*101);
$("<div class='single'></div>")
.css( 'height', valuesG[i] )
.appendTo("#second");
}
You get only one height(last one) because you set same css class in all div and update it's height in every loop so last height value will be applied to all.
As a solution try this:
for ( i=0; i < valuesG.length; i++ ) {
valuesG[i] = Math.floor(Math.random()*101);
$("<div class='single'></div>").css('height',valuesG[i]).appendTo("#second");
}