【问题标题】:JQuery: check if element is in normal flowJQuery:检查元素是否处于正常流程中
【发布时间】:2012-12-11 19:21:20
【问题描述】:

使用 jQuery 检查元素是否处于正常流程中最优雅的方法是什么?

根据CSS3 specification

如果满足以下条件,则框属于流:

其‘display’的使用值为‘block’、‘list-item’、‘table’或template

它的‘float’的使用值为‘none’。

它的“位置”的使用值是“静态”或“相对”。

它要么是流根的子节点,要么是属于流的框的子节点。

我应该检查所有这些情况,还是有更好的方法?

【问题讨论】:

  • 我的第一个问题是,你为什么需要知道这个?您可能只需要在实际应用中测试这些品质之一。
  • 如果这是一个仅在规范中使用的定义,您最好检查实际情况。
  • 我正在从事一个个人的副项目,其中涉及在浏览器中复制和粘贴样式内容。我想删除流中第一个元素的上边距和流中最后一个元素的下边距。
  • 如果您需要引用 CSS3 规范来说明元素在流中的含义,这意味着它与您的实际需要有些不同。顺便说一句,恕我直言,如果您甚至不知道粘贴的元素是什么,那么您将承担的任务不仅仅涉及 jQuery,而且您还需要了解一些 vanilla js。跨度>
  • 结合 jQuery + js 对每种情况进行测试,应该不会那么难。只需要十行代码。

标签: javascript jquery html css


【解决方案1】:

我怀疑有更好的方法,但另一种方法是:

1) 用包装器包围元素

2) 比较包装器与被包装元素的高度和宽度

例如:

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

【讨论】:

  • 对不起,我的意思是:这将如何检查元素是否处于正常流动中?
  • 不流动的元素不给他们的父母高度或宽度。
  • 有趣的技术,但是添加包装器div 似乎会导致误读,这取决于选择器在#elementToTest 上的应用方式。例如,如果导致#elementToTest 流出的原因是像.wrapper &gt; .originalElem {position: absolute} 这样的选择器,那么用div 包装它的克隆会破坏选择器正在寻找的直接子关系。兄弟选择器和其他选择器可能会被此方法破坏。因此,如果您确切地知道他们的期望,您的解决方案可能会很有用,但它不会成为一个好的通用解决方案。
【解决方案2】:

我认为另一个“流动”要求是将overflow 设置为visible

From the CSS2 spec:

浮动、绝对定位元素、不是块框的块容器(例如内联块、表格单元格和表格标题),以及具有“溢出”而不是“可见”的块框(该值除外已传播到视口)为其内容建立新的块格式化上下文。

根据您引用的要求和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));

【讨论】:

  • 接受深入分析和测试用例。在某些情况下,另一种解决方案已被证明是错误的。
【解决方案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]')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 2015-08-05
    • 2015-03-05
    • 2012-02-16
    • 1970-01-01
    • 2014-11-14
    • 2011-06-03
    相关资源
    最近更新 更多