Подтвердить что ты не робот

JQuery: проверьте, находится ли элемент в нормальном потоке

Каков самый элегантный способ проверить, находится ли элемент в обычном потоке с помощью jQuery?

В соответствии с спецификацией CSS3,

Коробка принадлежит потоку, если:

Используемое значение его "дисплея" - это блок, таблица "Список", таблица или шаблон.

     

Используемое значение его "float is" равно none.

     

Используемое значение его "позиции" является "статическим" или "относительным".

     

Это либо дочерний элемент корня потока, либо дочерний элемент поля, принадлежащего потоку.

Должен ли я просто проверять все эти условия или есть лучший способ?

4b9b3361

Ответ 1

Я думаю, что другое требование "в потоке" состоит в том, что overflow установлен на visible.

Из спецификации CSS2:

Поплавки, абсолютно позиционированные элементы, блокировать контейнеры (например, встроенные блоки, таблицы-ячейки и заголовки таблиц), которые не являются блочными блоками, и блокировать блоки с "переполнением", отличными от "видимых" (за исключением случаев, когда это значение был распространен в окне просмотра) для создания содержимого контекстов форматирования блоков.

В соответствии с требованиями, указанными вами, и требованием overflow, это один из способов сделать это с помощью 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;
}
​   

Смотрите jsFiddle для тестовых случаев.

Я не уверен, было бы лучше использовать window.getComputedStyle() или нет.

Функция проверяет, находится ли elm в ctxRoot потоке или контексте форматирования блока (как это было ранее названо, я думаю). Если ctxRoot не поставляется, он будет проверяться на элемент body. Это не проверяет, чтобы поток ctxRoot находился в потоке. Итак, с этим 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>

В тестовых случаях:

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));

Ответ 2

Я сомневаюсь, что это лучший способ, но другой способ:

1) Окружать элемент оберткой

2) Сравните высоту и ширину обертки с обернутым элементом

Например:

$('#elementToTest').clone().addClass('clone').wrap('<div></div>')
if($('#elementToTest.clone').height()>$('#elementToTest.clone').parent().height()){
    //outside the normal flow
}

Ответ 3

Вместо того, чтобы смотреть на него ретроактивно, вы можете упредить необходимость этого, используя аннотации данных. Каждый раз, когда вы создаете или определяете элемент, установите его атрибут data-flow в true или false.

Например:

var newDiv = document.createElement("div");
newDiv.style.position = "absolute";
newDiv.setAttribute("data-flow","false");

Или в html

<div style="position:absolute;" data-flow="false"></div>

И тогда вы можете просто выбрать эти элементы с помощью селектора:

$('*[data-flow=false]')