CSS :has()
pseudo clase se distribuye en muchos navegadores con Cromo y Safari ya lo apoya totalmente. A menudo se le llama "selector principal", ya que podemos seleccionar el estilo de un elemento principal de un selector secundario, pero hay mucho más, :has()
puede ayudarnos a decidir. Una de esas cosas es reinventar el modelo de mapa en el que se puede hacer clic que a muchos de nosotros nos gusta usar de vez en cuando.
Veremos cómo :has()
puede ayudarnos a procesar mapas vinculados, pero primero...
¿qué es esto? :has()
pseudoclase?
ya hay un un manojo en estupendo publicaciones flotando alrededor que hacen un excelente trabajo explicando lo que :has()
es y para qué se usa, pero todavía es lo suficientemente nuevo como para decir algunas palabras al respecto aquí también.
:has()
es una pseudoclase relacional que forma parte de Borrador de trabajo de nivel 4 de selectores W3CPara eso están los paréntesis: elementos coincidentes que están relacionados con, o, más precisamente, contienen, ciertos elementos secundarios.
/* Matches an article element that contains an image element */
article:has(img) { }
/* Matches an article element with an image contained immediately within it */
article:has(> img) { }
Entonces puede ver por qué podemos llamarlo un selector "principal". Pero también podemos combinarlo con otras pseudoclases funcionales para ser más específicos. Digamos que queremos diseñar artículos que no contiene cualquier imagen. Podemos combinar las fuerzas relacionales de :has()
con el grado de negación de :not()
para hacer esto:
/* Matches an article without images */
article:has(:not(img)) { }
Pero esto es solo el comienzo de cómo podemos combinar fuerzas para hacer más. :has()
Antes de comenzar a resolver específicamente el enigma de los mapas en los que se puede hacer clic, veamos algunas formas en que actualmente los abordamos sin usar :has()
.
Cómo manejamos actualmente las tarjetas de clic
Hay tres enfoques principales sobre cómo las personas crean un mapa en el que se puede hacer clic en estos días, y para comprender completamente el poder de esta pseudoclase, es bueno tener un poco de descripción general.
El enfoque de "Conexión como Shell".
Este enfoque se utiliza con bastante frecuencia. Nunca uso este enfoque, pero creé una demostración rápida para demostrarlo:
Hay muchas preocupaciones aquí, especialmente cuando se trata de accesibilidad. Cuando los usuarios navegan por su sitio web usando función del rotorescucharán el texto completo dentro <a>
elemento: el título, el texto y el enlace. Uno puede no querer investigar todo esto. Podemos hacerlo mejor. Desde HTML5 podemos insertar elementos de bloque dentro del <a>
Pero nunca se siente bien, especialmente por esa razón.
Profesionales:
- Rápido de ejecutar
- semánticamente correcto
Contras:
- Problemas de accesibilidad
- No se puede seleccionar el texto
- Muchas molestias para sobrescribir los estilos que usó en sus enlaces predeterminados
El método JavaScript
Usando JavaScript, podemos adjuntar un enlace a nuestro mapa en lugar de escribirlo en el marcado. Encontré esta gran demostración de CodePen de costodesv lo que también hizo que el texto del mapa se pudiera seleccionar en el proceso:
Este enfoque tiene muchas ventajas. Nuestros enlaces están disponibles en foco e incluso podemos seleccionar texto. Pero hay algunos inconvenientes cuando se trata de estilo. Si queremos animar estas tarjetas por ejemplo, necesitaremos agregar :hover
estilos de nuestro principal .card
envoltorio en lugar del enlace mismo Tampoco nos beneficiaríamos de las animaciones cuando los enlaces están enfocados desde la pestaña del teclado.
Profesionales:
- Se puede hacer perfectamente accesible.
- Posibilidad de seleccionar texto
Contras:
- Requiere JavaScript
- No es posible hacer clic derecho (aunque se puede arreglar con algunos scripts adicionales)
- Requeriría mucho estilo del mapa en sí, lo que no funcionaría al enfocarse en el enlace
los ::after
enfoque selector
Este método requiere que configuremos el mapa con posicionamiento relativo, luego establezcamos el posicionamiento absoluto del enlace ::after
selector de pseudo conexión. Esto no requiere JavaScript y es bastante fácil de implementar:
Aquí hay algunas desventajas, especialmente cuando se trata de la selección de texto. A menos que proporcione un índice z más alto para el cuerpo de su mapa, no podrá seleccionar texto, pero si lo hace, tenga en cuenta que hacer clic en el texto no activará su enlace. Depende de usted si desea texto seleccionable. Creo que esto podría ser un problema de UX, pero depende del caso. El texto aún es accesible para los lectores de pantalla, pero mi principal problema con el método es la falta de capacidades de animación.
Profesionales:
- Fácil de realizar
- Enlace accesible sin texto inflado
- Funciona en espera y enfoque
Contras:
- No se puede seleccionar el texto
- Solo puede animar el enlace ya que es el elemento que está sosteniendo.
Un nuevo enfoque: usar ::after
con :has()
Ahora que hemos establecido los enfoques existentes para los mapas en los que se puede hacer clic, Quiero mostrar cómo escribimos :has()
a la mezcla soluciona la mayor parte de estos inconvenientes.
En realidad, vamos a basar este enfoque en el último que vimos ::after
del elemento de enlace. De hecho, podemos usar :has()
allí para superar las limitaciones de animación de este enfoque.
Comencemos con el marcado:
<div class="card">
<img src="https://css-tricks.com/creating-animated-clickable-cards-with-the-has-relational-pseudo-class/cat.webp" alt="Fluffy gray and white tabby kitten snuggled up in a ball." />
<div clas="article-body">
<h2>Some Heading</h2>
<p>Curabitur convallis ac quam vitae laoreet. Nulla mauris ante, euismod sed lacus sit amet, congue bibendum eros. Etiam mattis lobortis porta. Vestibulum ultrices iaculis enim imperdiet egestas.</p>
</div>
</div>
Mantendré las cosas lo más simples posible apuntando a elementos CSS en lugar de clases.
Para esta demostración, agregaremos escala de imagen y una sombra paralela al mapa en espera y animaremos el enlace con una flecha emergente y cambiaremos el color del texto del enlace. Para hacerlo más fácil, agregaremos algunas propiedades personalizadas cubiertas por nuestro mapa. Aquí está el estilo básico:
/* The card element */
article {
--img-scale: 1.001;
--title-color: black;
--link-icon-translate: -20px;
--link-icon-opacity: 0;
position: relative;
border-radius: 16px;
box-shadow: none;
background: #fff;
transform-origin: center;
transition: all 0.4s ease-in-out;
overflow: hidden;
}
/* The link's ::after pseudo */
article a::after {
content: "";
position: absolute;
inset-block: 0;
inset-inline: 0;
cursor: pointer;
}
¡Impresionante! Agregamos una escala inicial para la imagen (--img-scale: 1.001
), el color inicial del título de la carta (--title-color: black
) y algunas propiedades adicionales que usaremos para hacer que nuestra flecha salga del enlace. También hemos establecido un estado vacío para box-shadow
declaración para animarlo más tarde Esto configura lo que necesitamos para el mapa en el que se puede hacer clic en este momento, así que vamos a agregarle un poco de reinicio y estilo agregando estas propiedades personalizadas a los elementos que queremos animar:
article h2 {
margin: 0 0 18px 0;
font-family: "Bebas Neue", cursive;
font-size: 1.9rem;
letter-spacing: 0.06em;
color: var(--title-color);
transition: color 0.3s ease-out;
}
article figure {
margin: 0;
padding: 0;
aspect-ratio: 16 / 9;
overflow: hidden;
}
article img {
max-width: 100%;
transform-origin: center;
transform: scale(var(--img-scale));
transition: transform 0.4s ease-in-out;
}
article a {
display: inline-flex;
align-items: center;
text-decoration: none;
color: #28666e;
}
article a:focus {
outline: 1px dotted #28666e;
}
article a .icon {
min-width: 24px;
width: 24px;
height: 24px;
margin-left: 5px;
transform: translateX(var(--link-icon-translate));
opacity: var(--link-icon-opacity);
transition: all 0.3s;
}
.article-body {
padding: 24px;
}
Seamos amables con la gente y también agreguemos una clase de lector de pantalla oculta detrás del enlace:
.sr-only:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
Nuestra tarjeta está empezando a verse muy linda. Es hora de agregarle algo de magia. S :has()
pseudo clase, ahora podemos verificar si nuestra conexión está retenida o enfocada, luego actualizar nuestras propiedades personalizadas y agregar box-shadow
Con esta pequeña pieza de CSS, nuestro mapa realmente cobra vida:
/* Matches an article element that contains a hover or focus state */
article:has(:hover, :focus) {
--img-scale: 1.1;
--title-color: #28666e;
--link-icon-translate: 0;
--link-icon-opacity: 1;
box-shadow: rgba(0, 0, 0, 0.16) 0px 10px 36px 0px, rgba(0, 0, 0, 0.06) 0px 0px 0px 1px;
}
¿Ves lo que hay? Ahora obtenemos los estilos if actualizados. cualquier tipo se mantiene o se enfoca un elemento secundario en el mapa. Y aunque el elemento de enlace es lo único que puede contener el estado del cursor o el foco en ::after
enfoque de mapa en el que se puede hacer clic, podemos usarlo para mapear el elemento principal y aplicar las transiciones.
Y ahí está. Solo otro poderoso caso de uso para :has()
No solo podemos hacer coincidir un elemento principal al declarar otros elementos como argumentos, sino que también podemos hacer coincidir y usar alias para hacer coincidir y diseñar los elementos principales.
Profesionales:
- Disponible
- Animado
- No se requiere JavaScript
- Usos
:hover
al elemento correcto
Contras:
- El texto no se selecciona fácilmente.
- El soporte del navegador está limitado a Chrome y Safari (compatible con Firefox detrás de una bandera).
Aquí hay una demostración usando esta técnica. Es posible que note un ajuste adicional alrededor del mapa, pero solo soy yo jugando con las solicitudes de contenedores, que es solo una de esas otras cosas elegantes que aparecen en todos los navegadores principales.
tengo algunos Otros ejemplos quieres compartir Otras soluciones o ideas son más que bienvenidas en la sección de comentarios.
Deja una respuesta