If you were to display element via the console, you would see that element does not have the attribute childElementCount -- but the first member of the element array does. Thus, refer to element[0] for all the attributes, and it behaves as expected. I think this is due to the selector you've used.
function isOverflowing(element) {
// 1. Main Part for overflow check
if (element.offsetHeight < element.scrollHeight ||
element.offsetWidth < element.scrollWidth) {
return true;
}
// 2. Partially invisible items
var invisibleItems = [];
for(var i=0; i<element[0].childElementCount; i++){
if (element[0].children[i].offsetTop + element[0].children[i].offsetHeight >
element[0].offsetTop + element[0].offsetHeight ||
element[0].children[i].offsetLeft + element[0].children[i].offsetWidth >
element[0].offsetLeft + element[0].offsetWidth ){
invisibleItems.push(element[0].children[i]);
}
}
if (invisibleItems.length) {
return true;
}
// Otherwise, neither Part 1 nor 2, return FALSE
return false;
}
$('#result').html('#1? ' + isOverflowing($('li:eq(0)')) +
'#2? ' + isOverflowing($('li:eq(1)')) +
'#3? ' + isOverflowing($('li:eq(2)')) +
'#4? ' + isOverflowing($('li:eq(3)'))
);
.type1 {
border: 1px solid black;
width: 130px;
height: 30px;
margin-bottom: 5px;
}
.type2 {
border: 1px dotted red;
width: 50px;
height: 25px;
margin-bottom: 45px;
}
.type3 {
border: 1px dashed blue;
width: 200px;
height: 40px;
margin-bottom: 5px;
}
.type4 {
border: 1px dashed green;
width: 100px;
height: 10px;
margin-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="type1"><span>Some text in LI 1</span></li>
<li class="type2"><span>Some more text in LI 2</span></li>
<li class="type3"><span>A long string of text in LI3</span></li>
<li class="type4"><span>A much longer string of text in LI4</span></li>
</ul>
<br/>
<br/>
<br/>
<br/>
<p id="result"></p>
As you say, however, this solution isn't generic enough -- it doesn't allow for nested DOM nodes. To fix this, we would want a recursive function. Try this, possibly. It's working, I think, but it really made my brain hurt to think recursively. ;)
function isOverflowing(element) {
/*******
* This is going to be a recursive function -- first,
* it'll check if there are children elements and,
* if not, simply return true. In the event there
* are child elements, it should recurse over each
* to see if any child overflows, whether partially
* invis or not.
******/
var elOverflows;
var el = element[0];
// On the first iteration, we initialize these. On every
// recursive iteration, we simply preserve them
var mainHeight = el.offsetTop + el.offsetHeight,
mainOffsetHeight = el.offsetHeight,
mainWidth = el.offsetLeft + el.offsetWidth,
mainOffsetWidth = el.offsetWidth;
// 1. Main Part for overflow check
if (mainOffsetHeight < el.scrollHeight ||
mainOffsetWidth < el.scrollWidth) {
elOverflows = true;
return elOverflows;
}
/***
* 2. If the current element doesn't contain any
* children, and the above check didn't return,
* then we don't have any overflow.
***/
if (el.childElementCount == 0) {
elOverflows = false;
return elOverflows;
} else {
// Here, we have child elements. We want to iterate
// over each of them and re-call isOverflowing() on
// each one. This is the recursion, allowing us to
// have any number of nested child elements.
$(el.children).each(function() {
elOverflows = isOverflowing($(this));
});
return elOverflows;
}
}
$("#container li").each(function() {
$("#result").append("<p>#" + $(this).index() + ": " + isOverflowing($(this)));
})
.type1 {
border: 1px solid black;
width: 130px;
height: 30px;
margin-bottom: 5px;
}
.type2 {
border: 1px dotted red;
width: 50px;
height: 25px;
margin-bottom: 45px;
}
.type3 {
border: 1px dashed blue;
width: 200px;
height: 40px;
margin-bottom: 5px;
}
.type4 {
border: 1px dashed green;
width: 100px;
height: 10px;
margin-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id='container'>
<li class="type1"><span>Some text in LI 1</span></li>
<li class="type2"><span>Some more text in LI 2</span></li>
<li class="type3"><span>A long string <span>containing A much longer string </span> in its center bit.</span>
</li>
<li class="type4"><span>A much longer string of text in LI4</span></li>
</ul>
<br/>
<br/>
<br/>
<br/>
<p id="result"></p>
I've made isOverflowing recursive, and for each child node of the current node, I simply re-call it again, until there are no more child nodes. passing the return value out to the initial call allows us to see if any of the child nodes exceed the bounds of the initial node.
Hope this helps!