it-swarm.com.ru

Есть ли селектор CSS «предыдущий брат»?

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

1185
Jourkey

Нет, селектор "предыдущий брат" отсутствует.

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

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

744
cletus

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

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

/* 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>
203
mantish

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

previous:has(+ next) {}

… Но на момент написания этой статьи, это нечто большее, чем кровоточащий край поддержки браузеров.

142
Quentin

Рассмотрим свойство order макетов flex и grid.

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


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

В частности, свойство flex 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. Используйте свойство flex 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 работает только с позиционированными элементами.

На самом деле, самая последняя версия спецификации - W3C Editor's Draft - все еще утверждает, что это правда:

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/

127
Michael_B

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

x ~ y

записывать

y ~ x

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

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

64
Bryan Larsen

Два хитрости. В основном инвертирование порядка 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>
24
Roko C. Buljan

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

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

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

  • + является непосредственным последующим селектором родного брата
  • ~ - это любой последующий селектор брата

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

Однако в библиотеке ax постпроцессора 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>
17
Rounin

Другое 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>
15
Vadim Ovchinnikov

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

Что вы можете сделать, это использовать селектор 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>

Ограничения

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

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

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

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

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

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

Который делает то же самое.

4
kernel

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

В моем случае я хотел использовать 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/

2
Andrew Leyva

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

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

<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
DynamicDan

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

  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>

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

1
Hejar

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


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

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

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

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

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


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

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

Таким образом я мог выбрать ВСЕ #full-widths.
Или я мог бы выбрать .companies, который следует только за #full-width.
Но я не смог выбрать только #full-widths, который продолжился .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.
. find : Получить потомков каждого элемента в текущем наборе соответствующих элементов, отфильтрованных селектор, объект jQuery или элемент.
. родителей : Получить непосредственно предшествующий элемент каждого элемента в наборе соответствующих элементов. Если предоставляется селектор, он извлекает предыдущего родного брата, только если он соответствует этому селектору (фильтрует результаты, чтобы включить только перечисленные элементы/селекторы).
. css : установить одно или несколько свойств CSS для набора соответствующих элементов.

0
SherylHohman

Мне нужно решение, чтобы выбрать предыдущий родной брат 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;
    }
`;
0
kyle