I would like to make an element (e.g. a <div>) be the top-most layer on the page.
My assumption is that the only way I can do this is to specify that the element has a style="z-index:" value that is the maximum the browser allows (int32?).
Is this correct?
Instead, would it be possible to somehow get the element's z-index whose is highest, and make this <div>'s z-index the [highest element's value] + 1? For example:
$myDiv.css("z-index", $(document.body).highestZIndex() + 1);
How do modal JavaScript "windows" work?
Here's how to do it :
var elements = document.getElementsByTagName("*");
var highest_index = 0;
for (var i = 0; i < elements.length - 1; i++) {
if (parseInt(elements[i].style.zIndex) > highest_index) {
highest_index = parseInt(elements[i].style.zIndex;
}
}
highest_index now contains the highest z-index on the page... just add 1 to that value and apply it wherever you want. You can apply it like so :
your_element.style.zIndex = highest_index + 1;
Here's another way of achieving the same thing using jQuery :
var highest_index = 0;
$("[z-index]").each(function() {
if ($(this).attr("z-index") > highest_index) {
highest_index = $(this).attr("z-index");
}
});
Again, same way to apply the new index to an element :
$("your_element").attr("z-index", highest_index + 1);
What about stacking context? It is not always true that: On a document highest z-index will be on top. See: http://philipwalton.com/articles/what-no-one-told-you-about-z-index/. If you do not take stacking context into account, setting a billion may not be enough to make your element on the top-most.
http://abcoder.com/javascript/a-better-process-to-find-maximum-z-index-within-a-page/ -> find the max z-index and assign +1 to it.
Sheavi's jQuery solution doesn't work because z-index is a css style, not an attribute.
Try this instead:
raiseToHighestZindex = function(elem) {
var highest_index = 0;
$("*").each(function() {
var cur_zindex= $(this).css("z-index");
if (cur_zindex > highest_index) {
highest_index = cur_zindex;
$(elem).css("z-index", cur_zindex + 1);
}
});
return highest_index;
};
Return value may not be what you expect due to Javascript's async nature, but calling the function on any element will work fine.
Related
I have a number of div elements with different z-index. And I want to find the highest z-index among these divs - how can I achieve it?
CSS:
#layer-1 { z-index: 1 }
#layer-2 { z-index: 2 }
#layer-3 { z-index: 3 }
#layer-4 { z-index: 4 }
HTML:
<div id="layer-1">layer-1</div>
<div id="layer-2">layer-2</div>
<div id="layer-3">layer-3</div>
<div id="layer-4">layer-4</div>
I don't think this line can find the highest z-index though.
var index_highest = parseInt($("div").css("zIndex"));
// returns 10000
Note that z-index only affects positioned elements. Therefore, any element with position: static will not have a z-index, even if you assign it a value. This is especially true in browsers like Google Chrome.
var index_highest = 0;
// more effective to have a class for the div you want to search and
// pass that to your selector
$("#layer-1,#layer-2,#layer-3,#layer-4").each(function() {
// always use a radix when using parseInt
var index_current = parseInt($(this).css("zIndex"), 10);
if(index_current > index_highest) {
index_highest = index_current;
}
});
JSFiddle demo
A general jQuery selector like that when used with an option that returns one value will merely return the first So your result is simply the z-index of the first div that jQuery grabs. To grab only the divs you want, use a class on them. If you want all divs, stick with div.
Here is a very concise method:
var getMaxZ = function(selector){
return Math.max.apply(null, $(selector).map(function(){
var z;
return isNaN(z = parseInt($(this).css("z-index"), 10)) ? 0 : z;
}));
};
Usage:
getMaxZ($("#layer-1,#layer-2,#layer-3,#layer-4"));
Or, as a jQuery extension:
jQuery.fn.extend({
getMaxZ : function(){
return Math.max.apply(null, jQuery(this).map(function(){
var z;
return isNaN(z = parseInt(jQuery(this).css("z-index"), 10)) ? 0 : z;
}));
}
});
Usage:
$("#layer-1,#layer-2,#layer-3,#layer-4").getMaxZ();
Besides #justkt's native solution above, there is a nice plugin to do what you want.
Take a look at TopZIndex.
$.topZIndex("div");
Try this :
var index_highest = 0;
$('div').each(function(){
var index_current = parseInt($(this).css("z-index"), 10);
if(index_current > index_highest) {
index_highest = index_current;
}
});
This would do it:
$(document).ready(function() {
var array = [];
$("div").each(function() {
array.push($(this).css("z-index"));
});
var index_highest = Math.max.apply(Math, array);
alert(index_highest);
});
Try this
This is taken directly from jquery-ui, it works really well:
(function ($) {
$.fn.zIndex = function (zIndex) {
if (zIndex !== undefined) {
return this.css("zIndex", zIndex);
}
if (this.length) {
var elem = $(this[ 0 ]), position, value;
while (elem.length && elem[ 0 ] !== document) {
// Ignore z-index if position is set to a value where z-index is ignored by the browser
// This makes behavior of this function consistent across browsers
// WebKit always returns auto if the element is positioned
position = elem.css("position");
if (position === "absolute" || position === "relative" || position === "fixed") {
// IE returns 0 when zIndex is not specified
// other browsers return a string
// we ignore the case of nested elements with an explicit value of 0
// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
value = parseInt(elem.css("zIndex"), 10);
if (!isNaN(value) && value !== 0) {
return value;
}
}
elem = elem.parent();
}
}
return 0;
}
})(jQuery);
I don't know how efficient this is, but you can use $.map to get all the z-indices:
var $divs = $('div'),
mapper = function (elem) {
return parseFloat($(elem).css('zIndex'));
},
indices = $.map($divs, mapper);
The indices variable is now an array of all the z-indices for all the divs. All you'd have to do now is apply them to Math.max:
var highest = Math.max.apply(whatevs, indices);
Here how I got both lowest/highest z-indexes. If you only want to get the highest z-index and nothing more, then this function may not efficient, but if you want to get all z-indexes and the ids associated with it (i.e. for use with bring 'layer' to front/send to back, bring forward, send backward, etc), this is one way to do it. The function returns an array of objects containing ids and their z-indexes.
function getZindex (id) {
var _l = [];
$(id).each(function (e) {
// skip if z-index isn't set
if ( $(this).css('z-index') == 'auto' ) {
return true
}
_l.push({ id: $(this), zindex: $(this).css('z-index') });
});
_l.sort(function(a, b) { return a.zindex - b.zindex });
return _l;
}
// You'll need to add a class 'layer' to each of your layer
var _zindexes = getZindex('.layer');
var _length = _zindexes.length;
// Highest z-index is simply the last element in the array
var _highest = _zindexes[_length - 1].zindex
// Lowest z-index is simply the first element in the array
var _lowest = _zindex[0].zindex;
alert(_highest);
alert(_lowest);
Vanilla JS, not 100% cross-browser. Including as reference for future readers/alternative method.
function getHighIndex (selector) {
// No granularity by default; look at everything
if (!selector) { selector = '*' };
var elements = document.querySelectorAll(selector) ||
oXmlDom.documentElement.selectNodes(selector),
i = 0,
e, s,
max = elements.length,
found = [];
for (; i < max; i += 1) {
e = window.getComputedStyle(elements[i], null).zIndex || elements[i].currentStyle.zIndex;
s = window.getComputedStyle(elements[i], null).position || elements[i].currentStyle.position;
// Statically positioned elements are not affected by zIndex
if (e && s !== "static") {
found.push(parseInt(e, 10));
}
}
return found.length ? Math.max.apply(null, found) : 0;
}
Try my fiddle:
http://planitize.tumblr.com/post/23541747264/get-highest-z-index-with-descendants-included
This combines three advantages I haven't seen combined elsewhere:
Gets either the highest explicitly defined z-index (default) or the highest computed one.
Will look at all descendants of your selector, or all descendants of the document if none is supplied.
Will return either the value of the highest z, or the element that has the highest z.
One disadvantage: no cross-browser guarantees.
If you are doing what I think you're doing, there is no need. Just do this:
$('div[id^=layer-]').css('z-index', 0);
$(this).css('z-index', 1000);
I have an object that contains a list of browser widths
breakpoints {
smallMobile: 0,
mobile: 480,
tablet: 672,
desktop: 868,
largeDesktop: 1050
}
I want to add a class to the body of the document based on whether the browser width falls between two values in the breakpoints object.
What I have so far
var key;
for (key in breakpoints) {
if (breakpoints.hasOwnProperty(key))
if (winWidth >= breakpoints[key]) {
$('body').removeClass().addClass(key);
} else {
$('body').removeClass(key);
}
}
}
Now this works, however it also removes ALL classes from the body. Instead I would like to add only one class, and not have to remove anything unless the breakpoint no longer matches.
I'm sure there has to be a way. Any help would be appreciated :)
EDIT
Current output at various widths
>= 1050: <body class="smallMobile mobile tablet desktop largeDesktop">
>= 868: <body class="smallMobile mobile tablet desktop">
>= 672: <body class="smallMobile mobile tablet">
Ideal output
>= 1050: <body class="largeDesktop">
>= 868: <body class="desktop">
>= 672: <body class="tablet">
(For the record I use Media Queries, but I need access to classnames for an edge case)
I've slightly modified your code and saved the class thats the highest applicable one. Then I remove every class and apply the applicable one.
// create a variable to store the only class you want to apply
var apply = "";
for (var key in breakpoints) {
// keep overwriting the apply var if the new key is applicable
if (winWidth >= breakpoints[key]) {
apply = key;
}
// remove any existing classes with that keyname
$('body').removeClass(key);
}
// add the key to the body as a class
$('body').addClass(apply);
Also, you can remove breakpoints.hasOwnProperty(key) as the for-loop only loops through keys that actually exist anyway, so you are doing an unnecessary check.
Update
At #juvian's note, I'll add a way to make sure that the order in which you make your object makes no difference:
var apply = "";
var check = 0;
for (var key in breakpoints) {
// Also check if the value is higher than the last set value
if (winWidth >= breakpoints[key] && breakpoints[key] >= check) {
apply = key;
check = breakpoints[key];
}
$('body').removeClass(key);
}
$('body').addClass(apply);
It's because you're using removeClass() without any parameter in it.
If a class name is included as a parameter, then only that class will
be removed from the set of matched elements. If no class names are
specified in the parameter, all classes will be removed.
Source: http://api.jquery.com/removeClass/
So, you should find the right class to remove and then call this function with a param.
Consider to store your breakpoints in sorted array instead of map:
var dimensions = [];
for (var key in breakpoints) {
dimensions.push({ name: key, width: breakpoints[key] })
}
dimensions.sort(function(a, b) { return b.width - a.width });
Now dimensions is
[
{"name":"largeDesktop","width":1050},
{"name":"desktop","width":868},
{"name":"tablet","width":672},
{"name":"mobile","width":480},
{"name":"smallMobile","width":0}
]
Of course you can hardcode it in this structure and not grep/sort each time.
Finally, find highest width with
for (var i = 0; i < dimensions.length; i++) {
if (winWidth >= dimensions[i].width) {
$("body").addClass(dimensions[i].name);
break;
}
}
However, if you want to create responsive layout, media queries is the way to go. Media queries also will take windows resize/orientation change events into account.
Here is a way you can get the one that matches with the highest value:
var wid = 868;
var max = 0;
var size = null;
Object.keys(breakpoints).map(function(a){
size = wid >= breakpoints[a] ? a : size;
max = wid >= breakpoints[a] ? Math.max(max,breakpoints[a]) : max;
})
console.log(max, size) // 868, 'desktop'
if you use .removeClass() without parameter then all class on selected element will remove as like prabu said, but if you want, i give some example so you will not confused how to remove class if window width less than breakpoints
var key;
for (key in breakpoints) {
if (breakpoints.hasOwnProperty(key)) {
$("body").addClass(key);
if (winWidth<breakpoints[key]) {
$("body").removeClass(key);
}
}
}
Is there a way to get the height from a style attribute on a div?
<div style="height:100px;"></div>
I can't use .height() as this will just return me the current height of the element - I need to check if the style has been set and then get that height if it has
The easiest way is to go straight to the style property:
var heightStyleValue = $("selector for your element")[0].style.height;
You don't want to use jQuery's css function because that will give you the calculated height, not the value from the style object.
Use css() in jquery
$('div').css('height');
I can't use .height() as this will just return me the current height of the element (...)
How is this possible? Unless you're using some !important statements (which you should avoid), the style attribute has higher specificity than anything else in your CSS. Therefore, the height returned by height() should be the same, unless it's constrained by some other container.
However in order to achieve what you want to do, you need to do 2 things:
Assign an ID to your div so you can target it in your Javascript
Use:
document.getElementById("yourID").style.height;
You cannot use elem.style.height because the named values of style have default values.
If you actually want to know which style parameters has been set, treat style as an array.
Vanilla:
// get style attributes that were actually set on the element
function getStyle(elem,prop) {
var actuallySetStyles = {};
for (var i = 0; i < elem.style.length; i++) {
var key = elem.style[i];
if (prop == key)
return elem.style[key];
actuallySetStyles[key] = elem.style[key];
}
if (!prop)
return actuallySetStyles;
}
console.log(getStyle(elem,'height'));
console.log(getStyle(elem));
jQuery:
jQuery.fn.extend({
// get style attributes that were set on the first element of the jQuery object
getStyle: function (prop) {
var elem = this[0];
var actuallySetStyles = {};
for (var i = 0; i < elem.style.length; i++) {
var key = elem.style[i];
if (prop == key)
return elem.style[key];
actuallySetStyles[key] = elem.style[key];
}
if (!prop)
return actuallySetStyles;
}
}
console.log(jQuery(elem).getStyle('height'));
console.log(jQuery(elem).getStyle());
Is it possible to get a value from the external CSS of a page if the element that the style refers to has not been generated yet? (the element is to be generated dynamically).
The jQuery method I've seen is $('element').css('property');, but this relies on element being on the page. Is there a way of finding out what the property is set to within the CSS rather than the computed style of an element?
Will I have to do something ugly like add a hidden copy of the element to my page so that I can access its style attributes?
With jQuery:
// Scoping function just to avoid creating a global
(function() {
var $p = $("<p></p>").hide().appendTo("body");
console.log($p.css("color"));
$p.remove();
})();
p {color: blue}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Using the DOM directly:
// Scoping function just to avoid creating a global
(function() {
var p = document.createElement('p');
document.body.appendChild(p);
console.log(getComputedStyle(p).color);
document.body.removeChild(p);
})();
p {color: blue}
Note: In both cases, if you're loading external style sheets, you'll want to wait for them to load in order to see their effect on the element. Neither jQuery's ready nor the DOM's DOMContentLoaded event does that, you'd have to ensure it by watching for them to load.
Normally you should be let the browser apply all the rules and then ask the browser for the results, but for the rare case where you really need to get the value out of the style sheet you can use this: (JSFiddle)
function getStyleSheetPropertyValue(selectorText, propertyName) {
// search backwards because the last match is more likely the right one
for (var s= document.styleSheets.length - 1; s >= 0; s--) {
var cssRules = document.styleSheets[s].cssRules ||
document.styleSheets[s].rules || []; // IE support
for (var c=0; c < cssRules.length; c++) {
if (cssRules[c].selectorText === selectorText)
return cssRules[c].style[propertyName];
}
}
return null;
}
alert(getStyleSheetPropertyValue("p", "color"));
Note that this is pretty fragile, as you have to supply the full selector text that matches the rule you are looking up (it is not parsed) and it does not handle duplicate entries or any kind of precedence rules. It's hard for me to think of a case when using this would be a good idea, but here it is just as an example.
In response to Karim79, I just thought I'd toss out my function version of that answer. I've had to do it several times so this is what I wrote:
function getClassStyles(parentElem, selector, style){
elemstr = '<div '+ selector +'></div>';
var $elem = $(elemstr).hide().appendTo(parentElem);
val = $elem.css(style);
$elem.remove();
return val;
}
val = getClassStyles('.container:first', 'class="title"', 'margin-top');
console.warn(val);
This example assumes you have and element with class="container" and you're looking for the margin-top style of the title class in that element. Of course change up to fit your needs.
In the stylesheet:
.container .title{ margin-top:num; }
Let me know what you think - Would you modify it, and if so how? Thanks!
I have written a helper function that accepts an object with the css attributes to be retrieved from the given css class and fills in the actual css attribute values.
Example is included.
function getStyleSheetValues(colScheme) {
var tags='';
var obj= colScheme;
// enumerate css classes from object
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") {
tags+= '<span class="'+prop+'"></span>';
}
}
// generate an object that uses the given classes
tags= $('<div>'+tags+'</div>').hide().appendTo("body");
// read the class properties from the generated object
var idx= 0;
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") {
var nobj= obj[prop];
for (var nprop in nobj) {
if (nobj.hasOwnProperty(nprop) && typeof(nobj[nprop])=="string") {
nobj[nprop]= tags.find("span:eq("+idx+")").css(nobj[nprop]);
}
}
idx++;
}
}
tags.remove();
}
// build an object with css class names where each class name contains one
// or more properties with an arbitrary name and the css attribute name as its value.
// This value will be replaced by the actual css value for the respective class.
var colorScheme= { chart_wall: {wallColor:'background-color',wallGrid:'color'}, chart_line1: { color:'color'} };
$(document).ready(function() {
getStyleSheetValues(colorScheme);
// debug: write the property values to the console;
if (window.console) {
var obj= colorScheme;
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") {
var nobj= obj[prop];
for (var nprop in nobj) {
if (nobj.hasOwnProperty(nprop)) {
console.log(prop+'.'+nprop +':'+ nobj[nprop]);
}
}
}
}
// example of how to read an individual css attribute value
console.log('css value for chart_wall.wallGrid: '+colorScheme.chart_wall.wallGrid);
}
});
I wrote this js function, seems to be working for nested classes as well:
usage:
var style = get_css_property('.container-class .sub-container-class .child-class', 'margin');
console.log('style');
function get_css_property(class_name, property_name){
class_names = class_name.split(/\s+/);
var container = false;
var child_element = false;
for (var i = class_names.length - 1; i >= 0; i--) {
if(class_names[i].startsWith('.'))
class_names[i] = class_names[i].substring(1);
var new_element = $.parseHTML('<div class="' + class_names[i] + '"></div>');
if(!child_element)
child_element = new_element;
if(container)
$(new_element).append(container);
container = new_element;
}
$(container).hide().appendTo('body');
var style = $(child_element).css(property_name);
$(container).remove();
return style;
}
For a DOM element, how to I get all styles specified in css for a particular element? Is it a case of iterating over all css style names?
Or is there a more elegant way? How does Firebug do it?
Thanks
You should be able to get it with getComputedStyle:
var css = window.getComputedStyle(element);
for (var i=0; i<css.length; i++) {
console.log(css[i] +'='+css.getPropertyValue(""+css[i]))
}
However, this method returns computed style meaning that it will perform some computation and convert your values in px. For example if you have a line-height of 1.2 then it will be returned as 57.6px instead of 1.2
Preveous solutions mangle the styles as they are modified before expanded.
Also you get a lot of default styles.
my solution strips the default styles and keeps the cascading styles through the elements.
Run in console and copy the element you want from the Elements view. (tested in chrome)
function setStyle(theElement) {
var els = theElement.children;
for(var i = 0, maxi = els.length; i < maxi; i++)
{
setStyle(els[i]);
var defaultElem = document.createElement(els[i].nodeName)
var child = document.body.appendChild(defaultElem);
var defaultsStyles = window.getComputedStyle(defaultElem,null);
var computed = window.getComputedStyle(els[i],null).cssText;
for(var j = 0, maxj = defaultsStyles.length; j < maxj; j++)
{
var defaultStyle = defaultsStyles[j] + ": " + defaultsStyles.getPropertyValue(""+defaultsStyles[j]) + ";"
if(computed.startsWith(defaultStyle)) {
computed = computed.substring(defaultStyle.length);
} else {
computed = computed.replace(" " + defaultStyle, "");
}
}
child.remove();
els[i].setAttribute("style", computed);
}
}
setStyle(document.getElementsByTagName("body")[0]);
console.log("DONE");
You can iterate through all of the CSS styles for an element like this:
var myElement = document.getElementById('someId');
var myElementStyle = myElement.style;
for(var i in myElementStyle){
// if it's not a number-index, print it out.
if(/^[\d]+/.exec(i) == null){
console.log("Style %s = %s", i, myElementStyle[i]);
/*
* Do other stuff here...
*/
}
}
For a DOM element, how to I get all
styles specified in css for a
particular element? Is it a case of
iterating over all css style names?
Yes, it is.
Or is there a more elegant way?
I don't know about more elegant (elegance is pretty high on the subjective scale), but it would certainly be shorter and sweeter if you made use of a library such as jQuery, here's a solution someone coded to answer another question:
How Can I Get List Of All Element CSS Attributes with jQuery?
How does Firebug do it?
I have no idea.