Существует ли CSS-селектор “предыдущий брат”?

StackOverflow https://stackoverflow.com/questions/1817792

  •  08-07-2019
  •  | 
  •  

Вопрос

Знак " плюс " (+) предназначен для следующего брата или сестер.Есть ли эквивалент для предыдущего брата или сестры?

Это было полезно?

Решение

Нет, "предыдущего брата" нет " селектор.

В связанной заметке ~ предназначен для обычного наследного брата (то есть элемент идет после этого, но не обязательно сразу после) и является селектором CSS3. + для следующего брата и является CSS2.1.

См. комбинатор соседних братьев и сестер из Селекторы 3-го уровня и 5.7 Селекторы соседних братьев и сестер из Каскадные таблицы стилей, уровень 2, редакция 1 (CSS 2.1), спецификация .

Другие советы

Я нашел способ стилизовать всех предыдущих братьев и сестер (в отличие от ~) это может сработать в зависимости от того, что вам нужно.

Допустим, у вас есть список ссылок, и при наведении курсора мыши на одну из них все предыдущие должны стать красными.Вы можете сделать это вот так:

/* default link color is blue */
.parent a {
  color: blue;
}

/* prev siblings should be red */
.parent:hover a {
  color: red;
}
.parent a:hover,
.parent a:hover ~ a {
  color: blue;
}
<div class="parent">
  <a href="#">link</a>
  <a href="#">link</a>
  <a href="#">link</a>
  <a href="#">link</a>
  <a href="#">link</a>
</div>

Селекторы 4-го уровня вводят :has() (ранее предметный индикатор !), который позволит вам выбрать предыдущего родного брата с:

previous:has(+ next) {}

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

Рассмотрим следующие order свойство гибких и сеточных макетов.

В приведенных ниже примерах я сосредоточусь на flexbox, но те же концепции применимы и к Grid.


С помощью flexbox можно смоделировать предыдущий однотипный селектор.

В частности, гибкий order свойство может перемещать элементы по экрану.

Вот пример:

Вы хотите, чтобы элемент A становился красным при наведении курсора мыши на элемент B.

<ul>
    <li>A</li>
    <li>B</li>
</ul>

ШАГИ

  1. Сделайте так, чтобы ul гибкий контейнер.

    ul { display: flex; }
    

  1. Измените порядок расположения братьев и сестер в разметке в обратном порядке.

    <ul>
       <li>B</li>
       <li>A</li>
    </ul>
    

  1. Используйте одноранговый селектор для нацеливания на элемент A (~ или + сделаю) .

    li:hover + li { background-color: red; }
    

  1. Используйте гибкий order свойство для восстановления порядка расположения братьев и сестер на визуальном дисплее.

    li:last-child { order: -1; }
    

...и вуаля!Рождается (или, по крайней мере, моделируется) предыдущий селектор родственных связей.

Вот полный код:

ul {
    display: flex;
}

li:hover + li {
    background-color: red;
}

li:last-child {
    order: -1;
}

/* non-essential decorative styles */
li {
    height: 200px;
    width: 200px;
    background-color: aqua;
    margin: 5px;
    list-style-type: none;
    cursor: pointer;
}
<ul>
    <li>B</li>
    <li>A</li>
</ul>

Из спецификации flexbox:

5.4.Порядок отображения:тот самый order собственность

Элементы Flex по умолчанию отображаются и располагаются в том же порядке, в каком они представлены в исходном документе.Тот Самый order свойство может быть использовано для изменения этого порядка.

Тот Самый order свойство управляет порядком отображения элементов flex в контейнере flex, присваивая им порядковые группы.Для этого требуется один <integer> значение, указывающее, к какой порядковой группе относится элемент flex .

Начальный order значение для всех элементов flex равно 0.

Также смотрите order в спецификации CSS Grid Layout.


Примеры "предыдущих родственных селекторов", созданных с помощью flex order собственность.

.container { display: flex; }

.box5 { order: 1; }    
.box5:hover + .box4 { background-color: orangered; font-size: 1.5em; }

.box6 { order: -4; }
.box7 { order: -3; }
.box8 { order: -2; }
.box9 { order: -1; }
.box9:hover ~ :not(.box12):nth-child(-1n+5) { background-color: orangered;
                                              font-size: 1.5em; }
.box12 { order: 2; }
.box12:hover ~ :nth-last-child(-1n+2) { background-color: orangered;
                                        font-size: 1.5em; }
.box21 { order: 1; }
.box21:hover ~ .box { background-color: orangered; font-size: 1.5em; }

/* non-essential decorative styles */
.container {
    padding: 5px;
    background-color: #888;
}
.box {
    height: 50px;
    width: 75px;
    margin: 5px;
    background-color: lightgreen;
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    cursor: pointer;
}
<p>
Using the flex <code>order</code> property to construct a previous sibling selector
</p>

<div class="container">
    <div class="box box1"><span>1</span></div>
    <div class="box box2"><span>2</span></div>
    <div class="box box3"><span>3</span></div>
    <div class="box box5"><span>HOVER ME</span></div>
    <div class="box box4"><span>4</span></div>
</div>

<br>

<div class="container">
    <div class="box box9"><span>HOVER ME</span></div>
    <div class="box box12"><span>HOVER ME</span></div>
    <div class="box box6"><span>6</span></div>
    <div class="box box7"><span>7</span></div>
    <div class="box box8"><span>8</span></div>
    <div class="box box10"><span>10</span></div>
    <div class="box box11"><span>11</span></div>
</div>

<br>

<div class="container">
    <div class="box box21"><span>HOVER ME</span></div>
    <div class="box box13"><span>13</span></div>
    <div class="box box14"><span>14</span></div>
    <div class="box box15"><span>15</span></div>
    <div class="box box16"><span>16</span></div>
    <div class="box box17"><span>17</span></div>
    <div class="box box18"><span>18</span></div>
    <div class="box box19"><span>19</span></div>
    <div class="box box20"><span>20</span></div>
</div>

jsFiddle


Дополнительное замечание – Два устаревших представления о CSS

Flexbox разрушает давние представления о CSS.

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

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

Как описано выше, это убеждение не совсем верно.Предыдущий селектор родственных элементов может быть смоделирован в CSS с помощью flex order собственность.

Тот Самый z-index Миф

Еще одним давним убеждением было то, что z-index работает только с расположенными элементами.

Фактически, самая актуальная версия спецификации – the Черновик редактора W3C – все еще утверждает, что это правда:

9.9.1 Указание уровня стека:тот самый z-index собственность

z-index

  • Значение:автоматически | | наследовать
  • Начальный:автоматический
  • Применяется к:позиционируемые элементы
  • Унаследованный:НЕТ
  • Проценты:N/A
  • Медиафайлы:визуальный
  • Вычисленное значение:как указано

(курсив добавлен)

Однако на самом деле эта информация устарела и неточна.

Элементы , которые являются гибкие изделия или элементы сетки может создавать контексты укладки, даже если position является static.

4.3.Гибкий элемент Z-Заказ

Элементы Flex отображаются точно так же, как встроенные блоки, за исключением того, что порядок документов, измененный порядком, используется вместо исходного порядок документов и z-index значения, отличные от auto создайте контекст стекирования, даже если position является static.

5.4.Упорядочение по оси Z:тот самый z-index собственность

Порядок отображения элементов сетки точно такой же, как у встроенных блоков, за исключением того, что порядок документов, измененный порядком, используется вместо исходного порядка документов, и z-index значения, отличные от auto создайте контекст стекирования, даже если position является static.

Вот демонстрация того, как z-index работа с непозиционированными гибкими элементами: https://jsfiddle.net/m0wddwxs/

У меня был тот же вопрос, но потом у меня был "Дух" момент. Вместо того, чтобы писать

x ~ y

написать

y ~ x

Очевидно, это соответствует " x " вместо "y", но он отвечает на "есть ли совпадение?" вопрос, и простой обход DOM может привести вас к нужному элементу более эффективно, чем зацикливание в JavaScript.

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

Два хитрости.В основном инвертируя HTML-порядок ваших желаемых элементов в HTML и используя
~ Следующие братья и сестры оператор:

float-right + измените порядок расположения HTML-элементов в обратном порядке

div{ /* Do with the parent whatever you know just to make the
  inner float-right elements appear where desired */
  display:inline-block;
}
span{
  float:right;  /* float-right the elements! */
}
span:hover ~ span{ /* On hover target it's "previous";) elements */
  background:red;
} 
<div>
  <!-- Reverse the order of inner elements -->
  <span>5</span>
  <span>4</span>
  <span>3</span>
  <span>2</span>
  <span>1</span>
</div>


Родитель с direction: rtl; + обратный порядок внутренних элементов

.inverse{
  direction: rtl;
  display: inline-block; /* inline-block to keep parent at the left of window */
}
span:hover ~ span{ /* On hover target it's "previous";) elements */
  background:gold;
}
Hover one span and see the previous elements being targeted!<br>

<div class="inverse">
  <!-- Reverse the order of inner elements -->
  <span>5</span>
  <span>4</span>
  <span>3</span>
  <span>2</span>
  <span>1</span>
</div>

+ это для следующего брата или сестренки.Существует ли эквивалент для предыдущего брата или сестры?

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

Есть такие 2 последующие родственные селекторы в обычном CSS:

  • + является ли немедленный последующий селектор родственных связей
  • ~ является ли Любой последующий селектор родственных связей

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

Однако, в топор Библиотека постпроцессора CSS, в которой есть 2 предыдущие селекторы сиблингов:

  • ? является ли немедленный предыдущий селектор родственных связей (напротив +)
  • ! является ли Любой предыдущий селектор родственных связей (напротив ~)

Рабочий Пример:

В приведенном ниже примере:

  • .any-subsequent:hover ~ div выбирает любой последующий div
  • .immediate-subsequent:hover + div выбирает немедленное последующее div
  • .any-previous:hover ! div выбирает любой предыдущий div
  • .immediate-previous:hover ? div выбирает непосредственный предыдущий div

div {
  display: inline-block;
  width: 60px;
  height: 100px;
  color: rgb(255, 255, 255);
  background-color: rgb(255, 0, 0);
  text-align: center;
  vertical-align: top;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.6s ease-out;
}

code {
  display: block;
  margin: 4px;
  font-size: 24px;
  line-height: 24px;
  background-color: rgba(0, 0, 0, 0.5);
}

div:nth-of-type(-n+4) {
  background-color: rgb(0, 0, 255);
}

div:nth-of-type(n+3):nth-of-type(-n+6) {
  opacity: 1;
}

.any-subsequent:hover ~ div,
.immediate-subsequent:hover + div,
.any-previous:hover ! div,
.immediate-previous:hover ? div {
  opacity: 1;
}
<h2>Hover over any of the blocks below</h2>

<div></div>
<div></div>

<div class="immediate-previous">Hover for <code>?</code> selector</div>
<div class="any-previous">Hover for <code>!</code> selector</div>
<div class="any-subsequent">Hover for <code>~</code> selector</div>
<div class="immediate-subsequent">Hover for <code>+</code> selector</div>

<div></div>
<div></div>

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

Еще одно решение flexbox

Вы можете использовать обратный порядок элементов в HTML.Затем, помимо использования order как в Ответ Michael_B вы можете использовать flex-direction: row-reverse; или flex-direction: column-reverse; в зависимости от вашего макета.

Рабочий образец:

.flex {
  display: flex;
  flex-direction: row-reverse;
   /* Align content at the "reversed" end i.e. beginning */
  justify-content: flex-end;
}

/* On hover target its "previous" elements */
.flex-item:hover ~ .flex-item {
  background-color: lime;
}

/* styles just for demo */
.flex-item {
  background-color: orange;
  color: white;
  padding: 20px;
  font-size: 3rem;
  border-radius: 50%;
}
<div class="flex">
  <div class="flex-item">5</div>
  <div class="flex-item">4</div>
  <div class="flex-item">3</div>
  <div class="flex-item">2</div>
  <div class="flex-item">1</div>
</div>

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

Что вы можете сделать, так это использовать селектор CSS3 :псевдокласс под названием nth-child()

#list>* {
  display: inline-block;
  padding: 20px 28px;
  margin-right: 5px;
  border: 1px solid #bbb;
  background: #ddd;
  color: #444;
  margin: 0.4em 0;
}

#list :nth-child(-n+4) {
  color: #600b90;
  border: 1px dashed red;
  background: orange;
}
<p>The oranges elements are the previous sibling li selected using li:nth-child(-n+4)</p>

<div id="list">
  <span>1</span><!-- this will be selected -->
  <p>2</p><!-- this will be selected -->
  <p>3</p><!-- this will be selected -->
  <div>4</div><!-- this will be selected -->
  <div>5</div>
  <p>6</p>
  <p>7</p>
  <p>8</p>
  <p>9</p>
</div>

Ограничения

  • Вы не можете выбрать предыдущие элементы на основе классов следующих элементов
  • Это то же самое для псевдоклассов

Если вы знаете точную позицию, сработает исключение на основе : nth-child () всех следующих братьев и сестер.

ul li:not(:nth-child(n+3))

Который выбрал бы все li до 3-го (например, 1-го и 2-го). Но, на мой взгляд, это выглядит некрасиво и имеет очень узкий сценарий использования.

Вы также можете выбрать n-го ребенка справа налево:

ul li:nth-child(-n+2)

Что делает то же самое.

К сожалению, нет "предыдущего" селектора родственных связей, но вы можете возможно все равно получите тот же эффект, используя позиционирование (например,плывите вправо).Это зависит от того, что вы пытаетесь сделать.

В моем случае я хотел использовать в первую очередь 5-звездочную систему оценки CSS.Мне нужно было бы раскрасить (или поменять местами значок) предыдущих звездочек.Перемещая каждый элемент вправо, я, по сути, получаю тот же эффект (таким образом, html для звезд должен быть написан "задом наперед").

В этом примере я использую FontAwesome и переключаюсь между юникодами fa-star-o и fa-star http://fortawesome.github.io/Font-Awesome/

CSS:

.fa {
    display: inline-block;
    font-family: FontAwesome;
    font-style: normal;
    font-weight: normal;
    line-height: 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* set all stars to 'empty star' */
.stars-container {
    display: inline-block;      
}   

/* set all stars to 'empty star' */
.stars-container .star {
    float: right;
    display: inline-block;
    padding: 2px;
    color: orange;
    cursor: pointer;

}

.stars-container .star:before {
    content: "\f006"; /* fontAwesome empty star code */
}

/* set hovered star to 'filled star' */
.star:hover:before{
    content: "\f005"; /* fontAwesome filled star code */
}

/* set all stars after hovered to'filled star' 
** it will appear that it selects all after due to positioning */
.star:hover ~ .star:before {
    content: "\f005"; /* fontAwesome filled star code */
}

HTML:(40)

JSFiddle: http://jsfiddle.net/andrewleyva/88j0105g/

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

Скажем, у нас есть:

<div>
  <ul>
    <li><a>Pants</a></li>
    <li><a>Socks</a></li>
    <ul>
      <li><a>White socks</a></li>
      <li><a>Blue socks</a></li>
    </ul>
  </ul>
</div>

Что мы можем сделать, чтобы блок Socks (включая цвета носков) выделялся визуально с помощью пробелов?

Что бы хорошо, но не существует:

ul li ul:parent {
  margin-top: 15px;
  margin-bottom: 15px;
}

Что существует:

li > a {
  margin-top: 15px;
  display: block;
}
li > a:only-child {
  margin-top: 0px;
}

Это устанавливает для всех якорных ссылок верхний край в 15px и сбрасывает его обратно в 0 для тех, у которых нет элементов UL (или других тегов) внутри LI.

У меня была похожая проблема, и я обнаружил, что все проблемы такого рода можно решить следующим образом:

  1. придайте всем вашим предметам стиль.
  2. придайте выбранному вами предмету стиль.
  3. присвоите следующим элементам стиль, используя + или ~.

и таким образом вы сможете стилизовать свои текущие, предыдущие элементы (все элементы переопределяются текущими и следующими элементами) и ваши следующие элементы.

пример:

/* all items (will be styled as previous) */
li {
  color: blue;
}

/* the item i want to distinguish */
li.milk {
  color: red;
}

/* next items */
li ~ li  {
  color: green;
}


<ul>
  <li>Tea</li>
  <li class="milk">Milk</li>
  <li>Juice</li>
  <li>others</li>
</ul>

Надеюсь, это кому-нибудь поможет.

Нет.Это невозможно с помощью CSS.Это принимает "Каскад" близко к сердцу ;-).


Однако, если вы сможете добавить JavaScript на вашу страницу, немного jQuery это могло бы привести вас к вашей конечной цели.
Вы можете использовать jQuery find чтобы выполнить "предварительный просмотр" вашего целевого элемента / класса / идентификатора, затем вернитесь назад, чтобы выбрать свою цель.
Затем вы используете jQuery, чтобы переписать DOM (CSS) для вашего элемента.

Основанный на этот ответ Майка Бранта, следующий фрагмент jQuery мог бы помочь.

$('p + ul').prev('p')

При этом сначала выбираются все <ul>ы, которые немедленно следуют за <p>.
Затем он "возвращается назад", чтобы выбрать все предыдущие <p>ы из этого набора <ul>s.

Фактически, "предыдущий брат" был выбран с помощью jQuery.
Теперь используйте .css функция для передачи в ваш CSS новых значений для этого элемента.


В моем случае я искал способ выбрать DIV с идентификатором #full-width, но ТОЛЬКО в том случае, если у него был (косвенный) потомок DIV с классом .companies.

У меня был контроль над всем HTML-кодом в разделе .companies, но не смог изменить ни один HTML-код над ним.
И каскад идет только в 1 направлении:вниз.

Таким образом, я мог бы выбрать ВСЕ #full-widths.
Или я мог бы выбрать .companies это последовало только за #full-width.
Но я мог бы нет выбрать только #full-widthэто что продолжалось .companies.

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

Но с помощью jQuery я может выберите необходимый #full-widths, затем назначьте соответствующий стиль:

$("#full-width").find(".companies").parents("#full-width").css( "width", "300px" );

Это находит все #full-width .companies, и выбирает только те .companies, аналогично тому, как селекторы используются для таргетинга на определенные элементы в стандарте CSS.
Затем он использует .parents чтобы "вернуться назад" и выбрать ВСЕХ родителей .companies,
но фильтрует эти результаты, чтобы сохранить только #fill-width элементы, так что в конце концов,
он выбирает только #full-width элемент, если он имеет .companies потомок класса.
Наконец, он присваивает новый CSS (width) значение результирующего элемента.

$(".parent").find(".change-parent").parents(".parent").css( "background-color", "darkred");
div {
  background-color: lightblue;
  width: 120px;
  height: 40px;
  border: 1px solid gray;
  padding: 5px;
}
.wrapper {
  background-color: blue;
  width: 250px;
  height: 165px;
}
.parent {
  background-color: green;
  width: 200px;
  height: 70px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<div class="wrapper">

  <div class="parent">
    "parent" turns red
    <div class="change-parent">
    descendant: "change-parent"
    </div>
  </div>
  
  <div class="parent">
    "parent" stays green
    <div class="nope">
    descendant: "nope"
    </div>
  </div>
  
</div>
Target <b>"<span style="color:darkgreen">parent</span>"</b> to turn <span style="color:red">red</span>.<br>
<b>Only</b> if it <b>has</b> a descendant of "change-parent".<br>
<br>
(reverse cascade, look ahead, parent un-descendant)
</html>

Справочные документы по jQuery:
$() или jQuery():Элемент DOM.
.Найти:Получите потомков каждого элемента в текущем наборе сопоставленных элементов, отфильтрованных с помощью селектора, объекта jQuery или элемента.
.родители:Получите непосредственно предшествующий сиблинг каждого элемента в наборе совпадающих элементов.Если указан селектор, он извлекает предыдущий аналог только в том случае, если он соответствует этому селектору (фильтрует результаты, чтобы они включали только перечисленные элементы / селекторы).
.css:Задайте одно или несколько свойств CSS для набора совпадающих элементов.

Мне нужно решение, чтобы выбрать предыдущего родного брата tr. Я придумал это решение, используя компоненты React и Styled. Это не мое точное решение (это по памяти, часы спустя). Я знаю, что есть ошибка в функции setHighlighterRow.

OnMouseOver для строки установит индекс строки в состояние и повторно отобразит предыдущую строку с новым цветом фона

class ReactClass extends Component {
  constructor() {
    this.state = {
       highlightRowIndex: null
    }
  }

  setHighlightedRow = (index) => {
    const highlightRowIndex = index === null ? null : index - 1;
    this.setState({highlightRowIndex});
  }

  render() {
    return (
       <Table>
        <Tbody>
           {arr.map((row, index) => {
                const isHighlighted = index === this.state.highlightRowIndex
                return {
                    <Trow 
                        isHighlighted={isHighlighted}
                        onMouseOver={() => this.setHighlightedRow(index)}
                        onMouseOut={() => this.setHighlightedRow(null)}
                        >
                        ...
                    </Trow>
                }
           })}  
        </Tbody>   
       </Table>
    )
  }
}

const Trow = styled.tr`
    & td {
        background-color: ${p => p.isHighlighted ? 'red' : 'white'};
    }

    &:hover {
        background-color: red;
    }
`;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top