【问题标题】:Complex CSS selector for parent of active child [duplicate]活动孩子的父母的复杂CSS选择器[重复]
【发布时间】:2010-09-07 21:12:08
【问题描述】:

有没有办法根据类中子元素的类来选择父元素?与我相关的示例与http://drupal.org 的漂亮菜单插件的 HTML 输出有关。输出呈现如下:

<ul class="menu">  
    <li>  
        <a class="active">Active Page</a>  
    </li>  
    <li>    
        <a>Some Other Page</a>  
    </li>  
</ul>  

我的问题是是否可以将样式应用于包含带有活动类的锚的列表项。显然,我希望将列表项标记为活动,但我无法控制生成的代码。我可以使用 javascript(想到 JQuery)来执行这类事情,但我想知道是否有办法使用 CSS 选择器来做到这一点。

为了清楚起见,我想将样式应用于列表项,而不是锚点。

【问题讨论】:

  • 与 Telerik ASP.NET Rad Tabstrip Control 完全相同的问题...
  • 除了给出的非常有用的答案之外,我发现查看 css 选择器的详细描述很有用,地址如下:w3.org/TR/CSS2/selector.html
  • 在 Google 中搜索时,我遇到了相反的问题,遇到了这个问题,试图选择一个元素的子元素,它很简单:#nav_sub li.active a
  • @Kieran 吹毛求疵,x y 匹配 y,如果它是 x后代,而 x&gt;y 匹配 y 如果它是 x 的孩子
  • 有一个技巧可以在你的 CSS 中使用 :parent。结帐stackoverflow.com/a/50657951/1249617

标签: css css-selectors


【解决方案1】:

According to Wikipedia:

选择器无法上升

CSS 无法选择满足特定条件的元素的父级或祖先。更高级的选择器方案(例如 XPath)将支持更复杂的样式表。然而,CSS 工作组拒绝父选择器提案的主要原因与浏览器性能和增量渲染问题有关。

对于将来搜索 SO 的任何人,这也可能被称为祖先选择器。

更新:

Selectors Level 4 Spec 允许您选择选择的哪一部分是主题:

选择器的主题可以通过前置显式标识 选择器中的复合选择器之一的美元符号 ($)。 虽然选择器所代表的元素结构是 相同的有或没有美元符号,表明本主题 方式可以更改哪个复合选择器代表该主题 结构。

示例 1:

例如,以下选择器表示列表项 LI 的唯一子项 有序列表 OL:

OL > LI:only-child

但是下面的一个表示一个有序列表 OL 有一个唯一的孩子, 那个孩子是李:

$OL > LI:only-child

这两个选择器表示的结构是一样的, 但选择器的主题不是。

尽管这在任何浏览器中都不可用(目前是 2011 年 11 月)或作为 jQuery 中的选择器。

【讨论】:

  • CSS 选择器 4 规范现在包括选择器上升的能力。 stackoverflow.com/q/1014958/392
  • 仅供参考,MooTools 已经支持 CSS 4 级选择器已有几年了——具有讽刺意味的是,MooTools 中的 Slick 选择器引擎实际上能够在规范草案发布之前处理这些选择器—— > github.com/mootools/slick/wiki/…
  • @csuwldcat:主题选择器已经讨论了好几年了,可能距离 CSS2.0 太平时代已经过去了近十年。但是现在 sel4 已更新为使用 ! 选择主题(在您发表评论后几个月),该实现暂时已过时/不符合/关闭/等。我想知道他们何时/是否会相应地更新他们的实现,或者等待它稳定下来。
  • 对于仍在查看此内容的任何人,第 4 级模块确实表明 :has() 选择器(以前为 $)仅在 JavaScript 中可用,并且不会在 CSS 中可用。这是由于 CSS 解析器的单通道特性。
【解决方案2】:

很遗憾,CSS 无法做到这一点。

不过,使用 JavaScript 并不难:

// JavaScript code:
document.getElementsByClassName("active")[0].parentNode;

// jQuery code:
$('.active').parent().get(0); // This would be the <a>'s parent <li>.

【讨论】:

    【解决方案3】:

    聚会又迟到了,但值得一提的是,使用 jQuery 可以更简洁一些。在我的情况下,我需要为子 &lt;li&gt; 中包含的 &lt;span&gt; 标签找到 &lt;ul&gt; 父标签。 jQuery 具有:has 选择器,因此可以通过它包含的子代来识别父代(根据@Afrowave 的评论更新:https://api.jquery.com/has-selector/):

    $("ul").has("#someId")
    

    将选择具有 ID 为 someId 的子元素的 ul 元素。或者要回答最初的问题,类似以下内容应该可以解决问题(未经测试):

    $("li").has(".active")
    

    【讨论】:

    【解决方案4】:

    “父”选择器

    现在,在 CSS(甚至 CSS3)中没有选择元素的父级的选项。但是对于 CSS4,当前 W3C 草案中最重要的消息是对父选择器的支持。

    $ul li:hover{
        background: #fff;
    }
    

    使用上面的方法,当悬停一个列表元素时,整个无序列表将通过添加一个白色背景来突出显示。

    官方文档:https://www.w3.org/TR/2011/WD-selectors4-20110929/#overview(最后一行)。

    【讨论】:

    • 根据current draft,当前语法是!subject &gt; selector。我发现css4-selectors.com 是一个很好的参考。在发表此评论时,没有浏览器支持此选择器。
    • @RobHall "no browsers support this selector" - 嗯,那我们为什么要谈论它?
    • @Programmer 因为这是关于 CSS4 草案的,所以将来可能会。是的,已经快 9 年了,没有任何进展! ?
    • @Programmer 因为那些刚接触 CSS 的人可能会遇到相互冲突的文档或规范,并在试图解决他们的理解时出现在这个 SO 帖子上。这正是发生在我身上的事。我想提供一个参考,以便其他人无需额外的跑腿就可以了解事态。
    【解决方案5】:

    Selectors Level 4 的初稿概述了一种明确设置选择器的主题 的方法。这将允许 OP 使用选择器 $li &gt; a.active

    设置列表元素的样式

    来自Determining the Subject of a Selector

    例如,以下选择器表示有序列表 OL 的列表项 LI 唯一子项:

    OL &gt; LI:only-child

    但是下面的一个表示一个有序列表 OL 有一个唯一的孩子,那个孩子是一个 LI:

    $OL &gt; LI:only-child

    这两个选择器所代表的结构是一样的,但是选择器的主题不同。

    编辑:鉴于规范草案的“草稿”程度,最好通过查看CSSWG's page on selectors level 4 来密切关注这一点。

    【讨论】:

      【解决方案6】:

      CSS4 选择器的未来答案

      新的 CSS 规范包含一个实验性的 :has 伪选择器,它可能能够做到这一点。

      li:has(a:active) {
        /* ... */
      }
      

      这个上的browser support这个时候基本没有,但是official specs上的在考虑中。


      2012 年的答案在 2012 年是错误的,在 2018 年更错误

      虽然 CSS 确实不能 ASCEND,但不能抓取另一个元素的父元素是不正确的。让我重申一下:

      使用您的 HTML 示例代码,您可以在不指定 li 的情况下获取 li

      ul * a {
          property:value;
      }
      

      在本例中,ul 是某个元素的父元素,而该元素是锚点的父元素。使用此方法的缺点是,如果 ul 的任何子元素包含锚点,它会继承指定的样式。

      您也可以使用子选择器,因为无论如何您都必须指定父元素。

      ul>li a {
          property:value;
      }
      

      在此示例中,锚点必须是 li 的后代,该 li 必须是 ul 的子节点,这意味着它必须位于 ul 声明之后的树中。这会更具体一点,只会抓取一个包含锚点并且是 ul 的子项的列表项。

      所以,用代码回答你的问题。

      ul.menu > li a.active {
          property:value;
      }
      

      这应该抓取带有菜单类的 ul,以及只包含一个带有活动类的锚的子列表项。

      【讨论】:

      • 不幸的是,这并不能回答问题,因为样式信息将应用于锚标记,而不是列表项标记。问题不在于如何使用选择器,而在于如何根据子类别选择列表项。所以你的答案仍然只会选择类活动的锚。
      【解决方案7】:

      我在使用 Drupal 时遇到了同样的问题。鉴于 CSS 的限制,实现此功能的方法是在生成菜单 HTML 时将“活动”类添加到父元素。 http://drupal.org/node/219804 对此进行了很好的讨论,其结果是该功能已被纳入 nicemenus 模块的 6.x-2.x 版本。由于这仍在开发中,我已将补丁程序向后移植到 http://drupal.org/node/465738 的 6.x-1.3,以便我可以继续使用该模块的生产就绪版本。

      【讨论】:

        【解决方案8】:

        许多人回答jQuery parent,但为了补充一点,我想分享一个快速的 sn-p 代码,用于向我的导航添加类,以便我可以向 li 的添加样式只有子菜单而没有li 的子菜单。

        $("li ul").parent().addClass('has-sub');
        

        【讨论】:

          【解决方案9】:

          我实际上遇到了与原始海报相同的问题。有一个简单的解决方案,只使用.parent() jQuery 选择器。我的问题是,我使用的是.parent 而不是.parent()。愚蠢的错误我知道。

          绑定事件(在这种情况下,由于我的选项卡处于模态状态,我需要使用 .live 而不是基本的 .click 绑定它们。

          $('#testTab1 .tabLink').live('click', function() {
              $('#modal ul.tabs li').removeClass("current"); //Remove any "current" class
              $(this).parent().addClass("current"); //Add "current" class to selected tab
              $('#modal div#testTab1 .tabContent').hide();
              $(this).next('.tabContent').fadeIn();   
              return false;
          })
          $('#testTab2 .tabLink').live('click', function() {
              $('#modal ul.tabs li').removeClass("current"); //Remove any "current" class
              $(this).parent().addClass("current"); //Add "current" class to selected tab
              $('#modal div#testTab2 .tabContent').hide();
              $(this).next('.tabContent').fadeIn();   
              return false;
          })
          

          这里是 HTML..

          <div id="tabView1" style="display:none;">
            <!-- start: the code for tabView 1 -->
            <div id="testTab1" style="width:1080px; height:640px; position:relative;">
              <h1 class="Bold_Gray_45px">Modal Header</h1>
              <div class="tabBleed"></div>
              <ul class="tabs">
                <li class="current"> <a href="#" class="tabLink" id="link1">Tab Title Link</a>
                  <div class="tabContent" id="tabContent1-1">
                    <div class="modalCol">
                      <p>Your Tab Content</p>
                      <p><a href="#" class="tabShopLink">tabBased Anchor Link</a> </p>
                    </div>
                    <div class="tabsImg"> </div>
                  </div>
                </li>
                <li> <a href="#" class="tabLink" id="link2">Tab Title Link</a>
                  <div class="tabContent" id="tabContent1-2">
                    <div class="modalCol">
                      <p>Your Tab Content</p>
                      <p><a href="#" class="tabShopLink">tabBased Anchor Link</a> </p>
                    </div>
                    <div class="tabsImg"> </div>
                  </div>
                </li>
              </ul>
            </div>
          </div>
          

          当然你可以重复那个模式……用更多的 LI

          【讨论】:

          • 顺便说一句.. 如果该模式因为它不是标准的 jQuery Tab 模式而让您感到困惑,那是因为我们必须从头开始构建它才能使其成为 JAWS 屏幕阅读器可访问的模式。我很快就会写一篇文章。
          【解决方案10】:

          我刚才想到的另一个想法可能是纯 CSS 解决方案。将您的活动类显示为绝对定位的块,并设置其样式以覆盖父 li。

          a.active {
             position:absolute;
             display:block;
             width:100%;
             height:100%;
             top:0em;
             left:0em;
             background-color: whatever;
             border: whatever;
          }
          /* will also need to make sure the parent li is a positioned element so... */
          ul.menu li {
              position:relative;
          }    
          

          对于那些想要在没有 jquery 的情况下使用 javascript 的人...

          选择父母是微不足道的。您需要某种getElementsByClass 函数,除非您可以让您的drupal 插件为活动项目分配ID 而不是Class。我提供的功能是从 SO 上的其他天才那里获得的。它运行良好,请记住在调试时该函数将始终返回一个节点数组,而不仅仅是单个节点。

          active_li = getElementsByClass("active","a");
          active_li[0].parentNode.style.whatever="whatever";
          
          function getElementsByClass(node,searchClass,tag) {
              var classElements = new Array();
              var els = node.getElementsByTagName(tag); // use "*" for all elements
              var elsLen = els.length;
              var pattern = new RegExp("\\b"+searchClass+"\\b");
              for (i = 0, j = 0; i < elsLen; i++) {
                 if ( pattern.test(els[i].className) ) {
                 classElements[j] = els[i];
                 j++;
             }
          }
          return classElements;
          }
          

          【讨论】:

          • 迟到了,但与此同时,document.getElementsByClassName() 已广泛使用。
          猜你喜欢
          • 2011-07-14
          • 2018-07-16
          相关资源
          最近更新 更多