¿Hay un selector de "hermano anterior"?

1356

El signo más ( +) es para el próximo hermano.

¿Hay un equivalente para el hermano anterior?

Jourkey
fuente
18
OMG, todas las respuestas aquí sugiriendo que inviertas el orden de los elementos html y luego uses CSS para que aparezcan al revés son un verdadero estiramiento. Claro que no se especifica en la pregunta, pero la mayoría de las preguntas "¿puedes hacer X con CSS?" Deberían asumir que no puedes cambiar el HTML estructuralmente.
squarecandy
3
@squarecandy, estoy mayormente de acuerdo con tu comentario. Pero las soluciones a las que hace referencia como inadecuadas son útiles en algunos casos (observe los votos a favor). Por lo tanto, vale la pena publicarlos. Lo que ves como un "tramo real" puede ser una "solución creativa" para los demás.
Michael Benjamin

Respuestas:

839

No, no hay un selector de "hermano anterior".

En una nota relacionada, ~es para el hermano sucesor general (lo que significa que el elemento viene después de este, pero no necesariamente inmediatamente después) y es un selector CSS3. +es para el próximo hermano y es CSS2.1.

Consulte Combinador de hermanos adyacentes de los selectores Nivel 3 y 5.7 Selectores de hermanos adyacentes de la Especificación de revisión de nivel 2 de hojas de estilo en cascada 2 (CSS 2.1) .

cletus
fuente
14
Desde el estándar CSS3: Los elementos representados por las dos secuencias comparten el mismo padre en el árbol del documento y el elemento representado por la primera secuencia precede (no necesariamente inmediatamente) al elemento representado por la segunda.
Mentira Ryan
26
@Lie Ryan: Sí, pero el punto que Cletus está haciendo en su respuesta es que no seleccionas el elemento anterior.
BoltClock
42
Aquí hay un ejemplo que hice para ver lo que esto puede y no puede hacer. jsfiddle.net/NuuHy/1
Abacus
77
La función jquery útil para esto es prev (). Por ejemplo $ ("# the_element"). Prev (). Css ("background-color", "red")
Satbir Kira
1
Dependiendo de su marcado, esto podría ayudar: stackoverflow.com/questions/42680881/…
samnau
235

Encontré una forma de diseñar todos los hermanos anteriores (opuestos a ~) que pueden funcionar dependiendo de lo que necesites.

Supongamos que tiene una lista de enlaces y al pasar el mouse sobre uno, todos los anteriores deberían volverse rojos. Puedes hacerlo así:

/* 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
fuente
17
Puede agregar una explicación de cómo funciona. (parece que aplica un estilo a todos los elementos y a los siguientes elementos, pero puede describirse explícitamente)
AL
1
Impresionante solución. No es necesario reordenar los elementos en marcado ni en render (vía float:right). Sí requirió un colapso de espacio en blanco entre unidades / palabras y relleno en lugar de márgenes, ¡pero funciona perfectamente de lo contrario!
Steven Vachon
77
sí, pero la mayoría de las veces se necesita un solo anterior ¡NO TODOS los anteriores!
azerafati
42
Todos los enlaces se vuelven rojos si me desplazo sobre el espacio entre ellos, para mí.
Lynn
3
@Lynn la respuesta solo incluye el código para hacer que los enlaces anteriores se vuelvan rojos al pasar el mouse. Los estilos adicionales dependen de su caso de uso. Para un componente de calificación de estrellas (que supongo que es un caso común), necesitaría deshacerse de ese espacio y también hacer rojo el enlace suspendido.
Mantish
164

Se presenta el selector de nivel 4:has() (anteriormente el indicador de sujeto !) que le permitirá seleccionar un hermano anterior con:

previous:has(+ next) {}

... pero al momento de escribir, está a cierta distancia más allá del límite de la compatibilidad con el navegador.

Quentin
fuente
52
"Borde sangrante para el soporte del navegador" podría ser una exageración. Al momento de escribir esto, ni siquiera la última versión de Chrome puede usar la :has()pseudoclase.
Reed Martin
33
@ReedMartin - Es por eso que dije un poco más allá del límite sangriento
Quentin
12
": has no está marcado como parte del perfil del selector dinámico, lo que significa que no se puede usar dentro de las hojas de estilo; solo con funciones como document.querySelector ()". - developer.mozilla.org/en-US/docs/Web/CSS/:has
Arch Linux Tux
1
@ArchLinuxTux: "Esta limitación ahora se elimina", por lo que alguna vez podremos usar esta función: D.
Jacob van Lingen
@JacobvanLingen - caniuse.com/#feat=css-has - Ningún navegador lo admite actualmente.
Quentin
153

Considere la orderpropiedad de los diseños flex y grid.

Me centraré en flexbox en los ejemplos a continuación, pero los mismos conceptos se aplican a Grid.


Con flexbox, se puede simular un selector de hermanos anterior.

En particular, la orderpropiedad flex puede mover elementos alrededor de la pantalla.

Aquí hay un ejemplo:

Desea que el elemento A se ponga rojo cuando el elemento B está suspendido.

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

PASOS

  1. Haz ulun contenedor flexible.

    ul { display: flex; }

  1. Invierta el orden de los hermanos en el marcado.

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

  1. Use un selector de hermanos para seleccionar el Elemento A ( ~o +lo hará).

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

  1. Use la orderpropiedad flex para restaurar el orden de los hermanos en la pantalla visual.

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

...¡y voilá! Nace un selector de hermanos anterior (o al menos simulado).

Aquí está el código completo:

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>

De la especificación flexbox:

5.4. Orden de visualización: la orderpropiedad

Los elementos flexibles se muestran y presentan de forma predeterminada en el mismo orden en que aparecen en el documento fuente. La orderpropiedad se puede usar para cambiar este orden.

La orderpropiedad controla el orden en que aparecen los elementos flexibles dentro del contenedor flexible, asignándolos a grupos ordinales. Toma un solo <integer>valor, que especifica a qué grupo ordinal pertenece el elemento flexible.

El ordervalor inicial para todos los elementos flexibles es 0.

Ver también orderen la especificación de diseño de cuadrícula CSS .


Ejemplos de "selectores hermanos anteriores" creados con la orderpropiedad 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


Una nota al margen - Dos creencias obsoletas sobre CSS

Flexbox está destruyendo creencias arraigadas sobre CSS.

Una de esas creencias es que un selector de hermano anterior no es posible en CSS .

Decir que esta creencia es generalizada sería un eufemismo. Aquí hay una muestra de preguntas relacionadas con Stack Overflow solo:

Como se describió anteriormente, esta creencia no es del todo cierta. Un selector de hermanos anterior se puede simular en CSS utilizando la orderpropiedad flex .

El z-indexmito

Otra creencia de larga data ha sido que z-indexsolo funciona en elementos posicionados.

De hecho, la versión más actual de la especificación, el Borrador del Editor del W3C , aún afirma que esto es cierto:

9.9.1 Especificar el nivel de pila: la z-index propiedad

z-index

  • Valor: auto | El | heredar
  • Inicial: auto
  • Se aplica a: elementos posicionados
  • Heredado: no
  • Porcentajes: N / A
  • Medios: visual
  • Valor calculado: como se especifica

(énfasis añadido)

En realidad, sin embargo, esta información es obsoleta e inexacta.

Los elementos que son elementos flexibles o elementos de cuadrícula pueden crear contextos de apilamiento incluso cuando positiones así static.

4.3. Artículo Flex Z-Ordering

Los elementos flexibles pintan exactamente igual que los bloques en línea, excepto que el orden del documento modificado se usa en lugar del orden del documento sin procesar y los z-indexvalores que no sean autocrear un contexto de apilamiento, incluso si positiones así static.

5.4. Ordenamiento del eje Z: la z-indexpropiedad

El orden de pintura de los elementos de la cuadrícula es exactamente el mismo que el de los bloques en línea, excepto que el orden del documento modificado se usa en lugar del orden del documento sin procesar y los z-indexvalores que no sean autocrear un contexto de apilamiento, incluso si positiones así static.

Aquí hay una demostración de cómo z-indextrabajar en elementos flexibles no posicionados: https://jsfiddle.net/m0wddwxs/

Michael Benjamin
fuente
15
La orderpropiedad no es una solución, ya que está destinada únicamente a cambiar el orden visual , por lo que no restaura el orden semántico original que se ve obligado a cambiar en HTML para que funcione esta solución alternativa.
Marat Tanalin
2
@Marat Tanalin: para el 90% de los casos de uso, suponiendo que el soporte del navegador no sea un problema, esto funcionará bien. El 10% restante de los casos de uso son 1) casos en los que cambiar el orden visual no es una solución, o 2) casos que no involucran CSS en absoluto. Afortunadamente, para el n. ° 2, selectors-4 proporciona: has (), y los desarrolladores de bibliotecas selectoras simplemente deben implementarlo.
BoltClock
55
Tenga en cuenta que el ED CSS2.2 que está citando es, en esencia, todavía CSS2. Y el diseño de cuadrícula y flexbox no existe en CSS2, por lo que en lo que respecta a CSS2, esa información ciertamente es cierta. Como mínimo, el texto podría actualizarse para mencionar que el índice z puede aplicarse a otros tipos de elementos en niveles futuros de CSS, de la misma manera que dice que otras propiedades pueden establecer un contexto de apilamiento, como la opacidad.
BoltClock
3
En caso de que alguien tenga problemas para entender cuándo z-indexfuncionará, incluso cuando "¡Dios mío, no se positionespecifica!", La especificación menciona el concepto de contexto de apilamiento , que se explica muy bien en este artículo sobre MDN
Rogier Spieker
3
@Michael_B de nada! He tratado con muchos candidatos que no saben esto. Otra cosa que me gustaría mencionar, el falso selector de hermano anterior también funciona bien con float: right(o cualquier otro medio para revertir el orden, de los cuales flex/ordertiene pocos (¿menos?) Efectos secundarios). Batió dos violines: demostrando el float: rightenfoque y demostrandodirection: rtl
Rogier Spieker
69

Tenía la misma pregunta, pero luego tuve un "duh" momento. En lugar de escribir

x ~ y

escribir

y ~ x

Obviamente, esto coincide con "x" en lugar de "y", pero responde "¿hay una coincidencia?" pregunta, y el simple recorrido del DOM puede llevarlo al elemento correcto de manera más eficiente que hacer un bucle en JavaScript.

Me doy cuenta de que la pregunta original era una pregunta de CSS, por lo que esta respuesta probablemente sea completamente irrelevante, pero otros usuarios de Javascript pueden tropezar con la pregunta a través de la búsqueda como lo hice yo.

Bryan Larsen
fuente
18
Creo que funciona cuando y se puede encontrar fácilmente. El problema es si y solo se puede encontrar en relación con x, y al revertirlo, no puede encontrar y porque primero tiene que encontrar x. Por supuesto, esto se refiere a la cuestión de y ser hermano anterior en lugar de siguiente, pero también puede aplicarse para y ser un hermano siguiente.
David
19
Estás siendo un poco duro, duro. (lo siento, no pude resistir). El punto es que a veces solo necesitas saber "¿existes?". Otras veces puedes usar ": before" para poner algo entre los dos elementos. Finalmente, si tiene que ingresar a jQuery, usar find ("y ~ x"). Prev () es más fácil que muchas alternativas.
Bryan Larsen
157
La idea de un selector hermano anterior es que seleccionará el elemento anterior. Desafortunadamente, invertirlo, como se describe aquí, no proporciona esta funcionalidad.
Zenexer
14
Gracias @Zenexer por la aclaración de que esta respuesta no proporciona una solución real a la pregunta original, estaba empezando a sentirme estúpido pensando en cómo y ~ xpodría resolver mi problema
Jaime Hablutzel
44
Entiendo la idea detrás de esta respuesta, sin embargo, el razonamiento dado en la respuesta no tiene mucho sentido. El selector y ~ xno responde "¿hay una coincidencia?" pregunta, porque los dos selectores dados aquí significan cosas completamente diferentes. No hay forma de que y ~ xpueda producir una coincidencia dado el subárbol, <root><x/><y/></root>por ejemplo. Si la pregunta es "¿existe y?" entonces el selector es simplemente y. Si la pregunta es "¿existe y dado un hermano x en alguna posición arbitraria?" entonces necesitarías ambos selectores. (Aunque tal vez solo estoy
haciendo trampas
25

Dos trucos . Básicamente, invierte el orden HTML de tus elementos deseados en HTML y usa el operador
~ Hermanos siguientes :

float-right + invertir el orden de los elementos 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>


Padre con direction: rtl;+ invertir el orden de los elementos internos

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

+es para el próximo hermano. ¿Hay un equivalente para el hermano anterior?

Puede usar los dos selectores de hacha : !y?

Hay 2 selectores hermanos posteriores en CSS convencional:

  • +es el selector de hermano posterior inmediato
  • ~es la de cualquier selector de hermanos subsecuente

En CSS convencional, no hay un selector de hermanos anterior .

Sin embargo, en la biblioteca de postprocesador CSS de ax , hay 2 selectores hermanos anteriores :

  • ?es el selector de hermano anterior inmediato (opuesto a +)
  • !es el cualquier selector hermano anterior (opuesto ~)

Ejemplo de trabajo

En el siguiente ejemplo:

  • .any-subsequent:hover ~ div selecciona cualquier posterior div
  • .immediate-subsequent:hover + div selecciona el subsiguiente inmediato div
  • .any-previous:hover ! div selecciona cualquier anterior div
  • .immediate-previous:hover ? div selecciona el previo inmediato 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
fuente
3
Esto me da un error de sintaxis cuando intento implementarlo en sass dentro de un proyecto rails.
alex
25
ax es un postprocesador CSS. No utiliza la misma sintaxis que los preprocesadores CSS como Sass, Less o Stylus.
Rounin
1
@Rounin, ¿te importaría agregar algunos enlaces de documentación? No puedo encontrar el procesador posterior del hacha .
Dionys
@Dionys - Gracias por su interés. ax es un proyecto que comencé a fines de 2016, cuando no conocía ES2015 e incluso los objetos en JS eran muy nuevos para mí. El repositorio de GitHub está aquí: github.com/RouninMedia/axe . Me refiero a volver a esto en algún momento (también he desarrollado algo llamado ax-blades, que son el equivalente CSS de los eventos de JavaScript), pero primero necesito completar mi trabajo en otro proyecto (con nombre en código ashiva ).
Rounin
17

Otra solución flexbox

Puede usar el orden inverso de los elementos en HTML. Luego, además de usar ordercomo en la respuesta de Michael_B, puede usar flex-direction: row-reverse;o flex-direction: column-reverse;según su diseño.

Muestra de trabajo:

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

No hay una forma oficial de hacerlo en este momento, ¡pero puedes usar un pequeño truco para lograrlo! Recuerde que es experimental y tiene algunas limitaciones ... (consulte este enlace si le preocupa la compatibilidad del navegador)

Lo que puedes hacer es usar un selector CSS3: la pseudoclase llamada 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>

Limitaciones

  • No puede seleccionar elementos anteriores en función de las clases de los siguientes elementos.
  • Esto es lo mismo para las pseudo clases
0x1gene
fuente
1
@Ian porque :nth-child(-n+4)es una pseudo clase que debe aplicarse a un selector para que funcione correctamente. Si no está convencido, intente experimentarlo con un tenedor de mi violín y verá que no funciona
0x1gene
1
En realidad, puede ser independiente del tipo de nodo usando el *selector, pero es una práctica desagradable.
Josh Burgess
1
Esta es la respuesta que funcionó para mí, no estoy seguro de por qué no se votó más alto o aceptado.
Jake Cattrall el
1
En realidad, funciona para diferentes nodos: jsfiddle.net/aLhv9r1w/316 . Actualice su respuesta :)
Jamie Barker
1
Tenía un selector complejo, pero digamos que es li#someListItemy quería los nodos justo antes (que es como interpreto "anterior"). No veo cómo la información que proporcionó puede ayudarme a expresar eso a través de CSS. Solo estás seleccionando los primeros n hermanos, y supones que sé el n. Según esta lógica, cualquier selector puede hacer el truco y seleccionar los elementos que necesito (como: not ()).
bitooleano
4

Si conoce la posición exacta, funcionaría una :nth-child()exclusión basada en todos los siguientes hermanos.

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

Que seleccionaría todas las lis antes de la 3ra (por ejemplo, 1ra y 2da). Pero, en mi opinión, esto se ve feo y tiene un caso de uso muy estricto.

También puede seleccionar el enésimo hijo de derecha a izquierda:

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

Que hace lo mismo.

núcleo
fuente
3

No. No es posible a través de CSS. Lleva la "Cascada" al corazón ;-).


Sin embargo, si puede agregar JavaScript a su página, un poco de jQuery podría llevarlo a su objetivo final.
Puede usar jQuery's findpara realizar una "anticipación" en su elemento / clase / id de destino, luego retroceder para seleccionar su objetivo.
Luego usa jQuery para reescribir el DOM (CSS) para su elemento.

Según esta respuesta de Mike Brant , el siguiente fragmento de jQuery podría ayudar.

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

Esto primero selecciona todos los correos <ul>electrónicos que siguen inmediatamente a <p>.
Luego "retrocede" para seleccionar todos los <p>s anteriores de ese conjunto de <ul>s.

Efectivamente, se ha seleccionado "hermano anterior" a través de jQuery.
Ahora, use la .cssfunción para pasar sus nuevos valores CSS para ese elemento.


En mi caso, estaba buscando encontrar una manera de seleccionar un DIV con la identificación #full-width, pero SOLO si tenía un DIV descendiente (indirecto) con la clase de .companies.

Tenía el control de todo el HTML debajo .companies, pero no pude alterar ninguno de los HTML anteriores.
Y la cascada solo va en 1 dirección: hacia abajo.

Por lo tanto, podría seleccionar TODOS #full-widths.
O podría seleccionar .companiesque solo siguiera a #full-width.
Pero podría no seleccionar sólo #full-widthde que procedieron .companies .

Y, de nuevo, no pude agregar .companiesmás arriba en el HTML. Esa parte del HTML se escribió externamente y envolvió nuestro código.

Pero con jQuery, puedo seleccionar los #full-widths requeridos y luego asignar el estilo apropiado:

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

Esto encuentra todo #full-width .companiesy selecciona solo esos .companies, de forma similar a cómo se usan los selectores para apuntar a elementos específicos en estándar en CSS.
Luego se usa .parentspara "retroceder" y seleccionar TODOS los padres de .companies,
pero filtra esos resultados para mantener solo #fill-widthelementos, de modo que al final,
solo selecciona un #full-widthelemento si tiene un .companiesdescendiente de clase.
Finalmente, asigna un nuevo widthvalor CSS ( ) al elemento resultante.

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

Documentos de referencia de jQuery:
$ () o jQuery () : elemento DOM.
. find : obtiene los descendientes de cada elemento en el conjunto actual de elementos coincidentes, filtrados por un selector, un objeto jQuery o un elemento.
. padres : Obtenga el hermano inmediatamente anterior de cada elemento en el conjunto de elementos coincidentes. Si se proporciona un selector, recupera el hermano anterior solo si coincide con ese selector (filtra los resultados para incluir solo los elementos / selectores enumerados).
. css : establece una o más propiedades CSS para el conjunto de elementos coincidentes.

SherylHohman
fuente
Esto no tiene nada que ver con la pregunta. Por supuesto, es posible usar JS y ni siquiera necesita jQuery para esto ( previousElementSibling).
Fabian von Ellerts
1
@FabianvonEllerts Respondí la pregunta de OP directamente en la primera línea de mi respuesta. Como dice mi respuesta, literalmente no es posible a través de CSS . Luego proporcioné 1 posible camino hacia adelante para lograr el objetivo, utilizando una tecnología (JS | JQuery) con la que los usuarios de CSS podrían estar familiarizados y tener acceso. Por ejemplo, muchos sitios de WordPress también tienen JQuery, por lo que es un punto de entrada fácil: fácil de usar, recordar y ampliar. Sería irresponsable simplemente responder NO , sin proporcionar una forma alternativa de lograr el objetivo. Compartí lo que aprendí y usé cuando tenía la misma pregunta.
SherylHohman
previousElementSibling()para aquellos más familiarizados con las funciones nativas de JS DOM podrían proporcionar otra ruta hacia adelante que no sea CSS.
SherylHohman
Los otros CSS HACKS me parecieron muy interesantes, pero para mi caso de uso en particular no funcionaron (cayeron en la categoría de advertencias) o fueron demasiado complicados. Para otros que caen en la misma circunstancia, es justo compartir este método fácil de usar que puede funcionar, donde las soluciones anteriores fallan o serían demasiado difíciles de implementar / mantener. Se compartieron muchos HACKS CSS. Este trabajo no estaba cubierto. Ninguna de las respuestas usa el +selector (inexistente) que el OP solicitó específicamente. Considera esta respuesta como un "hack" de JS. Está aquí para ahorrarle a alguien el tiempo que pasé para encontrar una solución.
SherylHohman
2

No hay ningún selector "anterior" hermanos por desgracia, pero se puede , posiblemente, aún así obtener el mismo efecto mediante el uso de posicionamiento (por ejemplo el derecho de flotación). Depende de lo que estés tratando de hacer.

En mi caso, quería un sistema de calificación de 5 estrellas CSS principalmente. Necesitaría colorear (o intercambiar el ícono) de las estrellas anteriores. Al flotar cada elemento a la derecha, esencialmente obtengo el mismo efecto (por lo tanto, el html para las estrellas debe escribirse 'al revés').

Estoy usando FontAwesome en este ejemplo y cambio entre los unicodes de fa-star-o y 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
fuente
1
floto hacia la derecha y / +o los ~selectores me parecen el trabajo más limpio.
Wylliam Judd
2

Dependiendo de su objetivo exacto, hay una manera de lograr la utilidad de un selector principal sin usar uno (incluso si existiera uno) ...

Digamos que tenemos:

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

¿Qué podemos hacer para que el bloque Socks (incluidos los colores de los calcetines) se destaque visualmente usando el espaciado?

Lo que sería bueno pero no existe:

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

¿Qué existe?

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

Esto establece que todos los enlaces de anclaje tengan un margen de 15 píxeles en la parte superior y lo restablece a 0 para aquellos sin elementos UL (u otras etiquetas) dentro de las LI.

DynamicDan
fuente
2

Necesitaba una solución para seleccionar el hermano anterior tr. Se me ocurrió esta solución usando React y Styled-components. Esta no es mi solución exacta (esto es de memoria, horas después). Sé que hay una falla en la función setHighlighterRow.

OnMouseOver una fila establecerá el índice de fila en estado y volverá a procesar la fila anterior con un nuevo color de fondo

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

No hay y hay .

Si debe colocar la etiqueta antes de la entrada, en su lugar, coloque la etiqueta después de la entrada, mantenga la etiqueta y la entrada dentro de un div, y estilice el div de la siguiente manera:

.input-box {
  display: flex;
  flex-direction: column-reverse;
}
<div class="input-box">
                <input
                  id="email"
                  class="form-item"
                 
                />
                <label for="email" class="form-item-header">                  
                      E-Mail*                  
                </label>
</div>

Ahora puede aplicar las siguientes opciones de estilo estándar para hermanos disponibles en css, y parecerá que está utilizando un estilo de hermano anterior.

Ron16
fuente
-1

Tuve un problema similar y descubrí que todos los problemas de esta naturaleza se pueden resolver de la siguiente manera:

  1. Dale un estilo a todos tus artículos.
  2. Dale un estilo a tu artículo seleccionado.
  3. Dale un estilo a los siguientes elementos usando + o ~.

y de esta manera podrá diseñar sus elementos anteriores actuales (todos los elementos anulados con los elementos actuales y siguientes) y sus elementos siguientes.

ejemplo:

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

Espero que ayude a alguien.

Hejar
fuente
1
es básicamente el mismo truco que en una respuesta anterior del mismo hilo: stackoverflow.com/a/27993987/717732
quetzalcoatl