Сложный селектор 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.

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


person Deeksy    schedule 05.09.2008    source источник
comment
Точно такая же проблема с Telerik ASP.NET Rad Tabstrip Control ...   -  person Juan Calero    schedule 11.05.2010
comment
В дополнение к приведенным очень полезным ответам я счел полезным просмотреть подробное описание селекторов css по следующему адресу: w3.org/TR/CSS2/selector.html   -  person green-i    schedule 13.09.2010
comment
При поиске в Google у меня возникла противоположная проблема, и я столкнулся с этим вопросом, пытаясь выбрать дочерний элемент элемента, и это так же просто, как: #nav_sub li.active a   -  person Kieran Andrews    schedule 18.10.2010
comment
@Kieran, чтобы быть придирчивым, x y соответствует y, если он потомок x, а x>y соответствует y, если он дочерний x   -  person MatrixFrog    schedule 20.01.2011
comment
Есть уловка: parent в вашем css. оформить заказ stackoverflow.com/a/50657951/1249617   -  person Ton    schedule 03.06.2018
comment
Если другие могут сказать вам еще нет или использовать JavaScript, я скажу вам, что это возможно , но в обход касайтесь чего угодно, кроме body и :root из любого места, используя только CSS и HTML. Однако я не могу рекомендовать это в рабочей среде.   -  person S0AndS0    schedule 09.06.2019
comment
Хотелось бы, чтобы было несколько селекторов CSS, которые позволяют выбирать предков на основе потомков :(   -  person pouya    schedule 01.11.2020


Ответы (10)


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

Однако с JavaScript это не очень сложно:

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

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

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

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

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

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

Обновление:

Selectors Level 4 Spec позволяет вам выбрать, какая часть выбор - это тема:

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

Пример 1:

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

OL > LI:only-child

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

$OL > LI:only-child

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

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

person Sam Hasler    schedule 05.09.2008
comment
Спецификация CSS Selectors 4 теперь включает возможность для селекторов подниматься вверх. stackoverflow.com/q/1014958/392 - person Dan Herbert; 22.11.2011
comment
К вашему сведению, MooTools уже пару лет поддерживает селекторы CSS уровня 4 - и, по иронии судьбы, механизм селекторов Slick в MooTools действительно смог обработать эти селекторы еще до того, как был опубликован черновой вариант спецификации - ›github.com/mootools/slick/wiki / - person csuwldcat; 25.04.2012
comment
@csuwldcat: Селектор темы обсуждается уже несколько лет, возможно, почти через десять лет после безмятежных дней CSS2.0. Но теперь, когда sel4 был обновлен, чтобы использовать ! для выбора темы (через несколько месяцев после вашего комментария), эта реализация предварительно устарела / не соответствует требованиям / отключена / и т. Д. Интересно, обновят ли они свою реализацию соответствующим образом или дождутся ее стабилизации. - person BoltClock; 19.10.2012
comment
Доступна ли сейчас спецификация CSS Selectors 4? (Декабрь 2012 г.) - person Sukanta Paul; 12.12.2012
comment
Для тех, кто все еще смотрит на это, модуль уровня 4 действительно говорит, что селектор :has() (ранее $) доступен только в JavaScript, а не будет доступен в CSS. Это связано с однопроходной природой синтаксического анализатора CSS. - person jhpratt; 22.08.2017

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

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

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

$("li").has(".active")
person David Clarke    schedule 10.08.2010
comment
JSFiddle demo для тестирования ... - person revoke; 08.10.2014
comment
jQuery рекомендует изменить :has(selector) на это: $("li").has('active'). Я реализовал это в демонстрации @revoke JSFiddle выше. api.jquery.com/has-selector - person Afrowave; 25.09.2017

«РОДИТЕЛЬСКИЙ» СЕЛЕКТОР

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

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

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

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

person Praveen Kumar Purushothaman    schedule 22.11.2012
comment
Согласно текущему черновику текущий синтаксис _ 1_. Я нашел css4-selectors.com хорошим справочником по этому поводу. На момент написания этого комментария ни один браузер не поддерживает этот селектор. - person Rob Hall; 16.06.2017
comment
@RobHall "no browsers support this selector" - хм, тогда почему мы об этом говорим? - person Programmer; 14.07.2021
comment
@Programmer Потому что речь идет о проекте CSS4, так что это может быть возможно в будущем. И да, прошло уже почти 9 лет, никаких подвижек! ???? - person Praveen Kumar Purushothaman; 14.07.2021
comment
@Programmer Потому что те, кто плохо знаком с CSS, могут столкнуться с противоречивой документацией или спецификациями и оказаться в этом сообщении SO, пытаясь разрешить свое понимание. Именно это и случилось со мной. Я хотел дать ссылку, чтобы другие люди могли оценить положение дел, не прибегая к лишней работе. - person Rob Hall; 17.07.2021

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

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

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

OL > LI:only-child

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

$OL > LI:only-child

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

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

person Brian    schedule 29.09.2011

Будущий ответ с селекторами 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.

person Matt Wagner    schedule 13.06.2012
comment
К сожалению, это не отвечает на вопрос, поскольку информация о стиле будет применяться к тегу привязки, а не к тегу элемента списка. Проблема не в том, как использовать селекторы, а в том, как ВЫБРАТЬ элемент списка на основе класса дочернего элемента. Таким образом, ваш ответ по-прежнему будет выбирать только якоря с активным классом. - person Deeksy; 14.06.2012

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

person Mark B    schedule 18.05.2009

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

$("li ul").parent().addClass('has-sub');
person ggedde    schedule 28.01.2013

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

person John Drefahl    schedule 29.10.2011
comment
Между прочим ... если шаблон сбивает вас с толку из-за того, что он не является стандартным шаблоном вкладки jQuery, то это потому, что нам пришлось создать его с нуля, чтобы он был доступен для чтения с экрана JAWS. Я скоро напишу об этом. - person John Drefahl; 29.10.2011

Еще одна мысль пришла мне в голову только что, что могло бы быть решением на чистом 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 назначать активному элементу идентификатор вместо класса. Функцию, которую я предоставил, я позаимствовал у другого гения на 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;
}
person Jared    schedule 02.02.2012
comment
Поздно к вечеринке, но тем временем document.getElementsByClassName () стал широко доступным. - person CONTRACT SAYS I'M RIGHT; 14.04.2016