Tejiendo una línea a través del texto en CSS

Índice
  1. estructura HTML
  2. Estilos básicos
  3. Longitud de la línea
  4. Haciendo que la línea vaya por encima y por debajo
  5. ¡Anímalo!
  6. Un toque 3D

A principios de este año, me encontré con esta demostración de Florin Pop, que hace que una línea pase por encima o por debajo de las letras de un encabezado de una sola línea. Pensé que era una buena idea, pero hubo algunas pequeñas cosas acerca de la implementación que sentí que podía simplificar y mejorar al mismo tiempo.

En primer lugar, la demostración original duplica el texto del título, lo que sabía que podría evitarse fácilmente. Luego está el hecho de que la longitud de la línea que atraviesa el texto es un número mágico, lo cual no es un enfoque muy flexible. Y finalmente, ¿no podemos deshacernos de JavaScript?

Así que echamos un vistazo a dónde terminé tomando esto.

estructura HTML

Florin coloca el texto en un elemento de encabezado y luego duplica este encabezado, usando Splitting.js para reemplazar el contenido del texto del encabezado duplicado con intervalos, cada uno de los cuales contiene una letra del texto original.

Habiendo decidido hacer esto sin duplicación de texto, usar una biblioteca para dividir el texto en caracteres y luego poner cada uno en una spansensación un poco exagerada, así que lo estamos haciendo todo con un preprocesador HTML.

- let text = 'We Love to Play';- let arr = text.split('');h1(role='image' aria-label=text)  - arr.forEach(letter = {    span.letter #{letter}  - });

Dado que dividir texto en Múltiples elementos puede no funcionar bien con lectores de pantalla, le hemos dado a todo un de roley imageun aria-label.

Esto genera el siguiente HTML:

h1 role="image" aria-label="We Love to Play"  spanW/span  spane/span  span /span  spanL/span  spano/span  spanv/span  spane/span  span /span  spant/span  spano/span  span /span  spanP/span  spanl/span  spana/span  spany/span/h1

Estilos básicos

Colocamos el encabezado en medio de su padre ( bodyen este caso) usando un griddiseño:

body {  display: grid;  place-content: center;}

También podemos añadir algunos toques bonitos, como un bonito fonto un backgrounden el recipiente.

A continuación, creamos la línea con un ::afterpseudoelemento de espesor ( height) absolutamente posicionado $h:

$h: .125em;$r: .5*$h;h1 {  position: relative;    ::after {    position: absolute;    top: calc(50% - #{$r}); right: 0;    height: $h;    border-radius: 0 $r $r 0;    background: crimson;  }}

El código anterior se encarga del posicionamiento y heightdel pseudoelemento, pero ¿qué pasa con width? ¿Cómo hacemos para que se extienda desde el borde izquierdo de la ventana gráfica hasta el borde derecho del texto del encabezado?

Longitud de la línea

Bueno, dado que tenemos un griddiseño donde el título está alineado en el medio horizontalmente, esto significa que la línea media vertical de la ventana gráfica coincide con la del título, dividiendo ambos en dos mitades del mismo ancho:

En consecuencia, la distancia entre el borde izquierdo de la ventana gráfica y el borde derecho del encabezado es la mitad del ancho de la ventana gráfica ( 50vw) más la mitad del ancho del encabezado, que puede expresarse como un %valor cuando se usa en el cálculo. de sus pseudoelementos width.

Entonces el widthde nuestro ::afterpseudoelemento es:

width: calc(50vw + 50%);

Haciendo que la línea vaya por encima y por debajo

Hasta ahora, el resultado es sólo una línea carmesí que cruza un texto negro:

Lo que queremos es que algunas de las letras aparezcan en la parte superior de la línea. Para conseguir este efecto, les damos (o no les damos) una clase de .overazar. Esto significa alterar ligeramente el código Pug:

- let text = 'We Love to Play';- let arr = text.split('');h1(role='image' aria-label=text)  - arr.forEach(letter = {    span.letter(class=Math.random()  .5 ? 'over' : null) #{letter}  - });

Luego posicionamos relativamente las letras con una clase de .overy les damos un positivo z-index.

.over {  position: relative;  z-index: 1;}

Mi idea inicial implicaba usar translatez(1px)en lugar de z-index: 1, pero luego me di cuenta de que usar z-indextiene mejor compatibilidad con el navegador e implica menos esfuerzo.

La línea pasa por encima de algunas letras, pero por debajo de otras:

¡Anímalo!

Ahora que superamos la parte complicada, también podemos agregar un animationpara hacer que la línea entre. Esto significa que la línea carmesí se desplaza hacia la izquierda (en la dirección negativa del eje x, por lo que el signo será menos) por su máximo width( 100%) al principio, sólo para luego permitirle volver a su posición normal.

@keyframes slide { 0% { transform: translate(-100%); } }

Opté por tener un poco de tiempo para respirar antes del inicio del animation. Esto significó agregar el 1sretraso que, a su vez, significó agregar la backwardspalabra clave para animation-fill-mode, de modo que la línea permaneciera en el estado especificado por el 0%fotograma clave antes del inicio de animation:

animation: slide 2s ease-out 1s backwards;

Un toque 3D

Hacer esto me dio otra idea, que fue hacer que la línea atravesara cada letra, es decir, comenzar arriba de la letra, recorrerla y terminar debajo (o al revés).

Esto requiere 3D real y algunos pequeños ajustes.

En primer lugar, configuramos transform-styleel preserve-3dencabezado ya que queremos que todos sus hijos (y pseudoelementos) formen parte del mismo ensamblaje 3D, lo que hará que se ordenen y se crucen según cómo estén posicionados en 3D.

A continuación, queremos rotar cada letra alrededor de su eje y, con la dirección de rotación dependiendo de la presencia de la clase asignada aleatoriamente (cuyo nombre cambiamos .revde “inverso” a “sobre” no sugiere realmente lo que queremos). estás haciendo aquí más).

Sin embargo, antes de hacer esto, debemos recordar que nuestros elementos todavía están en línea en este punto y establecer a transformen un elemento en línea no tiene absolutamente ningún efecto.

Para solucionar este problema, nos fijamos display: flexen el título. Sin embargo, esto crea un nuevo problema y es el hecho de que los elementos de intervalo que contienen solo un espacio ( " ") quedan reducidos a cero width.

Una solución sencilla para esto es configurar white-space: prenuestros .lettertramos.

Una vez que hayamos hecho esto, podemos rotar nuestros tramos en un ángulo $a… ¡en una dirección u otra!

$a: 2deg;.letter {  white-space: pre;  transform: rotatey($a);}.rev { transform: rotatey(-$a); }

Dado que la rotación alrededor del eje y aplasta nuestras letras horizontalmente, podemos escalarlas a lo largo del eje x mediante un factor ( $f) que es el inverso del coseno de $a.

$a: 2deg;$f: 1/cos($a).letter {  white-space: pre;  transform: rotatey($a) scalex($f)}.rev { transform: rotatey(-$a) scalex($f) }

Si desea comprender el motivo del uso de este factor de escala en particular, puede consultar este artículo anterior donde lo explico todo en detalle.

¡Y eso es! ¡Ahora tenemos el resultado 3D que buscábamos! Sin embargo, tenga en cuenta que la fuente utilizada aquí se eligió para que nuestro resultado se vea bien y es posible que otra fuente no funcione tan bien.

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion