复杂的CSS选择器的父活动子

是否有一种方法可以根据类中的子元素的类来选择父元素?这个例子与我有关,它通过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选择器。

为了明确起见,我想对列表项应用样式,而不是锚。

413496 次浏览

你可以使用has():

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

不幸的是,CSS没有办法做到这一点。

用JavaScript实现并不难:

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


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

根据维基百科:

选择者无法提升

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

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

更新:

选择器4级规格允许你选择选择的哪个部分是主题:

选择器的主题可以通过前置显式标识 美元符号($)到选择器中的一个复合选择器。 尽管选择器表示的元素结构是 不管有没有美元符号,都一样,表示主题 Way可以改变哪个复合选择器表示其中的主题 结构。< / p >

示例1:

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

OL > LI:only-child
但是下面这个表示一个有序列表OL,它有唯一的子元素, 那个孩子是LI:

$OL > LI:only-child
这两个选择器表示的结构是相同的, 但是选择器的主题不是。

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

我在Drupal上也遇到了同样的问题。考虑到CSS的局限性,使其工作的方法是在生成菜单HTML时将“活动”类添加到父元素中。在http://drupal.org/node/219804上对此有一个很好的讨论,其结果是该功能已滚入版本6.x-2。nicemenus模块的X。由于这仍在开发中,我已经在http://drupal.org/node/465738将补丁反向移植到6.x-1.3,以便我可以继续使用模块的生产就绪版本。

这次又迟到了,但是值得的是,使用jQuery可以更简洁一点。在我的例子中,我需要为子<li>中包含的<span>标记找到<ul>父标记。jQuery有:has选择器,所以可以通过它包含的子对象来识别父对象(根据@Afrowave的评论ref: https://api.jquery.com/has-selector/更新):

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

将选择带有id为someId的子元素的ul元素。或者要回答最初的问题,以下内容应该可以达到目的(未经测试):

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

选择器4级的第一稿概述了显式设置选择器的主题的方法。这将允许OP使用选择器$li > a.active对列表元素进行样式化

确定选择器的主题:

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

OL > LI:only-child

但是下面这个表示一个有序列表OL,它有一个唯一的子元素,这个子元素是一个LI:

$OL > LI:only-child

这两个选择器所表示的结构是相同的,但选择器的主题却不同。

编辑:鉴于“草案”;一个规范草案可以,最好通过检查CSSWG的页面上的选择器级别4来密切关注这一点。

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

绑定事件(在这种情况下,由于我的选项卡在Modal中,我需要用.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

我刚刚想到的另一个想法可能是一个纯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;
}

对于那些想使用javascript而不使用jquery的人…

选择父对象很简单。你需要一个某种类型的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;
}

未来答案与CSS4选择器

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

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

浏览器支持在这个时候基本不存在,但是在官方规格上正在考虑。


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

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

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

ul * a {
property:value;
}

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

你也可以使用子选择器,因为你必须指定父元素。

ul>li a {
property:value;
}

在这个例子中,锚必须是li的后代,li必须是ul的子结点,这意味着它必须在ul声明之后的树中。这将更具体一点,它只抓取包含锚点并且是ul的子元素的列表项。

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

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

这将抓取带有menu类的ul,以及只包含带有active类的锚的子列表项。

“父”选择器

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

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

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

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

很多人的答案是jQuery parent,但为了补充这一点,我想分享一段快速的代码片段,我用来向我的导航中添加类,这样我就可以为只有子菜单的li添加样式,而不是为没有子菜单的li添加样式。

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