Как выбрать элемент <li>, который является прямым родительским элементом элемента привязки?

Например, мой CSS будет примерно таким:

li < a.active {
    property: value;
}

Очевидно, есть способы сделать это с помощью JavaScript, но я надеюсь, что есть какое-то обходное решение, которое существует в CSS уровня 2.

Меню, которое я пытаюсь стилизовать, извергается CMS, поэтому я не могу переместить активный элемент в элемент <li> ... (если я не оформлю модуль создания меню, который я бы предпочел не делать).

Любые идеи?

3681
jcuenod 18 Июн 2009 в 23:59

30 ответов

Лучший ответ

В настоящее время нет возможности выбрать родительский элемент в CSS.

Если бы и был способ сделать это, он был бы в любой из текущих спецификаций селекторов CSS:

При этом рабочий проект уровня 4 селекторов включает : has () псевдокласс, который предоставит эту возможность. Он будет похож на реализацию jQuery.

li:has(> a.active) { /* styles to apply to the li tag */ }

Однако по состоянию на 2021 год это все еще не поддерживается ни одним браузером .

А пока вам придется прибегнуть к JavaScript, если вам нужно выбрать родительский элемент.

2826
Boris 29 Мар 2021 в 00:14

Я не думаю, что вы можете выбрать родителя только в CSS.

Но поскольку у вас уже есть класс .active, было бы проще переместить этот класс в li (вместо a). Таким образом, вы можете получить доступ как к li, так и к a только через CSS.

168
Peter Mortensen 24 Июл 2019 в 22:21

Вы можете использовать этот скрипт:

*! > input[type=text] { background: #000; }

Это выберет любого родителя текстового ввода. Но подождите, это еще не все. При желании можно выбрать указанного родителя:

.input-wrap! > input[type=text] { background: #000; }

Или выберите его, когда он активен:

.input-wrap! > input[type=text]:focus { background: #000; }

Посмотрите этот HTML:

<div class="input-wrap">
    <input type="text" class="Name"/>
    <span class="help hide">Your name sir</span>
</div>

Вы можете выбрать этот span.help, когда input активен, и показать его:

.input-wrap! .help > input[type=text]:focus { display: block; }

Есть еще много возможностей; просто ознакомьтесь с документацией плагина.

Кстати, это работает в Internet Explorer.

139
Peter Mortensen 24 Июл 2019 в 22:24

Как упоминалось несколькими другими, нет способа стилизовать родительский элемент / элементы с использованием только CSS, но следующее работает с jQuery:

$("a.active").parents('li').css("property", "value");
114
Alastair 2 Май 2013 в 05:11

Родительского селектора нет; точно так же, как нет предыдущего селектора братьев и сестер. Одна из веских причин отсутствия этих селекторов заключается в том, что браузер должен пройти через всех дочерних элементов элемента, чтобы определить, следует ли применять класс. Например, если вы написали:

body:contains-selector(a.active) { background: red; }

Затем браузеру придется подождать, пока он загрузится, и проанализировать все до </body>, чтобы определить, должна ли страница быть красной или нет.

Статья Почему у нас нет родительского селектора подробно это объясняет.

78
Peter Mortensen 24 Июл 2019 в 22:29

В CSS 2 нет способа сделать это. Вы можете добавить класс в li и сослаться на a:

li.active > a {
    property: value;
}
61
Peter Mortensen 24 Июл 2019 в 22:19

Попробуйте переключить a на отображение block, а затем используйте любой стиль, который хотите. Элемент a заполнит элемент li, и вы сможете изменить его внешний вид по своему усмотрению. Не забудьте установить отступ li равным 0.

li {
  padding: 0;
  overflow: hidden;
}
a {
  display: block;
  width: 100%;
  color: ..., background: ..., border-radius: ..., etc...
}
a.active {
  color: ..., background: ...
}
37
Peter Mortensen 24 Июл 2019 в 22:25

Псевдоэлемент :focus-within позволяет выбрать родителя, если у потомка есть фокус.

Элемент может быть сфокусирован, если у него есть атрибут tabindex.

Поддержка браузера для фокусировки внутри

Табиндекс

Пример

.click {
  cursor: pointer;
}

.color:focus-within .change {
  color: red;
}

.color:focus-within p {
  outline: 0;
}
<div class="color">
  <p class="change" tabindex="0">
    I will change color
  </p>
  <p class="click" tabindex="1">
    Click me
  </p>
</div>
31
roberrrt-s 20 Мар 2018 в 13:36

Для что ты хочешь:

E ~ F {
    property: value;
}

Это соответствует любому элементу F, которому предшествует элемент E.

28
Cody Gray 23 Авг 2017 в 12:27

Насколько мне известно, не в CSS 2. CSS 3 имеет более надежные селекторы, но не во всех браузерах единообразно. Я не верю, что даже с улучшенными селекторами он выполнит именно то, что вы указали в своем примере.

26
Mark Hurd 18 Июн 2009 в 20:09

Я знаю, что OP искал решение CSS, но этого легко добиться с помощью jQuery. В моем случае мне нужно было найти родительский тег <ul> для тега <span>, содержащегося в дочернем <li>. jQuery имеет селектор :has, поэтому можно идентифицировать родителя по дочерним элементам, которые он содержит:

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

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

$("li:has(.active)")
23
David Clarke 16 Май 2013 в 22:04

Это наиболее обсуждаемый аспект спецификации Селекторы уровня 4 . При этом селектор сможет стилизовать элемент в соответствии с его дочерним элементом, используя восклицательный знак после данного селектора (!).

Например:

body! a:hover{
   background: red;
}

Установит красный цвет фона, если пользователь наводит курсор на любую привязку.

Но надо дождаться реализации браузеров :(

23
Peter Mortensen 24 Июл 2019 в 22:33

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

a.active h1 {color:red;}

a.active:hover h1 {color:green;}

a.active h2 {color:blue;}

a.active:hover h1 {color:yellow;}

Таким образом, вы можете изменить стиль в нескольких внутренних тегах в зависимости от ролловера родительского элемента.

23
TylerH 15 Апр 2020 в 21:17

Вот хак с использованием pointer-events с hover:

<!doctype html>
<html>
    <head>
        <title></title>
        <style>
/* accessory */
.parent {
    width: 200px;
    height: 200px;
    background: gray;
}
.parent, 
.selector {
    display: flex;
    justify-content: center;
    align-items: center;
}
.selector {
    cursor: pointer;
    background: silver;
    width: 50%;
    height: 50%;
}
        </style>
        <style>
/* pertinent */
.parent {
    background: gray;
    pointer-events: none;
}
.parent:hover {
    background: fuchsia;
}
.parent 
.selector {
    pointer-events: auto;
}
        </style>
    </head>
    <body>
        <div class="parent">
            <div class="selector"></div>
        </div>
    </body>
</html>
19
Jan Kyu Peblik 3 Окт 2020 в 07:57

Идея горизонтального меню ...

Часть HTML

<div class='list'>
  <div class='item'>
    <a>Link</a>
  </div>
  <div class='parent-background'></div>
  <!-- submenu takes this place -->
</div>

Часть CSS

/* Hide parent backgrounds... */
.parent-background {
  display: none; }

/* ... and show it when hover on children */
.item:hover + .parent-background {
  display: block;
  position: absolute;
  z-index: 10;
  top: 0;
  width: 100%; }

Обновленная демонстрация и остальной код

Другой пример того, как использовать его с вводом текста - выберите родительский набор полей

15
Community 20 Июн 2020 в 09:12

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

Здесь много технических объяснений.

Джонатан Снук объясняет, как оценивается CSS.

Крис Койер о разговорах о родительском селекторе.

Гарри Робертс снова о написании эффективных селекторов CSS.

Но Николь Салливан поделился некоторыми интересными фактами о положительных тенденциях..

Все эти люди высшего класса в области фронтенд-разработки.

14
Nathan Tuggy 2 Ноя 2017 в 00:38

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

Одна из вещей, добавленных EQCSS, - это родительский селектор. Он работает во всех браузерах, начиная с Internet Explorer 8 и выше. Вот формат:

@element 'a.active' {
  $parent {
    background: red;
  }
}

Итак, здесь мы открыли элементный запрос для каждого элемента a.active, и для стилей внутри этого запроса такие вещи, как $parent, имеют смысл, потому что есть точка отсчета. Браузер может найти родительский объект, потому что он очень похож на parentNode в JavaScript.

Вот демонстрация $parent и еще одна $parent демонстрация, которая работает в Internet Explorer 8, а также снимок экрана на случай, если у вас нет Internet Explorer 8 для тестирования.

EQCSS также включает мета-селекторы: $prev для элемента перед выбранным элементом и $this только для тех элементов, которые соответствуют запросу элемента, и т. Д.

14
Peter Mortensen 24 Июл 2019 в 22:43

Технически прямого способа сделать это нет. Однако вы можете разобраться с этим с помощью jQuery или JavaScript.

Однако вы тоже можете сделать что-то подобное.

a.active h1 {color: blue;}
a.active p {color: green;}

jQuery

$("a.active").parents('li').css("property", "value");

Если вы хотите добиться этого с помощью jQuery, вот ссылка на родительский селектор jQuery .

11
Peter Mortensen 24 Июл 2019 в 22:36

Короткий ответ: НЕТ . на данном этапе у нас нет parent selector в CSS, но если вам все равно не нужно менять местами элементы или классы, второй вариант использует JavaScript. Что-то вроде этого:

var activeATag = Array.prototype.slice.call(document.querySelectorAll('a.active'));

activeATag.map(function(x) {
  if(x.parentNode.tagName === 'LI') {
    x.parentNode.style.color = 'red'; // Your property: value;
  }
});

Или более короткий способ, если вы используете в своем приложении jQuery :

$('a.active').parents('li').css('color', 'red'); // Your property: value;
11
Peter Mortensen 24 Июл 2019 в 22:45

Сейчас 2019 год, и в последней версии модуля CSS Nesting действительно есть что-то вроде этого. . Представляем @nest at-rules.

3.2. Правило вложенности: @nest

Хотя прямое гнездование выглядит красиво, оно несколько хрупкое. Некоторые допустимые селекторы вложенности, такие как .foo &, запрещены, и изменение селектора определенными способами может неожиданно сделать правило недействительным. Кроме того, некоторым людям сложно визуально отличить вложенность от окружающих деклараций.

Чтобы помочь во всех этих проблемах, эта спецификация определяет правило @nest, которое налагает меньше ограничений на то, как правильно размещать правила стиля. Его синтаксис:

@nest = @nest <selector> { <declaration-list> }

Правило @nest работает так же, как правило стиля: оно начинается с селектора и содержит объявления, которые применяются к элементам, которым соответствует селектор. Единственное отличие состоит в том, что селектор, используемый в правиле @nest, должен содержать вложение, что означает, что он где-то содержит селектор вложенности. Список селекторов содержит вложения, если все его отдельные сложные селекторы содержат вложения.

(Скопируйте и вставьте из URL выше).

Пример допустимых селекторов в соответствии с этой спецификацией:

.foo {
  color: red;
  @nest & > .bar {
    color: blue;
  }
}
/* Equivalent to:
   .foo { color: red; }
   .foo > .bar { color: blue; }
 */

.foo {
  color: red;
  @nest .parent & {
    color: blue;
  }
}
/* Equivalent to:
   .foo { color: red; }
   .parent .foo { color: blue; }
 */

.foo {
  color: red;
  @nest :not(&) {
    color: blue;
  }
}
/* Equivalent to:
   .foo { color: red; }
   :not(.foo) { color: blue; }
 */
11
Community 20 Июн 2020 в 09:12

W3C исключил такой селектор из-за огромного влияния на производительность браузера.

10
rgb 16 Авг 2011 в 04:43

Любые идеи?

CSS4 будет красивым, если он добавит несколько крючков в ход назад . До тех пор можно (хотя не рекомендуется) использовать checkbox и / или radio input для разрыва обычным способом, которым все соединяются, и посредством этого также позволяет CSS работать за пределами своей нормальной области действия ...

/* Hide things that may be latter shown */
.menu__checkbox__selection,
.menu__checkbox__style,
.menu__hidden {
  display: none;
  visibility: hidden;
  opacity: 0;
  filter: alpha(opacity=0); /* Old Microsoft opacity */
}


/* Base style for content and style menu */
.main__content {
  background-color: lightgray;
  color: black;
}

.menu__hidden {
  background-color: black;
  color: lightgray;
  /* Make list look not so _listy_ */
  list-style: none;
  padding-left: 5px;
}

.menu__option {
  box-sizing: content-box;
  display: block;
  position: static;
  z-index: auto;
}

/* &#9660; - \u2630 - Three Bars */
/*
.menu__trigger__selection::before {
  content: '\2630';
  display: inline-block;
}
*/

/* &#9660; - Down Arrow */
.menu__trigger__selection::after {
  content: "\25BC";
  display: inline-block;
  transform: rotate(90deg);
}


/* Customize to look more `select` like if you like */
.menu__trigger__style:hover,
.menu__trigger__style:active {
  cursor: pointer;
  background-color: darkgray;
  color: white;
}


/**
 * Things to do when checkboxes/radios are checked
 */

.menu__checkbox__selection:checked + .menu__trigger__selection::after,
.menu__checkbox__selection[checked] + .menu__trigger__selection::after {
  transform: rotate(0deg);
}

/* This bit is something that you may see elsewhere */
.menu__checkbox__selection:checked ~ .menu__hidden,
.menu__checkbox__selection[checked] ~ .menu__hidden {
  display: block;
  visibility: visible;
  opacity: 1;
  filter: alpha(opacity=100); /* Microsoft!? */
}


/**
 * Hacky CSS only changes based off non-inline checkboxes
 * ... AKA the stuff you cannot unsee after this...
 */
.menu__checkbox__style[id="style-default"]:checked ~ .main__content {
  background-color: lightgray;
  color: black;
}

.menu__checkbox__style[id="style-default"]:checked ~ .main__content .menu__trigger__style[for="style-default"] {
  color: darkorange;
}

.menu__checkbox__style[id="style-one"]:checked ~ .main__content {
  background-color: black;
  color: lightgray;
}

.menu__checkbox__style[id="style-one"]:checked ~ .main__content .menu__trigger__style[for="style-one"] {
  color: darkorange;
}

.menu__checkbox__style[id="style-two"]:checked ~ .main__content {
  background-color: darkgreen;
  color: red;
}

.menu__checkbox__style[id="style-two"]:checked ~ .main__content .menu__trigger__style[for="style-two"] {
  color: darkorange;
}
<!--
  This bit works, but will one day cause troubles,
  but truth is you can stick checkbox/radio inputs
  just about anywhere and then call them by id with
  a `for` label. Keep scrolling to see what I mean
-->
<input type="radio"
       name="colorize"
       class="menu__checkbox__style"
       id="style-default">
<input type="radio"
       name="colorize"
       class="menu__checkbox__style"
       id="style-one">
<input type="radio"
       name="colorize"
       class="menu__checkbox__style"
       id="style-two">


<div class="main__content">

  <p class="paragraph__split">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  </p>

  <input type="checkbox"
         class="menu__checkbox__selection"
         id="trigger-style-menu">
  <label for="trigger-style-menu"
         class="menu__trigger__selection"> Theme</label>

  <ul class="menu__hidden">
    <li class="menu__option">
      <label for="style-default"
             class="menu__trigger__style">Default Style</label>
    </li>

    <li class="menu__option">
      <label for="style-one"
             class="menu__trigger__style">First Alternative Style</label>
    </li>

    <li class="menu__option">
      <label for="style-two"
             class="menu__trigger__style">Second Alternative Style</label>
    </li>
  </ul>

  <p class="paragraph__split">
    consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
    cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
    proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </p>

</div>

... довольно грубо , но с помощью только CSS и HTML можно коснуться и повторно коснуться чего угодно, кроме body и :root практически из любого места, связав Свойства id и for триггеров radio / checkbox input и label ; вероятно, в какой-то момент кто-то покажет, как их повторно коснуться.

Еще одно предостережение: может быть использован только один input из определенного id, первый checkbox / radio побеждает иными словами, переключенное состояние ... Но все несколько ярлыков могут указывать на один и тот же input, хотя это сделало бы и HTML, и CSS еще грубее.


... Я надеюсь, что есть какое-то обходное решение, которое существует в CSS уровня 2 ...

Я не уверен насчет других псевдоклассов, но я :checked для pre-CSS 3. Если я правильно помню, это было что-то вроде [checked], поэтому вы можете найти его в приведенном выше коде для пример,

.menu__checkbox__selection:checked ~ .menu__hidden,
.menu__checkbox__selection[checked] ~ .menu__hidden {
 /* rules: and-stuff; */
}

... но для таких вещей, как ::after и :hover, я совершенно не уверен, в какой версии CSS они появились впервые.

С учетом всего сказанного, пожалуйста, никогда не используйте это в продакшене, даже в гневе. Конечно, в шутку или, другими словами, просто потому, что что-то можно сделать, не всегда означает, что это должно .

7
S0AndS0 18 Сен 2020 в 17:55

Хотя в настоящее время в стандартном CSS нет родительского селектора, я работаю над (личным) проектом под названием ax (т. Е. расширенный синтаксис селектора CSS / ACSSSS ), который, среди прочего, его 7 новых селекторов включают в себя:

  1. селектор непосредственного родителя < (который включает выбор, противоположный >)
  2. селектор любого предка ^ (который включает выбор, противоположный [SPACE])

ax в настоящее время находится на относительно ранней стадии бета-разработки.

Смотрите демонстрацию здесь:

.parent {
  float: left;
  width: 180px;
  height: 180px;
  margin-right: 12px;
  background-color: rgb(191, 191, 191);
}

.child {
  width: 90px;
  height: 90px;
  margin: 45px;
  background-color: rgb(255, 255, 0);
}

.child.using-axe < .parent {
  background-color: rgb(255, 0, 0);
}
<div class="parent">
  <div class="child"></div>
</div>

<div class="parent">
  <div class="child using-axe"></div>
</div>


<script src="https://rouninmedia.github.io/axe/axe.js"></script>

В приведенном выше примере < - это непосредственный родительский селектор , поэтому

  • .child.using-axe < .parent

Означает:

любой непосредственный родитель .child.using-axe, который является .parent

В качестве альтернативы вы можете использовать:

  • .child.using-axe < div

Что означало бы:

любой непосредственный родительский элемент .child.using-axe, который является div

7
Rounin 19 Янв 2021 в 14:29

По крайней мере, до CSS 3 включительно вы не можете так выбрать. Но в настоящее время это можно сделать довольно легко с помощью JavaScript, вам просто нужно добавить немного ванильного JavaScript, обратите внимание, что код довольно короткий.

cells = document.querySelectorAll('div');
[].forEach.call(cells, function (el) {
    //console.log(el.nodeName)
    if (el.hasChildNodes() && el.firstChild.nodeName=="A") {
        console.log(el)
    };
});
<div>Peter</div>
<div><a href="#">Jackson link</a></div>
<div>Philip</div>
<div><a href="#">Pullman link</a></div>
5
Peter Mortensen 24 Июл 2019 в 22:50

Нет, вы не можете выбрать родителя только в CSS.

Но поскольку у вас уже есть класс .active, было бы проще переместить этот класс в li (вместо a). Таким образом, вы можете получить доступ как к li, так и к a только через CSS.

4
Peter Mortensen 24 Июл 2019 в 22:40

Изменение родительского элемента на основе дочернего элемента в настоящее время может происходить только тогда, когда у нас есть элемент <input> внутри родительского элемента. Когда вход получает фокус, соответствующий родительский элемент может быть затронут с помощью CSS.

Следующий пример поможет вам понять использование :focus-within в CSS.

.outer-div {
  width: 400px;
  height: 400px;
  padding: 50px;
  float: left
}

.outer-div:focus-within {
  background: red;
}

.inner-div {
  width: 200px;
  height: 200px;
  float: left;
  background: yellow;
  padding: 50px;
}
<div class="outer-div">
  <div class="inner-div">
    I want to change outer-div(Background color) class based on inner-div. Is it possible?
    <input type="text" placeholder="Name" />
  </div>
</div>
2
VFDan 7 Июл 2019 в 00:56

Я бы нанял для этого код JavaScript. Например, в React, когда вы перебираете массив, добавьте еще один класс к родительскому компоненту, что указывает на то, что он содержит ваших дочерних элементов:

<div className={`parent ${hasKiddos ? 'has-kiddos' : ''}`}>
    {kiddos.map(kid => <div key={kid.id} />)}
</div>

А потом просто:

.parent {
    color: #000;
}

.parent.has-kiddos {
    color: red;
}
2
Damiano 2 Янв 2020 в 15:41

Попробуй это...

Это решение использует простые правила CSS2 без Javascript и работает во всех браузерах, как старых, так и новых . При нажатии дочерний тег anchor активирует событие псевдокласса active. Затем он просто скрывается, позволяя событию active всплывать в родительский тег li, который затем изменяет свой стиль и снова открывает своего дочернего якоря в новом стиле. Ребенок стилизовал родителя.

Используя ваш пример:

<ul>
    <li class="listitem">
        <a class="link" href="#">This is a Link</a>
    </li>
</ul>

Теперь примените эти стили с псевдоклассом active на a, чтобы изменить стиль родительского тега li при нажатии на ссылку:

a.link {
    display: inline-block;
    color: white;
    background-color: green;
    text-decoration: none;
    padding: 5px;
}

li.listitem {
    display: inline-block;
    margin: 0;
    padding: 0;
    background-color: transparent;
}

/* When this 'active' pseudo-class event below fires on click, it hides itself,
triggering the active event again on its parent which applies new styles to itself and its child. */

a.link:active {
    display: none;
}

.listitem:active {
    background-color: blue;
}

.listitem:active a.link {
    display: inline-block;
    background-color: transparent;
}

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

enter image description here

Превращается в

enter image description here

По щелчку.

2
Stokely 1 Мар 2021 в 17:35

Да: :has()

Поддержка браузера: нет

183
RockPaperLz- Mask it or Casket 10 Июн 2020 в 10:20

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

4
Dmitry Sokolov 31 Янв 2020 в 15:53