Detect whether an element has position:fixed (possibly by parent element) via jQuery
Here is a solution based on walking through the element's parents, checking the CSS position value for each in turn.
Is this the most efficient way, or is there a way to detect the effective positioning by only examining the element itself?
http://jsfiddle.net/Q4mSJ/
CSS
.trigger-event {background:#ccc}
#one {position:relative; height:50px; width:50px}
#two-wrapper {position:fixed; bottom:0; height:50px; width:50px}
#two {height:50px; width:50px}
HTML
<div id="one" class="trigger-event">element one</div>
<div id="two-wrapper">
<div id="two" class="trigger-event">element two</div>
</div>
JS
function elementOrParentIsFixed(element) {
var $element = $(element);
var $checkElements = $element.add($element.parents());
var isFixed = false;
$checkElements.each(function(){
if ($(this).css("position") === "fixed") {
isFixed = true;
return false;
}
});
return isFixed;
}
$(document).ready(function(){
$('.trigger-event').on('mouseenter', function(event){
var isFixed = elementOrParentIsFixed(event.target);
if (isFixed) {
$(event.target).css('background','red');
} else {
$(event.target).css('background','green');
}
});
});
Using $(selector).offsetParent() you can search through the ancestors of the selector without having to load all the elements parents. It will still have to walk through the elements parents but will stop once it finds the closest element with the chosen position (relative, absolute, or fixed).
http://jsfiddle.net/89y1buz9/11/
CSS:
div {
border: 1px solid #ccc;
}
#outer {
height: 200px;
width: 120px;
position: fixed;
padding-top: 20px;
}
#inner {
width: 95px;
height: 150px;
margin: 0px auto;
position: relative;
}
#clickme {
width: 70px;
height: 50px;
cursor: pointer;
text-align: center;
line-height: 40px;
margin: 20px auto;
}
HTML:
<div id="outer">
<div id="inner">
<div id="clickme">ClickMe</div>
</div>
</div>
Javascript:
function isFixed(ele, posType) {
var eleCheck = ele.offsetParent(),
returnVal;
posType = posType || "fixed";
if (eleCheck.prop("tagName") === 'HTML') {
return false;
}
returnVal = (eleCheck.css("position") !== posType) ? isFixed(eleCheck): posType;
return returnVal;
}
Usage: Call it with or without the second argument it defaults to search for a fixed element
$(function () {
$("#clickme").on("click", function () {
if (isFixed($(this), "fixed") === "fixed") {
$(this).css("background", "red");
} else {
$(this).css("background", "green");
}
});
});
UPDATED, see below...
I dropped by here while searching a pure javascript solution for this... But I hope that somebody will like my jquery version.
Here are two functions, which work slightly different, but the performance differences are minimal. I did not measure it, but according this test on jsperf "each vs filter" the .each()
version is slightly faster.
Nevertheless, I like the .filter()
version because it's so short and clear.
$.fn.isfixed = function(){
var el = $(this);
var all = el.add(el.parents());
return all.filter(function(){
return $(this).css("position") === "fixed";
}).length > 0;
};
$.fn.isfixed = function(){
var el = $(this);
var all = el.add(el.parents());
var ret = false;
all.each(function(){
if ($(this).css("position") === "fixed") {
ret = true;
return false;
}
});
return ret;
};
Usage is $('path > to > your > element').isfixed()
and returns true
or false
UPDATE
And here's the pure javascript version. It turned out, that to detect el.style.position
(fixed/absolute/relative) does not work, don't know why, but window.getComputedStyle(el)...
does.
var isfixed = function(elm) {
var el;
if (typeof elm === 'object') el = elm[0] || elm;
else if (typeof elm === 'string') el = document.querySelector(elm);
while (typeof el === 'object' && el.nodeName.toLowerCase() !== 'body') {
if (window.getComputedStyle(el).getPropertyValue('position').toLowerCase() === 'fixed') return true;
el = el.parentElement;
}
return false;
};
It accepts three kind of element parameters:
as javascript object:
var obj = document.querySelector('div#myID > span');
or
var obj = document.getElementById('span#someID');
as jquery object:
var obj = $('div#myID > span');
or as selector only:
var obj = 'div#myID > span';
Usage is simply isfixed(obj);
and delivers boolean true
or false
And here's finally the mixed solution (pure javascript as jquery plugin)
$.fn.isfixed = function(){
var el = this[0];
while (typeof el === 'object' && el.nodeName.toLowerCase() !== 'body') {
if (window.getComputedStyle(el).getPropertyValue('position').toLowerCase() === 'fixed') return true;
el = el.parentElement;
}
return false;
};
Usage: $('div#myID > span').isfixed()
as in examples above.
Hope you'll like it.