Есть ли родительский селектор CSS?

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

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

li < a.active {
    property: value;
}

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

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

Есть идеи?

40 ответов

Решение

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

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

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


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

С помощью :has() Исходный вопрос может быть решен с помощью этого:

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

Да: :has()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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>

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

li.active > a {
    property: value;
}

Попробуй переключиться 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: ...
}

Селектор CSS " General Sibling Combinator" может быть использован для того, что вы хотите:

E ~ F {
    property: value;
}

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

Обновленные селекторы CSS 2022 4

В спецификации CSS Selectors 4 CSS представляет новый селектор под названием:has(), что, наконец, позволяет нам выбирать родителей. Это означает, что мы сможем настроить таргетинг на элемент CSS, внутри которого есть определенные дочерние элементы. Это уже поддерживается в Safari, а также есть в Chrome 105. Полная таблица поддержки показана здесь.

Работа родительских селекторов

В CSS, если мы хотим что-то выбрать, мы используем селекторы, спускающиеся по DOM.

Например, выбор тега ap внутри тега div выглядит следующим образом:

       div p {
   color: red;
}

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

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

Например, выбор с ребенком теперь выглядит так:

      div:has(p) {
  color: red;
}

Это сделает любой с ребенкомpкрасный.

Объединение родительского выбора с другими селекторами

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

      div:has(> span) {
  color: red;
}

Как следует из словаря, он не ограничивается только родительским выбором.

Например, ниже мы можем выбратьspanкакой братdiv:

      span:has(+ div) {
color: red;
}

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

Например, следующее выберет любой div, у которого нет дочернего элемента ap:

      div:not(:has(p)) {
 color: red;
}

Выбор элементов, которые содержат только текст в CSS

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

Хотя это не идеальное решение для простого:emptyэлементы с пробелами (поскольку это выберет любой элемент только с текстом и без дополнительных элементов HTML DOM) — это дает нам возможность выбирать элементы DOM только с текстовыми узлами, что раньше было невозможно. Мы можем добиться этого с помощью следующего кода:

      div:not(:has(*)) {
  background: green;
}

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

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

a.active h1 {color:red;}

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

a.active h2 {color:blue;}

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

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

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

Например:

body! a:hover{
   background: red;
}

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

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

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

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

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

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

Вот взломать с помощью 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>

Кто-нибудь предложил что-то подобное? Просто идея для горизонтального меню...

часть 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%; }

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

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

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

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

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

Крис Койер о беседах селектора родителей.

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

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

Эти люди все высшего класса в области разработки переднего плана.

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

EQCSS добавляет родительский селектор. Работает во всех браузерах IE8 и выше. Вот формат:

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

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

Вот демо $parent и другой $parent демонстрация, которая работает в IE8, а также скриншот на случай, если у вас нет IE8 для тестирования.

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

Родительский селектор CSS (также известный как селектор :has()) наконец-то появился в Safari TP 137. В настоящее время эта функция также реализуется в Chrome. (Документация MDN )

Выбор родителя осуществляется через псевдокласс :has(). Например, div:has(> .child)выберет все <div>элементы с ребенком, имеющим childучебный класс.

Другие примеры:

Выбор прямого родителя элемента

      <div>
  <p>Child Element</p>
</div>
      div:has(> p)

Выбор всех родителей элемента

      <div id="grandparent">
      <div id="parent">
            <div id="child"></div>
      <div>
</div>

Следующий селектор выберет оба grandparentа также parent

      div:has(.child)

Вы также можете использовать его для вложенных селекторов и даже с другими псевдоклассами:

      div:has(> :nth-child(10))

Для настройки запроса можно использовать другие допустимые операторы CSS.

Следите за совместимостью с браузерами на caniuse.com/css-has .

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

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

Технически нет прямого способа сделать это, однако, вы можете отсортировать его с помощью jquery или javascript.

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

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

JQuery

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

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

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

Короткий ответ - НЕТ, у нас нет 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;

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

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

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

Смотрите демо здесь:

http://rounin.co.uk/projects/axe/axe2.html

(сравните два списка слева в стиле стандартных селекторов и два списка справа в стиле топоров)

Есть идеи?

CSS 4 будет интересен, если он добавит несколько хуков в ход назад. До этого можно (хотя и не желательно) использовать checkbox и / или radioinputчтобысломать обычный способ, которым вещи связаны, и через это также позволяют 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/checkboxinputс и 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 они впервые появились.

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

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

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

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

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

Изменение родительского элемента на основе дочернего элемента в настоящее время может произойти только тогда, когда у нас есть <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>

Другие вопросы по тегам