web-dev-qa-db-fra.com

Existe-t-il un sélecteur "précédent frère"?

Le signe plus (+) est celui du prochain frère.

Y a-t-il un équivalent pour le frère précédent?

1219
Jourkey

Non, il n'y a pas de sélecteur "précédent frère".

Sur une note connexe, ~ est destiné au frère successeur général (ce qui signifie que l'élément vient après celui-ci, mais pas nécessairement immédiatement après) et constitue un sélecteur CSS3. + est pour le prochain frère et est CSS2.1.

Voir combinateur de frères et sœurs adjacents de sélecteurs de niveau et 5.7 sélecteurs de frères et sœurs adjacents de feuilles de style en cascade de niveau 2, révision 1 (CSS 2.1) Spécification .

760
cletus

J'ai trouvé un moyen de styler tous les frères et soeurs précédents (à l'opposé de ~) qui peut fonctionner en fonction de vos besoins.

Supposons que vous avez une liste de liens et que lorsque vous passez la souris sur l'un d'entre eux, tous les liens précédents doivent devenir rouges. Vous pouvez le faire comme ça:

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

Les sélecteurs de niveau 4 introduisent :has() (auparavant l'indicateur de sujet !) qui vous permettra de sélectionner un frère précédent avec:

previous:has(+ next) {}

… Mais au moment de la rédaction de cet article, la prise en charge du navigateur dépasse de loin les limites du système.

141
Quentin

Considérez la propriété order des schémas flex et grid.

Je vais me concentrer sur flexbox dans les exemples ci-dessous, mais les mêmes concepts s'appliquent à Grid.


Avec flexbox, un sélecteur de frères précédent peut être simulé.

En particulier, la propriété flex order peut déplacer des éléments sur l'écran.

Voici un exemple:

Vous souhaitez que l'élément A devienne rouge lorsque l'élément B est survolé.

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

PAS

  1. Faites de la ul un conteneur flexible.

    _ul { display: flex; }
    _

  1. Inverser l'ordre des frères et sœurs dans la marge.

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

  1. Utilisez un sélecteur de frères et sœurs pour cibler l'élément A (_~_ ou _+_ fera l'affaire).

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

  1. Utilisez la propriété flex order pour restaurer l'ordre des frères et soeurs sur l'affichage visuel.

    _li:last-child { order: -1; }
    _

... et voilà! Un sélecteur de frères et sœurs précédent est né (ou du moins simulé).

Voici le code complet:

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

À partir de la spécification flexbox:

5.4. Ordre d'affichage: la propriété order]

Les éléments Flex sont, par défaut, affichés et agencés dans le même ordre dans lequel ils apparaissent dans le document source. La propriété order peut être utilisée pour modifier cet ordre.

La propriété order contrôle l'ordre dans lequel les éléments flex apparaissent dans le conteneur flex, en les affectant à des groupes ordinaux. Il prend une seule valeur _<integer>_, qui spécifie le groupe ordinal auquel appartient l'élément flex.

La valeur initiale de order pour tous les éléments flexibles est 0.

Voir aussi order dans la spécification CSS Grid Layout .


Exemples de "sélecteurs frères précédents" créés avec la propriété 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


Une note de côté - Deux croyances dépassées concernant les CSS

Flexbox bouleverse les croyances de longue date à propos de CSS.

Une de ces croyances est que n sélecteur précédent n'est pas possible en CSS .

Dire que cette croyance est répandue serait un euphémisme. Voici un échantillon de questions connexes sur le débordement de pile uniquement:

Comme décrit ci-dessus, cette croyance n'est pas entièrement vraie. Un sélecteur de frères précédent peut être simulé en CSS à l'aide de la propriété flex order.

Le _z-index_ Myth

Une autre croyance de longue date est que _z-index_ ne fonctionne que sur des éléments positionnés.

En fait, la version la plus récente de la spécification - le brouillon de l'éditeur du W3C - affirme encore que ceci est vrai:

9.9.1 Spécification du niveau de pile: la propriété _z-index_

z-index

  • Valeur: auto | | hériter
  • Initial: auto
  • S'applique à: éléments positionnés
  • Hérité: non
  • Pourcentages: N/A
  • Média: visuel
  • Valeur calculée: comme spécifié

(emphase ajoutée)

En réalité, ces informations sont obsolètes et inexactes.

Eléments qui sont éléments flexibles ou éléments maillés peut créer des contextes d'empilement même lorsque position est static.

[4.3. Flex Item Z-Ordering

Les éléments Flex peignent exactement de la même manière que les blocs en ligne, à la différence que l'ordre des documents modifié est utilisé à la place de l'ordre des documents bruts et que les valeurs _z-index_ autres que auto créent un contexte de pile même si position est static.

[5.4. Commande de l'axe Z: la propriété _z-index_]

L'ordre de peinture des éléments de la grille est identique à celui des blocs incorporés, à la différence que l'ordre du document modifié est utilisé à la place de l'ordre du document brut et que les valeurs _z-index_ autres que auto créent un contexte de pile même si position est static.

Voici une démonstration de _z-index_ travaillant sur des éléments flex non positionnés: https://jsfiddle.net/m0wddwxs/

134
Michael_B

J'avais la même question, mais ensuite j'ai eu un moment "duh". Au lieu d'écrire

x ~ y

écrire

y ~ x

Évidemment, cela correspond à "x" au lieu de "y", mais cela répond au "y a-t-il une correspondance?" question, et une simple traversée du DOM peut vous permettre d’obtenir le bon élément de manière plus efficace que la boucle en javascript.

Je me rends compte que la question initiale était une question CSS, donc cette réponse n’est sans doute pas tout à fait pertinente, mais d’autres utilisateurs de Javascript peuvent trébucher sur la question via une recherche, comme je l’ai fait.

67
Bryan Larsen

Deux astuces. Inverser fondamentalement l'ordre HTML des éléments souhaités en HTML et en utilisant
~frères suivants opérateur:

float-right+ inverse l'ordre des éléments 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>

Parent avec direction: rtl; + inverse l'ordre des éléments internes

.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

+ est pour le prochain frère. Y a-t-il un équivalent pour le frère précédent?

Vous pouvez utiliser les deux sélecteurs ax ax : ! et ?

Il y a 2 sélecteurs frères suivants dans CSS conventionnel:

  • + est le sélecteur de frère suivant immédiat
  • ~ est le sélecteur frère quelconque suivant

En CSS conventionnel, il y a pas de sélecteur de frère précédent.

Cependant, dans la ax bibliothèque de post-processeurs CSS, il y a 2 précédents sélecteurs frères :

  • ? est le sélecteur de frère précédent immédiat (à l'opposé de +)
  • ! est le sélecteur quelconque précédent (à l'opposé de ~)

Exemple de travail:

Dans l'exemple ci-dessous:

  • .any-subsequent:hover ~ div sélectionne toute éventuelle div
  • .immediate-subsequent:hover + div sélectionne l'immédiat suivant div
  • .any-previous:hover ! div sélectionne n'importe quel précédent div
  • .immediate-previous:hover ? div sélectionne le précédent précédent 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>
18
Rounin

Une autre solution flexbox

Vous pouvez utiliser l'inverse de l'ordre des éléments en HTML. Ensuite, en plus d'utiliser order comme dans réponse de Michael_B , vous pouvez utiliser flex-direction: row-reverse; ou flex-direction: column-reverse; en fonction de votre mise en page.

Échantillon de travail:

.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

Il n'y a pas de moyen officiel de le faire pour le moment mais vous pouvez utiliser un petit truc pour y parvenir! Rappelez-vous que c'est expérimental et qu'il a quelques limitations ... (cochez ce lien si vous vous inquiétez pour la compatibilité du navigateur)

Ce que vous pouvez faire est d'utiliser un sélecteur CSS3: la pseudo classe appelée 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>

Limites

  • Vous ne pouvez pas sélectionner les éléments précédents en fonction des classes des éléments suivants
  • C'est la même chose pour les pseudo-classes
14
0x1gene

Si vous connaissez la position exacte, une exclusion basée sur :nth-child()- de tous les frères et sœurs suivants fonctionnerait.

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

Ce qui sélectionnerait tous les lis avant la 3ème (par exemple 1ère et 2ème). Mais, à mon avis, cela semble moche et a un cas d'utilisation très serré.

Vous pouvez également sélectionner le nième enfant de droite à gauche:

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

Qui fait la même chose.

4
kernel

Malheureusement, il n’existe pas de sélecteur de frères "précédent", mais vous pouvez éventuellement obtenir le même effet en utilisant le positionnement (par exemple, float right). Cela dépend de ce que vous essayez de faire.

Dans mon cas, je voulais un système de classification 5 étoiles principalement CSS. Je devrais colorier (ou permuter l'icône des) étoiles précédentes. En flottant correctement chaque élément, j'obtiens essentiellement le même effet (le code HTML pour les étoiles doit donc être écrit "à l'envers").

J'utilise FontAwesome dans cet exemple et permute entre les unicodes de fa-star-o et de 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

En fonction de votre objectif exact, il existe un moyen de tirer parti de l'utilité d'un sélecteur parent sans en utiliser un (même s'il en existait un) ...

Disons que nous avons:

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

Que pouvons-nous faire pour que le bloc Chaussettes (y compris les couleurs des chaussettes) se démarque visuellement à l'aide de l'espacement?

Que serait Nice mais qui n'existe pas:

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

Qu'est-ce qui existe:

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

Ainsi, tous les liens d'ancrage doivent avoir une marge de 15 px et les remettre à 0 pour ceux sans éléments UL (ou autres balises) dans les LI.

1
DynamicDan

J'ai eu un problème similaire et j'ai découvert que tous les problèmes de cette nature peuvent être résolus comme suit:

  1. donnez un style à tous vos objets.
  2. donnez un style à votre article sélectionné.
  3. donnez un style aux éléments suivants en utilisant + ou ~.

de cette façon, vous pourrez styliser vos éléments actuels et précédents (tous les éléments remplacés par les éléments actuel et suivant) et vos éléments suivants.

exemple:

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

J'espère que ça aide quelqu'un.

1
Hejar

Non, ce n'est pas possible via CSS. Il prend la "cascade" à coeur ;-).


Toutefois, si vous pouvez ajouter du JavaScript à votre page, un peu de jQuery pourrait vous amener à votre objectif final.
Vous pouvez utiliser la fonction find de jQuery pour effectuer une "analyse prospective" de votre élément/classe/id cible, puis effectuer un retour arrière pour sélectionner votre cible.
Vous utilisez ensuite jQuery pour réécrire le DOM (CSS) de votre élément.

Basé sur cette réponse de Mike Brant , le fragment de code jQuery suivant pourrait aider.

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

Cette première sélectionne tous les _<ul>_ qui suivent immédiatement un _<p>_.
Ensuite, il fait un "retour en arrière" pour sélectionner tous les _<p>_ précédents de cet ensemble de _<ul>_ s.

Effectivement, "frère précédent" a été sélectionné via jQuery.
Maintenant, utilisez la fonction _.css_ pour transmettre vos nouvelles valeurs CSS à cet élément.


Dans mon cas, je cherchais un moyen de sélectionner une DIV portant l'id _#full-width_, mais UNIQUEMENT si elle possédait une DIV descendante (indirecte) avec la classe _.companies_.

J'avais le contrôle de tout le code HTML sous _.companies_, mais je ne pouvais en modifier aucun du code HTML situé au-dessus.
Et la cascade ne va que dans un sens: vers le bas.

Ainsi, je pouvais sélectionner ALL _#full-width_ s.
Ou je pourrais sélectionner _.companies_ qui ne suit qu'un _#full-width_.
Mais je pouvais ne pas sélectionner uniquement _#full-width_ s que continuait _.companies_.

Et, encore une fois, je n'ai pas pu ajouter _.companies_ plus haut dans le code HTML. Cette partie du HTML a été écrite en externe et a enveloppé notre code.

Mais avec jQuery, je peux sélectionner le _#full-width_ s requis, puis attribuer le style approprié:

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

Ceci trouve tout _#full-width .companies_ et sélectionne uniquement ces _.companies_, de la même manière que les sélecteurs sont utilisés pour cibler des éléments spécifiques dans la norme en CSS.
Ensuite, il utilise _.parents_ pour "revenir en arrière" et sélectionner TOUS les parents de _.companies_,
mais filtre ces résultats pour ne conserver que _#fill-width_ éléments, de sorte qu'à la fin,
il sélectionne uniquement un élément _#full-width_ s'il possède un descendant de classe _.companies_.
Enfin, il attribue une nouvelle valeur CSS (width) à l'élément obtenu.

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

Documents de référence jQuery:
$ () ou jQuery () : élément DOM.
. find : Obtenez les descendants de chaque élément de l'ensemble actuel d'éléments correspondants, filtrés par un sélecteur, objet jQuery ou élément.
. parents : Obtenez le frère immédiatement précédent de chaque élément de l'ensemble des éléments correspondants. Si un sélecteur est fourni, il récupère le frère précédent uniquement s'il correspond à ce sélecteur (filtre les résultats pour n'inclure que les éléments/sélecteurs répertoriés).
. css : Définissez une ou plusieurs propriétés CSS pour l'ensemble des éléments correspondants.

0
SherylHohman

J'avais besoin d'une solution pour sélectionner le tr frère précédent. J'ai trouvé cette solution en utilisant React et Styled-components. Ce n'est pas ma solution exacte (c'est de mémoire, des heures plus tard). Je sais qu'il y a une faille dans la fonction setHighlighterRow.

OnMouseOver une ligne définira l'index de la ligne à l'état et rendra la ligne précédente avec une nouvelle couleur d'arrière-plan

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