Сложный селектор CSS для родителя активного дочернего элемента

Есть ли способ выбрать родительский элемент на основе класса дочернего элемента в классе? Пример, имеющий отношение ко мне, связанный с выходом HTML с помощью приятного плагина меню для http://drupal.org. Результат выглядит следующим образом:

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

Мой вопрос в том, можно ли применить стиль к элементу списка, который содержит якорь с активным классом на нем. Очевидно, я бы предпочел, чтобы элемент списка был отмечен как активный, но у меня нет контроля над кодом, который создается. Я мог бы выполнять такие вещи, используя javascript (напомню JQuery), но мне было интересно, есть ли способ сделать это с помощью селекторов CSS.

Чтобы быть ясным, я хочу применить стиль к элементу списка, а не к якорю.

Ответ 1

К сожалению, нет способа сделать это с помощью CSS.

Это не очень сложно с JavaScript:

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

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

Ответ 2

Согласно Википедии:

Селекторы не могут подняться

CSS не предлагает выбора родителя или предка элемента, который удовлетворяет определенным критериям. Более совершенная селекторная схема (например, XPath) позволит использовать более сложные таблицы стилей. Однако основные причины, по которым Рабочая группа CSS отклоняет предложения для родительских селекторов, связаны с производительностью браузера и проблемами с инкрементным рендерингом.

И для тех, кто ищет SO в будущем, это может также упоминаться как селектор предков.

Обновление:

Селекторы Уровень 4 Spec позволяет выбрать, какая часть объекта выбора является объектом:

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

Пример 1:

Например, следующий селектор представляет элемент списка LI уникального дочернего элемента упорядоченный список OL:

OL > LI:only-child

Однако следующий представляет собой упорядоченный список OL, имеющий единственный дочерний элемент, этот ребенок является LI:

$OL > LI:only-child

Структуры, представленные этими двумя селекторами, одинаковы, но субъектами селекторов не являются.

Хотя это недоступно (в настоящее время, ноябрь 2011 г.) в любом браузере или в качестве селектора в jQuery.

Ответ 3

Поздно к вечеринке снова, но для того, что это стоит, можно использовать jQuery, чтобы быть немного более кратким. В моем случае мне нужно было найти тег <ul> для тега <span>, содержащегося в дочернем <li>. jQuery имеет селектор :has, поэтому он может идентифицировать родителя по содержащимся в нем детям (обновляется на @Afrowave comment ref: https://api.jquery.com/has-selector/):

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

выберет элемент ul, у которого есть дочерний элемент с id someId. Или, чтобы ответить на исходный вопрос, что-то вроде следующего должно сделать трюк (непроверенный):

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

Ответ 4

SELECTOR "PARENT"

В настоящее время нет возможности выбрать родителя элемента в CSS (даже CSS3). Но с CSS4 наиболее важными новостями в текущем проекте W3C является поддержка родительского селектора.

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

Используя вышеизложенное, при наведении элемента списка весь неупорядоченный список будет выделен путем добавления к нему белого фона.

Официальная документация: https://www.w3.org/TR/2011/WD-selectors4-20110929/#overview (последняя строка).

Ответ 5

Первый черновик Селектора уровня 4 описывает способ явно задать тему селектора. Это позволило бы OP стилизовать элемент списка с помощью селектора $li > a.active

Из Определение темы селектора:

Например, следующий селектор представляет элемент списка LI уникального дочернего элемента упорядоченного списка OL:

OL > LI:only-child

Однако следующий представляет собой упорядоченный список OL, имеющий единственный дочерний элемент, этот ребенок является LI:

$OL > LI:only-child

Структуры, представленные этими двумя селекторами, одинаковы, но субъекты селекторов не являются.

Изменить: учитывая, насколько "сквозняком" может быть черновик, лучше всего следить за этим, проверяя страницу CSSWG на селекторах уровня 4.

Ответ 6

У меня была такая же проблема с Drupal. Учитывая ограничения CSS, способ получить эту работу - добавить "активный" класс к родительским элементам при создании HTML-кода меню. Там хорошо обсуждается это на http://drupal.org/node/219804, результатом чего является то, что эта функциональность была включена в версию 6.x-2.x модуля nicemenus. Поскольку это все еще находится в разработке, я вернул патч в 6.x-1.3 на http://drupal.org/node/465738, чтобы я мог продолжать использовать готовая версия модуля.

Ответ 7

На самом деле я столкнулся с той же проблемой, что и исходный плакат. Существует простое решение только с помощью селектора .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

Ответ 8

Многие ответили с помощью jQuery parent, но просто чтобы добавить к этому, я хотел бы поделиться быстрым фрагментом кода, который я использую для добавления классов в свои навигаторы, поэтому я могу добавить стиль в li, который имеет только суб- -menus, а не li, которые этого не делают.

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

Ответ 9

Еще одна мысль возникла для меня только сейчас, что может быть чистым решением CSS. Отобразите активный класс как абсолютно позиционированный блок и установите его стиль, чтобы скрыть родительский ли.

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 вместо класса. Функция, которую я предоставил, я схватил от какого-то другого гения на SO. Он работает хорошо, просто имейте в виду, когда вы отлаживаете, что функция всегда будет возвращать массив узлов, а не только один node.

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

Ответ 10

Будущий ответ с помощью селекторов CSS4

Новые спецификации CSS содержат экспериментальный :has псевдо-селектор, который может сделать это.

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

В настоящее время поддержка браузера в основном отсутствует, но это рассматривается в официальных спецификациях.


Ответ 2012 года, который был неверным в 2012 году и еще более неправильным в 2018 году

Хотя верно, что CSS не может ASCEND, неверно, что вы не можете получить родительский элемент другого элемента. Позвольте мне повторить:

Используя ваш пример HTML-кода, вы можете получить li без указания li

ul * a {
    property:value;
}

В этом примере ul является родителем некоторого элемента, а этот элемент является родителем якоря. Недостатком использования этого метода является то, что если есть ul с любым дочерним элементом, который содержит привязку, он наследует указанные стили.

Вы также можете использовать дочерний селектор, так как вам все равно придется указывать родительский элемент.

ul>li a {
    property:value;
}

В этом примере якорь должен быть потомком li, который ДОЛЖЕН быть потомком ul, то есть он должен находиться в дереве после объявления ul. Это будет более конкретным и будет захватывать только элемент списка, который содержит якорь И является потомком ul.

ТАК, чтобы ответить на ваш вопрос по коду.

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

Это должно захватить ul с классом меню, и дочерний элемент списка, который содержит только привязку с классом active.