Czy istnieje selektor „poprzedniego rodzeństwa”?

1354

Znak plus ( +) dotyczy następnego rodzeństwa.

Czy istnieje odpowiednik dla poprzedniego rodzeństwa?

Jourkey
źródło
17
OMG, wszystkie odpowiedzi tutaj sugerujące odwrócenie kolejności elementów HTML, a następnie użycie CSS, aby pojawiały się wstecz, są naprawdę rozciągliwe. Jasne, że nie określono tego w pytaniu, ale większość pytań „czy możesz zrobić X z CSS” powinna zakładać, że nie możesz strukturalnie zmienić HTML.
squarecandy
3
@squarecandy, w większości zgadzam się z twoim komentarzem. Ale rozwiązania, które określasz jako nieodpowiednie, są jednak przydatne w niektórych przypadkach (zwróć uwagę na opinie). Dlatego warto je opublikować. To, co postrzegasz jako „prawdziwy odcinek”, może być „kreatywnym rozwiązaniem” dla innych.
Michael Benjamin

Odpowiedzi:

839

Nie, nie ma selektora „poprzedniego rodzeństwa”.

Powiązana uwaga ~dotyczy generalnego następcy (co oznacza, że ​​element pojawia się po tym, ale niekoniecznie natychmiast po nim) i jest selektorem CSS3. +jest dla następnego rodzeństwa i jest CSS2.1.

Zobacz Kombinator sąsiedniego rodzeństwa z Selektorów Poziom 3 i 5.7 Selektor sąsiedniego rodzeństwa z Kaskadowych Arkuszy Stylów Poziom 2 Wersja 1 (CSS 2.1) Specyfikacja .

Cletus
źródło
14
Ze standardu CSS3: Elementy reprezentowane przez dwie sekwencje mają tego samego rodzica w drzewie dokumentów, a element reprezentowany przez pierwszą sekwencję poprzedza (niekoniecznie natychmiast) element reprezentowany przez drugą.
Lie Ryan,
26
@Lie Ryan: Tak, ale chodzi Cletus robi w jego odpowiedź jest taka, że nie wybrać element poprzedzający.
BoltClock
42
Oto przykład, który podałem, aby zobaczyć, co to może, a czego nie może zrobić. jsfiddle.net/NuuHy/1
Abacus
7
Przydatną do tego funkcją jquery jest prev (). Na przykład $ („# the_element”). Prev (). Css („kolor tła”, „czerwony”)
Satbir Kira
1
W zależności od znaczników może to pomóc: stackoverflow.com/questions/42680881/...
samnau
234

Znalazłem sposób na stylizację wszystkich poprzednich rodzeństw (przeciwnie do ~), które mogą działać w zależności od potrzeb.

Załóżmy, że masz listę linków, a po najechaniu na nią wszystkie poprzednie powinny zmienić kolor na czerwony. Możesz to zrobić w następujący sposób:

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

mantish
źródło
17
Możesz dodać wyjaśnienie, jak to działa. (wygląda na to, że zastosujesz styl do wszystkich elementów i do następujących elementów, ale można to wyraźnie opisać)
AL
1
Niesamowite rozwiązanie. Nie trzeba zmieniać kolejności elementów w znacznikach ani w renderowaniu (via float:right). Wymagało to zawinięcia białych znaków między jednostkami / słowami i wypełnienia zamiast marginesów, ale działa idealnie inaczej!
Steven Vachon
7
tak, ale przez większość czasu potrzebny jest jeden poprzedni NIE WSZYSTKIE poprzednie!
azerafati
41
Wszystkie linki zmieniają kolor na czerwony, jeśli zatrzymam się nad przestrzenią między nimi.
Lynn,
3
@ Lynn odpowiedź zawiera tylko kod powodujący, że poprzednie linki po najechaniu kursorem stały się czerwone. Dodatkowe style zależą od przypadku użycia. W przypadku elementu oznaczonego gwiazdką (co, jak sądzę, jest częstym przypadkiem), musisz pozbyć się tego miejsca, a także zmienić kolor na czerwony.
Mantish
164

Poziom selektorów 4 wprowadza:has() (wcześniej wskaźnik przedmiotu !), który pozwoli ci wybrać poprzednie rodzeństwo za pomocą:

previous:has(+ next) {}

… Ale w chwili pisania tego tekstu jest pewien dystans do najnowocześniejszej obsługi przeglądarki.

Quentin
źródło
51
„Bleeding edge for support browser” może być zawyżeniem. Pisząc to, nawet najnowsza wersja Chrome nie może używać :has()pseudoklasy.
Reed Martin,
33
@ReedMartin - Właśnie dlatego powiedziałem, że jestem trochę dalej niż krwawiąca krawędź
Quentin
12
„: has nie jest oznaczony jako część dynamicznego profilu wyboru, co oznacza, że ​​nie można go używać w arkuszach stylów; tylko z funkcjami takimi jak document.querySelector ().” - developer.mozilla.org/en-US/docs/Web/CSS/:has
Arch Linux Tux
1
@ArchLinuxTux: „To ograniczenie jest już usunięte”, więc kiedyś będziemy mogli użyć tej funkcji: D.
Jacob van Lingen
@JacobvanLingen - caniuse.com/#feat=css-has - Obecnie żadna przeglądarka go nie obsługuje.
Quentin
153

Rozważ orderwłaściwość układów flex i grid.

Skoncentruję się na Flexbox w poniższych przykładach, ale te same koncepcje dotyczą Grid.


Dzięki Flexbox można symulować poprzedni selektor rodzeństwa.

W szczególności orderwłaściwość flex może przenosić elementy po ekranie.

Oto przykład:

Chcesz, aby element A zmienił kolor na czerwony, gdy element B zostanie najechany.

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

KROKI

  1. Zrób ulelastyczny pojemnik.

    ul { display: flex; }

  1. Odwróć kolejność rodzeństwa w narzutu.

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

  1. Użyj selektora rodzeństwa, aby wybrać element A ( ~lub +zrobi to).

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

  1. Użyj orderwłaściwości flex, aby przywrócić kolejność rodzeństwa na ekranie wizualnym.

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

... i voilà! Urodził się poprzedni selektor rodzeństwa (lub przynajmniej symulował).

Oto pełny kod:

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>

Ze specyfikacji Flexbox:

5.4 Kolejność wyświetlania: orderwłaściwość

Elementy Flex są domyślnie wyświetlane i rozmieszczane w tej samej kolejności, w jakiej pojawiają się w dokumencie źródłowym. orderNieruchomość może być używany, aby zmienić tę kolejność.

Te orderkontrole własności kolejności, w jakiej pojawiają się w pozycji Flex flex kontenera, poprzez przypisanie ich do grup porządkowych. Pobiera pojedynczą <integer>wartość, która określa, do której grupy porządkowej należy element flex.

Wartość początkowa orderdla wszystkich elementów elastycznych wynosi 0.

Zobacz także orderspecyfikację układu siatki CSS .


Przykłady „poprzednich selektorów rodzeństwa” utworzonych za pomocą orderwłaściwości flex .

.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


Dodatkowa uwaga - dwie przestarzałe wierzenia na temat CSS

Flexbox burzy dawne przekonania na temat CSS.

Jednym z takich przekonań jest to, że poprzedni selektor rodzeństwa nie jest możliwy w CSS .

Powiedzenie, że ta wiara jest powszechna, byłoby niedopowiedzeniem. Oto próbka powiązanych pytań dotyczących samego przepełnienia stosu:

Jak opisano powyżej, przekonanie to nie jest do końca prawdziwe. Poprzedni selektor rodzeństwa można symulować w CSS za pomocą orderwłaściwości flex .

z-indexMit

Innym wieloletnim przekonaniem jest to, że z-indexdziała tylko na pozycjonowanych elementach.

W rzeczywistości najnowsza wersja specyfikacji - wersja robocza edytora W3C - nadal potwierdza to:

9.9.1 Określanie poziomu stosu: z-index właściwość

z-index

  • Wartość: auto | | dziedziczyć
  • Inicjał: auto
  • Dotyczy: elementów pozycjonowanych
  • Dziedziczony: nie
  • Odsetki: nie dotyczy
  • Media: wizualne
  • Obliczona wartość: jak określono

(podkreślenie dodane)

W rzeczywistości jednak informacje te są przestarzałe i niedokładne.

Elementy będące elementami elastycznymi lub elementami siatki mogą tworzyć konteksty stosu, nawet jeśli positionstatic.

4.3 Flex Zamawianie pozycji Z.

Elementy Flex malują dokładnie tak samo jak bloki wbudowane, z tą różnicą, że zamiast surowego porządku dokumentów używana jest kolejność dokumentów ze zmienioną kolejnością, a z-indexwartości inne niż autotworzą kontekst stosu, nawet jeśli positionjest static.

5.4 Zamawianie w osi Z: z-indexwłaściwość

Kolejność malowania elementów siatki jest dokładnie taka sama, jak w przypadku bloków wbudowanych, z tym wyjątkiem, że zamiast surowego porządku dokumentów używana jest kolejność dokumentów ze zmienioną kolejnością, a z-indexwartości inne niż autotworzą kontekst stosu, nawet jeśli tak positionjest static.

Oto demonstracja z-indexpracy nad nie pozycjonowanymi elementami flex: https://jsfiddle.net/m0wddwxs/

Michael Benjamin
źródło
15
orderNieruchomość nie jest rozwiązaniem, ponieważ jest on przeznaczony wyłącznie do zmiany wizualne porządku, więc to nie nie przywrócić oryginalną semantyczną rozkaz, że jesteś zmuszony do zmian w HTML dla tego obejścia do pracy.
Marat Tanalin
2
@Marat Tanalin: Przy 90% przypadków użycia, przy założeniu, że obsługa przeglądarki nie stanowi problemu, będzie to działać dobrze. Pozostałe 10% przypadków użycia to albo 1) przypadki, w których zmiana kolejności wizualnej nie jest rozwiązaniem, lub 2) przypadki, które w ogóle nie wymagają CSS. Na szczęście dla # 2 selektory-4 zapewniają: has (), a ich implementacja zależy od twórców bibliotek selektorów.
BoltClock
5
Pamiętaj, że cytowany przez ciebie CSS2.2 ED to w zasadzie CSS2. A flexbox i układ siatki nie istnieją w CSS2, więc jeśli chodzi o CSS2, ta informacja z pewnością jest prawdziwa. Przynajmniej tekst mógłby zostać zaktualizowany, aby wspomnieć, że indeks Z może mieć zastosowanie do innych typów elementów w przyszłych poziomach CSS, w ten sam sposób, w jaki mówi, że inne właściwości mogą ustanowić kontekst stosowy, taki jak nieprzezroczystość.
BoltClock
3
W przypadku, gdy ktoś ma problem ze zrozumieniem, kiedy z-indexzadziała, nawet gdy „omg, nie ma positionokreślonego!”, Specyfikacja wspomina o kontekście kontekstu stosu , co jest ładnie wyjaśnione w tym artykule na temat MDN
Rogier Spieker
3
@Michael_B nie ma za co! Miałem do czynienia z wieloma front-enderami nieświadomymi tego. Jeszcze jedna rzecz, o której chciałbym wspomnieć, faux poprzedni selektor rodzeństwa również działa dobrze z float: right(lub jakimkolwiek innym sposobem odwrócenia kolejności, z których flex/orderma niewiele (najmniej?) Skutków ubocznych). Wymieszałem dwa skrzypce: demonstrując float: rightpodejście i demonstrującdirection: rtl
Rogier Spieker
69

Miałem to samo pytanie, ale potem miałem moment „duh”. Zamiast pisać

x ~ y

pisać

y ~ x

Oczywiście pasuje to do „x” zamiast „y”, ale odpowiada „czy istnieje dopasowanie?” pytanie, a proste przejście do DOM może sprawić, że trafisz do właściwego elementu bardziej efektywnie niż zapętlenie w javascript.

Zdaję sobie sprawę, że pierwotne pytanie było pytaniem CSS, więc ta odpowiedź jest prawdopodobnie zupełnie nieistotna, ale inni użytkownicy Javascript mogą natknąć się na to pytanie, tak jak ja.

Bryan Larsen
źródło
18
Wierzę, że to działa, kiedy można łatwo znaleźć. Problem polega na tym, że y można znaleźć tylko względem x, a odwracając go, nie możesz znaleźć y, ponieważ najpierw musisz znaleźć x. Odnosi się to oczywiście do pytania, czy y jest rodzeństwem, a nie następnym, ale może również dotyczyć bycia kolejnym rodzeństwem.
David
19
Jesteś trochę ostry, trudny. (przepraszam, nie mogłem się oprzeć.) Chodzi o to, że czasami trzeba tylko wiedzieć „czy istniejesz?”. Innym razem możesz użyć „: przed”, aby umieścić coś między dwoma elementami. Wreszcie, jeśli musisz wpaść do jQuery, użycie find ("y ~ x"). Prev () jest łatwiejsze niż wiele alternatyw.
Bryan Larsen
156
Idea poprzedniego selektora rodzeństwa polega na tym, że wybierze on poprzedni element. Niestety, odwrócenie go, jak opisano tutaj, nie zapewnia tej funkcji.
Zenexer
14
Dzięki @Zenexer za wyjaśnienie, że ta odpowiedź nie stanowi rzeczywistego rozwiązania pierwotnego pytania, zacząłem czuć się głupio, myśląc o tym, jak y ~ xrozwiązać mój problem
Jaime Hablutzel,
4
Rozumiem ideę tej odpowiedzi, jednak rozumowanie podane w odpowiedzi nie ma sensu. Selektor y ~ xnie odpowiada na pytanie „czy istnieje dopasowanie?” pytanie, ponieważ dwa podane tutaj selektory oznaczają zupełnie inne rzeczy. Na przykład y ~ xw poddrzewie nie ma możliwości wyprodukowania dopasowania <root><x/><y/></root>. Jeśli pytanie brzmi „czy istniejesz?” wtedy selektor jest po prostu y. Jeśli pytanie brzmi „czy istniejesz, biorąc pod uwagę rodzeństwo x w dowolnej pozycji?” wtedy potrzebujesz obu selektorów. (Chociaż może po prostu wkurzam się w tym momencie ...)
BoltClock
25

Dwie sztuczki . Zasadniczo odwracanie kolejności HTML żądanych elementów w HTML i używanie operatora
~ Next rodzeństwa :

float-right + odwrotna kolejność elementów 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>


Nadrzędny z direction: rtl;+ odwrotną kolejnością elementów wewnętrznych

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

Roko C. Buljan
źródło
25

+jest dla następnego rodzeństwa. Czy istnieje odpowiednik dla poprzedniego rodzeństwa?

Możesz użyć dwóch selektorów osi : !i?

Istnieją dwa kolejne selektory rodzeństwa w konwencjonalnym CSS:

  • +jest natychmiastowym selektorem rodzeństwa
  • ~jest dowolnym kolejnym selektorem rodzeństwa

W konwencjonalnym CSS nie ma wcześniejszego selektora rodzeństwa .

Jednak w bibliotece postprocesora ax CSS znajdują się 2 poprzednie selektory rodzeństwa :

  • ?jest bezpośrednim poprzednim selektorem rodzeństwa (przeciwnie do +)
  • !to jakikolwiek poprzedni selektor rodzeństwa (przeciwny do ~)

Przykład roboczy:

W poniższym przykładzie:

  • .any-subsequent:hover ~ div wybiera kolejne div
  • .immediate-subsequent:hover + div wybiera natychmiastowe kolejne div
  • .any-previous:hover ! div wybiera dowolne poprzednie div
  • .immediate-previous:hover ? div wybiera bezpośredni poprzedni 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>

Rounin
źródło
3
Daje mi to błąd składniowy, gdy próbuję zaimplementować go na sassie w projekcie szyn.
alex
25
ax jest postprocesorem CSS. Nie używa tej samej składni, co wstępne procesory CSS, takie jak Sass, Less lub Stylus.
Rounin
1
@Rounin czy miałbyś coś przeciwko dodaniu linków do dokumentacji? Nie mogę znaleźć topora postprocesora.
Dionys
@Dionys - Dziękujemy za zainteresowanie. ax to projekt, który rozpocząłem pod koniec 2016 roku, kiedy nie znałem ES2015, a nawet obiekty w JS były dla mnie bardzo nowe. Repozytorium GitHub znajduje się tutaj: github.com/RouninMedia/axe . Chciałbym w pewnym momencie powrócić do tego w pewnym momencie (opracowałem też coś, co nazywa się ostrzami toporów, które są odpowiednikiem zdarzeń JavaScript w CSS), ale najpierw muszę zakończyć pracę nad innym projektem (o nazwie kodowej ashiva ).
Rounin
17

Kolejne rozwiązanie typu flexbox

Możesz użyć odwrotnej kolejności elementów w HTML. Następnie oprócz używania orderjak w odpowiedzi Michael_B możesz użyć flex-direction: row-reverse;lub w flex-direction: column-reverse;zależności od układu.

Próbka robocza:

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

Vadim Ovchinnikov
źródło
16

W tej chwili nie ma oficjalnego sposobu, aby to zrobić, ale możesz to zrobić dzięki małej sztuczce! Pamiętaj, że jest eksperymentalny i ma pewne ograniczenia ... (sprawdź ten link, jeśli martwisz się kompatybilnością nawigatora)

Możesz użyć selektora CSS3: wywoływana pseudo klasa 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>

Ograniczenia

  • Nie możesz wybrać poprzednich elementów na podstawie klas następnych elementów
  • To samo dotyczy pseudoklas
0x1 gen
źródło
1
@Ian, ponieważ :nth-child(-n+4)jest to pseudo-klasa, którą należy zastosować do selektora, aby działała poprawnie. Jeśli nie jesteś przekonany, spróbuj poeksperymentować za pomocą widelca mojej skrzypce, a zobaczysz, że to nie wok
0x1gene,
1
W rzeczywistości można przejść do niezależnego od typu węzła za pomocą *selektora, ale jest to okropnie zła praktyka.
Josh Burgess,
1
To była odpowiedź, która zadziałała dla mnie, nie jestem pewien, dlaczego nie została głosowana wyżej ani zaakceptowana.
Jake Cattrall
1
W rzeczywistości działa dla różnych węzłów: jsfiddle.net/aLhv9r1w/316 . Zaktualizuj swoją odpowiedź :)
Jamie Barker
1
Miałem złożony selektor, ale powiedzmy, że tak, li#someListItemi chciałem, aby węzeł (węzły) znajdował się tuż przed nim (tak interpretuję „poprzednie”) - nie widzę, w jaki sposób podane informacje mogą pomóc mi wyrazić to za pomocą CSS. Po prostu wybierasz pierwsze n rodzeństwa i zakładam, że znam n. W oparciu o tę logikę dowolny selektor może wykonać lewę i wybrać elementy, których potrzebuję (takie jak: not ()).
bitoolean
4

Jeśli znasz dokładną pozycję :nth-child(), zadziałałoby oparte na wykluczeniu wszystkie kolejne rodzeństwo.

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

Który wybrałby wszystkie lis przed 3. (np. 1. i 2.). Ale moim zdaniem wygląda to brzydko i ma bardzo ciasną obudowę.

Możesz także wybrać n-te dziecko od prawej do lewej:

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

Co robi to samo.

jądro
źródło
3

Nie. Nie jest to możliwe za pośrednictwem CSS. „Kaskada” bierze sobie do serca ;-).


Jeśli jednak możesz dodać JavaScript do swojej strony, odrobina jQuery może doprowadzić cię do ostatecznego celu.
Możesz użyć jQuery's, findaby wykonać „spojrzenie do przodu” na docelowym elemencie / klasie / id, a następnie cofnąć się, aby wybrać swój cel.
Następnie używasz jQuery, aby ponownie napisać DOM (CSS) dla swojego elementu.

W oparciu o tę odpowiedź Mike'a Branta następujący fragment kodu jQuery może pomóc.

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

To najpierw wybiera wszystkie <ul>s, które następują bezpośrednio po <p>.
Następnie „cofa się”, aby wybrać wszystkie poprzednie <p>s z tego zestawu <ul>.

W efekcie jQuery zostało wybrane „poprzednie rodzeństwo”.
Teraz użyj .cssfunkcji, aby przekazać nowe wartości CSS dla tego elementu.


W moim przypadku szukałem sposobu, aby wybrać DIV z identyfikatorem #full-width, ale TYLKO, jeśli miał (pośrednio) potomka DIV z klasą .companies.

Miałem kontrolę nad całym HTMLem .companies, ale nie mogłem zmienić żadnego HTMLa powyżej.
Kaskada idzie tylko w jednym kierunku: w dół.

W ten sposób mogłem wybrać WSZYSTKIE #full-width.
Lub mogłem wybrać, .companiesże tylko po #full-width.
Ale mogę nie zaznaczyć tylko #full-widthy, który przystąpił .companies .

I znowu nie byłem w stanie dodać .companieswyżej w HTML. Ta część HTML została napisana zewnętrznie i otoczyła nasz kod.

Ale dzięki jQuery mogę wybrać wymagane #full-widths, a następnie przypisać odpowiedni styl:

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

Znajduje to wszystko #full-width .companiesi wybiera tylko te .companies, podobne do tego, w jaki sposób selektory są używane do kierowania określonych elementów w standardzie w CSS.
Następnie używa .parents„cofania się” i wybierania WSZYSTKICH elementów nadrzędnych .companies,
ale filtruje te wyniki, aby zachować tylko #fill-widthelementy, tak że ostatecznie
wybiera #full-widthelement tylko, jeśli ma .companiespotomek klasy.
Na koniec przypisuje nową widthwartość CSS ( ) do wynikowego elementu.

$(".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>

Dokumenty referencyjne jQuery:
$ () lub jQuery () : element DOM.
. find : pobierz potomki każdego elementu w bieżącym zestawie dopasowanych elementów, przefiltrowane przez selektor, obiekt jQuery lub element.
. rodzice : Uzyskaj bezpośrednio poprzedzające rodzeństwo każdego elementu w zestawie dopasowanych elementów. Jeśli selektor jest dostępny, pobiera poprzednie rodzeństwo tylko wtedy, gdy pasuje do tego selektora (filtruje wyniki, aby uwzględnić tylko wymienione elementy / selektory).
. css : Ustaw jedną lub więcej właściwości CSS dla zestawu dopasowanych elementów.

SherylHohman
źródło
To nie ma nic wspólnego z pytaniem. Oczywiście jest to możliwe przy użyciu JS i do tego nie potrzebujesz nawet jQuery ( previousElementSibling).
Fabian von Ellerts,
1
@FabianvonEllerts Odpowiedziałem na pytanie OP bezpośrednio w pierwszej linii mojej odpowiedzi. Jak wynika z mojej odpowiedzi, dosłownie nie jest to możliwe za pośrednictwem CSS . Następnie podałem 1 możliwą ścieżkę do osiągnięcia celu, korzystając z technologii (JS | JQuery), którą użytkownicy CSS mogą znać i mieć do niej dostęp. Na przykład wiele witryn WordPress ma również JQuery, więc jest to łatwy punkt wejścia: łatwy w użyciu, zapamiętywaniu i rozwijaniu. Byłoby nieodpowiedzialne po prostu odpowiedzieć NIE , bez zapewnienia alternatywnego sposobu osiągnięcia celu. Dzieliłem się tym, czego się nauczyłem i korzystałem, kiedy miałem to samo pytanie.
SherylHohman,
previousElementSibling()dla bardziej zaznajomionych z natywnymi funkcjami DOM JS DOM może zapewnić inną ścieżkę do przodu inną niż CSS.
SherylHohman,
Znalazłem inne HACKY CSS bardzo interesujące, ale w moim konkretnym przypadku użycia albo nie działały (należą do kategorii ostrzeżeń), albo były zbyt skomplikowane. W przypadku innych, którzy popadają w tę samą okoliczność, uczciwie jest udostępnić tę łatwą w użyciu metodę, która może zadziałać tam, gdzie powyższe rozwiązania zawodzą lub byłyby zbyt trudne do wdrożenia / utrzymania. Udostępniono wiele HACKÓW CSS. To obejście nie zostało objęte. ŻADNA z odpowiedzi nie używa +selektora (nieistniejącego), o który konkretnie poprosił PO. Rozważ tę odpowiedź jako „hack” JS. Ma na celu zaoszczędzić komuś czas, który spędziłem na znalezieniu rozwiązania.
SherylHohman,
2

Niestety nie ma „poprzedniego” selektora rodzeństwa, ale prawdopodobnie nadal możesz uzyskać ten sam efekt, używając pozycjonowania (np. Przesuń w prawo). To zależy od tego, co próbujesz zrobić.

W moim przypadku chciałem przede wszystkim 5-gwiazdkowego systemu oceny CSS. Musiałbym pokolorować (lub zamienić ikonę) poprzednich gwiazd. Po przesunięciu każdego elementu w prawo uzyskuję zasadniczo ten sam efekt (dlatego html dla gwiazd musi być napisany „wstecz”).

Używam FontAwesome w tym przykładzie i przełączam się między Unicode fa-star-o i 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/

Andrew Leyva
źródło
1
unosić się w prawo i / +lub ~selektory wydają mi się najczystsze.
Wylliam Judd
2

W zależności od dokładnego celu istnieje sposób, aby osiągnąć użyteczność selektora rodzica bez użycia jednego (nawet gdyby taki istniał) ...

Powiedzmy, że mamy:

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

Co możemy zrobić, aby blok Skarpetki (w tym kolory skarpet) wyróżniał się wizualnie za pomocą odstępów?

Co byłoby fajne, ale nie istnieje:

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

Co istnieje:

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

Powoduje to ustawienie wszystkich linków zakotwiczonych na marginesie 15 pikseli na górze i resetuje go z powrotem do 0 dla tych bez elementów UL (lub innych znaczników) wewnątrz LI.

DynamicDan
źródło
2

Potrzebowałem rozwiązania, aby wybrać poprzednie rodzeństwo tr. Wymyśliłem to rozwiązanie przy użyciu komponentów React i Styled. To nie jest moje dokładne rozwiązanie (pochodzi z pamięci, kilka godzin później). Wiem, że w funkcji setHighlighterRow występuje usterka.

OnMouseOver wiersz ustawi indeks wiersza na stan i ponownie wyśle ​​poprzedni wiersz z nowym kolorem tła

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;
    }
`;
Kyle
źródło
-1

Miałem podobny problem i odkryłem, że wszystkie problemy tego rodzaju można rozwiązać w następujący sposób:

  1. nadaj wszystkim swoim przedmiotom styl.
  2. nadaj wybranemu elementowi styl.
  3. nadaj kolejnym elementom styl za pomocą + lub ~.

i w ten sposób będziesz mógł stylizować swoje obecne, poprzednie elementy (wszystkie elementy zastąpione obecnymi i następnymi) i swoje następne.

przykład:

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

Mam nadzieję, że to komuś pomoże.

Hejar
źródło
1
jest to w zasadzie ta sama sztuczka, co w starszej odpowiedzi z tego samego wątku: stackoverflow.com/a/27993987/717732
quetzalcoatl