8. Scope
Un selector normal sabe decir dónde empieza a aplicarse un estilo, pero no dónde termina. Escribes .tarjeta p y ese color cae sobre todos los párrafos que cuelguen de la tarjeta, estén donde estén, por muy abajo que se hayan metido. ¿Y si quieres pintar solo una parte del árbol y dejar el resto tranquilo?
Para eso está @scope. Sirve para decir "estas reglas solo se aplican aquí dentro", acotando una región del documento con un techo y, si quieres, también con un suelo.
La forma básica
La versión mínima es esta:
@scope (.tarjeta) {
p {
color: #444;
}
}
Traducido: los párrafos que estén dentro de un .tarjeta se pintan de gris. Hasta aquí lo mismo que un .tarjeta p { color: #444; } de toda la vida.
<div class="tarjeta">
<p>Estoy dentro de la tarjeta, así que salgo en gris.</p>
</div>
<p>Estoy fuera, a mí no me toca.</p>
Estoy dentro de la tarjeta, así que salgo en gris.
Estoy fuera, a mí no me toca.
Menos especificidad, más fácil de sobrescribir
Hay una ventaja pequeña pero cómoda. La especificidad de la regla es la del selector interno (p), no la suma del selector externo más el interno. Con @scope el .tarjeta de la cabecera no suma peso, así que sobrescribir ese estilo después te cuesta menos:
@scope (.tarjeta) {
p {
color: #444;
}
}
/* Basta una clase para ganar, no hace falta pelear con la especificidad */
.destacado {
color: crimson;
}
El donut: poner también un suelo
Aquí está lo interesante. Además del techo puedes marcar un límite inferior con la palabra to:
@scope (.tarjeta) to (.tarjeta__pie) {
p {
color: #444;
}
}
Ahora las reglas empiezan en .tarjeta y se detienen al llegar a .tarjeta__pie. Míralo en el árbol:
.tarjeta ← empieza
├── <p> ✅ gris
├── <p> ✅ gris
│
└── .tarjeta__pie ← se detiene
├── <p> ❌ nada
└── <p> ❌ nada
Es una rosquilla: hay masa alrededor y un agujero en medio. Por eso se le llama donut scope, y por eso es la parte que de verdad importa. Un selector normal solo sabe decir dónde empieza. @scope sabe decir también dónde termina.
<div class="tarjeta">
<p>Cuerpo de la tarjeta, en gris.</p>
<p>Otra línea del cuerpo, también en gris.</p>
<div class="tarjeta__pie">
<p>El pie queda fuera del agujero, no cambia.</p>
</div>
</div>
Cuerpo de la tarjeta, en gris.
Otra línea del cuerpo, también en gris.
El pie queda fuera del agujero, no cambia.
Esto resuelve un dolor clásico. Piensa en un bloque de contenido con tarjetas anidadas, o en un editor de texto que renderiza HTML de terceros: quieres dar estilo al contenido, pero sin que se cuele dentro de los componentes que viven ahí metidos. El suelo del donut es justo eso.
:scope, el elemento raíz
Dentro del bloque, la palabra :scope apunta al propio elemento que abre el alcance, es decir, al .tarjeta de la cabecera. Sirve para dar estilo a la raíz además de a lo que hay dentro:
@scope (.tarjeta) {
:scope {
border: 1px solid #ccc;
border-radius: .5rem;
}
p {
margin: 0;
}
}
También puedes usar & para referirte a esa raíz al construir selectores, igual que en la anidación normal.
La cercanía desempata
Este es el truco que no tiene ningún selector clásico. Cuando dos reglas con la misma especificidad intentan pintar el mismo elemento, @scope da la victoria a la que tenga su raíz más cerca en el árbol. Se llama scope proximity.
Imagina un tema claro y otro oscuro anidados:
@scope (.claro) {
p {
color: #222;
}
}
@scope (.oscuro) {
p {
color: #eee;
}
}
<div class="claro">
<p>Texto sobre fondo claro.</p>
<div class="oscuro">
<p>Aquí gana el .oscuro, que es la raíz más cercana.</p>
</div>
</div>
Texto sobre fondo claro.
Aquí gana el .oscuro, que es la raíz más cercana.
El párrafo de dentro cumple las dos reglas, porque vive a la vez dentro de .claro y de .oscuro. Las dos tienen la misma especificidad (p a secas), así que el desempate lo decide la proximidad: gana .oscuro por estar más cerca. Sin @scope tendrías que recurrir a selectores más rebuscados para lograr lo mismo.
No sustituyas todas tus reglas por @scope. Su gran baza es el suelo del donut: acotar una región sin que el estilo se cuele en los componentes de dentro. Para el resto, un selector normal sigue siendo más corto y más claro.
Actividad 1
Crea un .aviso con varios párrafos dentro. Usando @scope, pinta de rojo solo los párrafos que estén dentro del aviso y comprueba que un párrafo colocado fuera no cambia de color.
Actividad 2
Construye una .tarjeta con un cuerpo y un .tarjeta__pie. Aplica un donut scope con @scope (.tarjeta) to (.tarjeta__pie) para dar color al cuerpo y verifica que los párrafos del pie se quedan sin estilo.
Este trabajo está bajo una licencia Attribution-NonCommercial-NoDerivatives 4.0 International.
Desafíos de programación atemporales y multiparadigmáticos
Te encuentras ante un librillo de actividades, divididas en 2 niveles de dificultad. Te enfrentarás a los casos más comunes que te puedes encontrar en pruebas técnicas o aprender conceptos elementales de programación.
Comprar el libroAyúdame a seguir escribiendo
Cada café me da un empujón para escribir el siguiente artículo.
¡Claro, te invito!
Comentarios
Todavía no hay ningún comentario.