JQuery: check if element is in normal flow
css, html, javascript, jquery
Solution
I think another "in flow" requirement is that `overflow` is set to `visible`.
From the CSS2 spec:
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
- A very detailed answer to a related question.
- YUI blog entry about block formatting contexts.
- A blog post I've found helpful in the past.
Based on the requirements you quoted and the `overflow` requirement, this is one way to do it with jquery:
function isInFlow(elm, ctxRoot) {
ctxRoot = ctxRoot || document.body;
var $elm = $(elm),
ch = -1,
h;
if (!$elm.length) {
return false;
}
while ($elm[0] !== document.body) {
h = $elm.height();
if (h < ch || !okProps($elm)) {
return false;
}
ch = h;
$elm = $elm.parent();
if (!$elm.length) {
// not attached to the DOM
return false;
}
if ($elm[0] === ctxRoot) {
// encountered the ctxRoot and has been
// inflow the whole time
return true;
}
}
// should only get here if elm
// is not a child of ctxRoot
return false;
}
function okProps($elm) {
if ($elm.css('float') !== 'none'){
return false;
}
if ($elm.css('overflow') !== 'visible'){
return false;
}
switch ($elm.css('position')) {
case 'static':
case 'relative':
break;
default:
return false;
}
switch ($elm.css('display')) {
case 'block':
case 'list-item':
case 'table':
return true;
}
return false;
}
See this jsFiddle for test cases.
I'm not sure if it would be better to use `window.getComputedStyle()` or not.
The function is checking to see if `elm` is in `ctxRoot`'s flow or block formatting context (as it was previously called, I think). If `ctxRoot` is not supplied, it will check against the `body` element. This does not check to make sure `ctxRoot` is in flow. So, with this HTML
<div id="b" style="overflow: hidden;">
<div id="ba">ba
<p id="baa">baa</p>
<span id="bab">bab</span>
<span id="bac" style="display:block;">bac</span>
</div>
</div>
The test cases are:
var b = $('#b')[0];
console.log('no ',isInFlow(b));
console.log('no ',isInFlow('#ba'));
console.log('yes ',isInFlow('#ba', b));
console.log('no ',isInFlow('#baa'));
console.log('yes ',isInFlow('#baa', b));
console.log('no ',isInFlow('#bab'));
console.log('no ',isInFlow('#bab', b));
console.log('no ',isInFlow('#bac'));
console.log('yes ',isInFlow('#bac', b));
Problem
What is the most elegant way to check whether an element is in the normal flow using jQuery? According to the CSS3 specification, A box belongs to the flow if: The used value of its ‘display’ is ‘block’, ‘list-item’, ‘table’ or template. The used value of its ‘float’ is ‘none’. The used value of its ‘position’ is ‘static’ or ‘relative’. It is either a child of the flow root or a child of a box that belong to the flow. Should I just check for all these conditions, or is there a better way?