Como dice el título, ¡decoraremos imágenes! Hay muchos otros artículos que hablan de esto, pero lo que estamos viendo aquí es bastante diferente porque es más un desafío. ¿El reto? Decora una imagen usando solo <img>
etiqueta y nada más.
Así es, sin marcado adicional, sin divs y pseudo-elementos. Solo una etiqueta.
Suena difícil, ¿verdad? Pero al final de este artículo, y de los demás que componen esta pequeña serie, demostraré que CSS es lo suficientemente poderoso como para brindarnos resultados excelentes y sorprendentes a pesar de la limitación de trabajar con un solo elemento.
Serie de decoración de imágenes de lujo
- Magia de un elemento— Estás aquí
- Máscaras y efectos extendidos de mouse-over (llegando el 21 de octubre )
- Contornos y animaciones complejas (próximo 28 de octubre )
Comencemos con nuestro primer ejemplo.
Antes de sumergirnos en el código, enumeremos las opciones de estilo para un <img>
sin ningún elemento adicional o pseudo-elemento Podemos usar border
, box-shadow
, outline
y por supuesto, background
Puede parecer extraño agregar un fondo a una imagen porque no podemos verlo porque estará detrás de la imagen, pero el truco es crear espacio. alrededor usando la imagen padding
y/o border
y luego dibujar nuestro fondo dentro de ese espacio.
Creo que sabes lo que sigue después de que hable de eso. background
¿Correcto? Sí, gradientes! Todas las decoraciones que vamos a hacer se basan en muchos degradados. Si me has estado siguiendo por un tiempo, creo que esto probablemente no te sorprenda en absoluto. 😁
Volvamos a nuestro primer ejemplo:
img {
--s: 10px; /* control the size */
padding: var(--s);
border: calc(2 * var(--s)) solid #0000;
outline: 1px solid #000;
outline-offset: calc(-1 * var(--s));
background: conic-gradient(from 90deg at 1px 1px, #0000 25%, #000 0);
}
Nosotros determinamos padding
y transparente border
usando la variable --s
para crear un espacio alrededor de nuestra imagen igual a tres veces esta variable.
Por qué usamos ambos padding
y border
en lugar de uno o el otro? Podemos obtener usando solo uno de ellos, pero necesito esta combinación para mi gradiente porque, por defecto, el valor inicial de background-clip
es border-box
y background-origin
es igual a padding-box
.
Aquí hay una ilustración paso a paso para entender la lógica:
Inicialmente, no tenemos bordes de imagen, por lo que nuestro degradado creará dos segmentos con 1px
de espesor (yo uso 3px
en esta demostración en particular, por lo que es más fácil de ver). Agregamos un borde de color y el degradado aún nos da el mismo resultado dentro del área del pad (debido a background-origin
), pero se repite más allá del límite. Si hacemos transparente el color del marco, podemos usar la repetición y obtendremos el marco deseado.
los outline
en la demostración hay una compensación negativa. Esto crea una forma cuadrada en la parte superior del degradado. ¡Está! Agregamos una bonita decoración a nuestra imagen usando un solo degradado y outline
. ¡Podríamos usar más gradientes! Pero siempre trato de mantener mi código lo más simple posible y descubrí que agregar el outline
es mejor así.
Aquí hay una solución de solo gradiente donde solo uso padding
para definir el espacio. Sigue siendo el mismo resultado, pero con una sintaxis más compleja.
Probemos con otra idea:
Para este tomé el ejemplo anterior, eliminé outline
y aplicó un clip-path
para recortar el degradado en cada lado clip-path
value es un poco prolijo y confuso, pero aquí hay una ilustración para ver mejor sus puntos:
Creo que entiendes la esencia. Combinaremos fondos, contornos, recortes y un poco de enmascaramiento para lograr diferentes tipos de decoraciones. ¡También veremos algunas animaciones geniales como una ventaja adicional! ¡Lo que hemos cubierto hasta ahora es solo una pequeña vista previa de lo que está por venir!
El marco solo con un ángulo.
Esto toma cuatro gradientes. Cada degradado cubre una esquina y al pasar el mouse los expande para crear un marco completo alrededor de la imagen. Analicemos el código de uno de los gradientes:
--b: 5px; /* border thickness */
background: conic-gradient(from 90deg at top var(--b) left var(--b), #0000 90deg, darkblue 0) 0 0;
background-size: 50px 50px;
background-repeat: no-repeat;
Dibujaremos un degradado con un tamaño igual a 50px 50px
y colóquelo en la esquina superior izquierda (0 0
). Para la configuración del gradiente, aquí hay una ilustración paso a paso que muestra cómo logré este resultado.
Tendemos a pensar que los gradientes solo son buenos para la transición entre dos colores. Pero en realidad, ¡podemos hacer mucho más con ellos! Son especialmente útiles a la hora de crear diferentes formas. El truco es asegurarse de que tengamos paradas duras entre los colores, como en el ejemplo anterior, en lugar de transiciones suaves:
#0000 25%, darkblue 0
Esto básicamente significa: "llene el degradado con un color transparente mientras 25%
del área, luego llene el resto con darkblue
.
Puede que te estés rascando la cabeza 0
valor. Este es un pequeño truco para simplificar la sintaxis. De hecho, necesitamos usar esto para hacer una parada brusca entre los colores:
#0000 25%, darkblue 25%
¡Eso es más lógico!, el transparente. color termina en 25%
y darkblue
comienza exactamente donde termina la transparencia, haciendo una parada brusca.Si reemplazamos el segundo con 0
el navegador hará el trabajo por nosotros, por lo que es una forma un poco más eficiente de hacerlo.
En algún lugar de la especificacióndice:
si parada de color o un toque de transición tiene una posición que es menor que la posición especificada de cualquier parada de color o sugerencia de transición anterior en la lista, establezca su posición para que sea igual a la posición especificada más grande de cualquier parada de color o sugerencia de transición anterior.
0
es siempre menor que cualquier otro valor, por lo que el navegador siempre lo convertirá al valor más grande que viene antes en la declaración. En nuestro caso, este número es 25%
.
Ahora aplicamos la misma lógica a todos los rincones y terminamos con el siguiente código:
img {
--b: 5px; /* border thickness */
--c: #0000 90deg, darkblue 0; /* define the color here */
padding: 10px;
background:
conic-gradient(from 90deg at top var(--b) left var(--b), var(--c)) 0 0,
conic-gradient(from 180deg at top var(--b) right var(--b), var(--c)) 100% 0,
conic-gradient(from 0deg at bottom var(--b) left var(--b), var(--c)) 0 100%,
conic-gradient(from -90deg at bottom var(--b) right var(--b), var(--c)) 100% 100%;
background-size: 50px 50px; /* adjust border length here */
background-repeat: no-repeat;
}
Introduje variables CSS para evitar cierta redundancia ya que todos los degradados usan la misma configuración de color.
Para el efecto de retención, todo lo que hago es aumentar el tamaño de los degradados para crear el marco completo:
img:hover {
background-size: 51% 51%;
}
Sí, lo es 51%
en cambio 50%
— que crea poca superposición y evita posibles lagunas.
Probemos otra idea usando la misma técnica:
Esta vez usamos solo dos degradados, pero con una animación más compleja. Primero actualizamos la posición de cada degradado, luego aumentamos sus tamaños para crear el marco completo. También introduje más variables para un mejor control sobre el color, el tamaño, el grosor e incluso la distancia entre la imagen y el marco.
img {
--b: 8px; /* border thickness*/
--s: 60px; /* size of the corner*/
--g: 14px; /* the gap*/
--c: #EDC951;
padding: calc(var(--b) + var(--g));
background-image:
conic-gradient(from 90deg at top var(--b) left var(--b), #0000 25%, var(--c) 0),
conic-gradient(from -90deg at bottom var(--b) right var(--b), #0000 25%, var(--c) 0);
background-position:
var(--_p, 0%) var(--_p, 0%),
calc(100% - var(--_p, 0%)) calc(100% - var(--_p, 0%));
background-size: var(--s) var(--s);
background-repeat: no-repeat;
transition:
background-position .3s var(--_i,.3s),
background-size .3s calc(.3s - var(--_i, .3s));
}
img:hover {
background-size: calc(100% - var(--g)) calc(100% - var(--g));
--_p: calc(var(--g) / 2);
--_i: 0s;
}
por qué --_i
y --_p
variables tienen un guión bajo en su nombre? El guión bajo es parte de una convención de nomenclatura que utilizo para referirme a las variables "internas" utilizadas para optimizar el código. No son nada especial, pero quiero diferenciar entre las variables que ajustamos para controlar el marco (como --b
, --c
etc) y los que uso para acortar el código.
El código puede parecer confuso y no fácil de entender, pero he escrito una serie de tres partes que detallan esta técnica. Recomiendo encarecidamente leer al menos el primer artículo para comprender cómo llegué al código anterior.
Aquí hay una ilustración para entender mejor los diferentes valores:

Revelando el marco
Probemos con otro tipo de animación donde revelamos todo el cuadro al pasar el mouse:
Genial, ¿verdad? Y si observa de cerca, notará que las líneas desaparecen en la dirección opuesta cuando sale el mouse, ¡lo que hace que el efecto sea aún más sofisticado! Usé un efecto similar en un artículo anterior.
Pero esta vez, en lugar de cubrir todo el elemento, cubro solo una pequeña parte definiendo un height
para obtener algo como esto:
Este es el límite superior de nuestro marco. Repetimos el mismo proceso en cada lado de la imagen y tenemos nuestro efecto de retención:
img {
--b: 10px; /* the border thickness*/
--g: 5px; /* the gap on hover */
--c: #8A9B0F;
padding: calc(var(--g) + var(--b));
--_g: no-repeat linear-gradient(var(--c) 0 0);
background:
var(--_g) var(--_i, 0%) 0,
var(--_g) 100% var(--_i, 0%),
var(--_g) calc(100% - var(--_i, 0%)) 100%,
var(--_g) 0 calc(100% - var(--_i, 0%));
background-size: var(--_i, 0%) var(--b),var(--b) var(--_i, 0%);
transition: .4s, background-position 0s;
cursor: pointer;
}
img:hover {
--_i: 100%;
}
Como puede ver, aplico el mismo degradado cuatro veces y cada una tiene una posición diferente para cubrir solo un lado a la vez.
¿Otro? ¡Vamos!
Esto parece un poco complicado y realmente requiere un poco de imaginación para descubrir cómo dos gradientes cónicos hacen este tipo de magia. Aquí hay una demostración que ilustra uno de los gradientes:
El pseudo-elemento simula el degradado. Inicialmente, no es visible y, al pasar el mouse, primero lo reposicionamos para obtener el borde superior del marco. Luego aumentamos la altura para obtener el borde correcto. La forma del degradado es similar a las que usamos en la última sección: dos segmentos para cubrir ambos lados.
Pero, ¿por qué hice el ancho del degradado? 200%
Tu pensarias 100%
eso sería suficiente, ¿no?
100%
debería ser suficiente, pero no podré mover el gradiente como quiero si mantengo su ancho igual a 100%
Esta es otra pequeña peculiaridad relacionada con cómo background-position
obras. Cubrí esto en un artículo anterior. Yo también publicó una respuesta en Stack Overflow para lidiar con eso. Sé que es mucha lectura, pero realmente vale la pena tu tiempo.
Ahora que hemos explicado la lógica de un degradado, el segundo es fácil porque hace exactamente lo mismo, pero en su lugar cubre los bordes izquierdo e inferior. Todo lo que tenemos que hacer es intercambiar algunos valores y listo:
img {
--c: #8A9B0F; /* the border color */
--b: 10px; /* the border thickness*/
--g: 5px; /* the gap */
padding: calc(var(--g) + var(--b));
--_g: #0000 25%, var(--c) 0;
background:
conic-gradient(from 180deg at top var(--b) right var(--b), var(--_g))
var(--_i, 200%) 0 / 200% var(--_i, var(--b)) no-repeat,
conic-gradient( at bottom var(--b) left var(--b), var(--_g))
0 var(--_i, 200%) / var(--_i, var(--b)) 200% no-repeat;
transition: .3s, background-position .3s .3s;
cursor: pointer;
}
img:hover {
--_i: 100%;
transition: .3s, background-size .3s .3s;
}
Como puede ver, ambos gradientes son casi idénticos. Solo cambio los valores de tamaño y posición.
Rotación de fotogramas
Esta vez no dibujaremos un borde alrededor de nuestra imagen, sino que ajustaremos la apariencia de uno existente.
Probablemente te estés preguntando cómo diablos puedo transformar una línea recta en una línea en ángulo. No, la magia es diferente de eso. Esta es solo la ilusión que obtenemos después de combinar animaciones simples para cuatro gradientes.
Veamos cómo se hace la animación para el degradado superior:
Solo estoy actualizando la posición de un gradiente repetitivo. Todavía nada especial! Hagamos lo mismo para el lado derecho:
¿Estás empezando a ver el truco? Ambos degradados se cruzan en la esquina para crear la ilusión de una línea recta que cambia a una en ángulo. Eliminemos el contorno y ocultemos el desbordamiento para que pueda verlo mejor:
Ahora agregamos dos degradados más para cubrir los bordes restantes y terminamos:
img {
--g: 4px; /* the gap */
--b: 12px; /* border thickness*/
--c: #669706; /* the color */
padding: calc(var(--g) + var(--b));
--_c: #0000 0 25%, var(--c) 0 50%;
--_g1: repeating-linear-gradient(90deg ,var(--_c)) repeat-x;
--_g2: repeating-linear-gradient(180deg,var(--_c)) repeat-y;
background:
var(--_g1) var(--_p, 25%) 0,
var(--_g2) 0 var(--_p, 125%),
var(--_g1) var(--_p, 125%) 100%,
var(--_g2) 100% var(--_p, 25%);
background-size: 200% var(--b), var(--b) 200%;
transition: .3s;
}
img:hover {
--_p: 75%;
}
Si tomamos este código y lo ajustamos ligeramente, podemos obtener otra gran animación:
¿Puedes entender la lógica en este ejemplo? ¡Esta es tu tarea! El código puede parecer intimidante, pero usa la misma lógica que los ejemplos anteriores que vimos. Intenta aislar cada degradado e imagina cómo se anima.
resumiendo
¡Eso es un montón de gradientes en un artículo!
¡Debe ser así y te lo advertí! Pero si el reto es decorar una imagen sin elementos extra y pseudoelementos, nos quedan pocas posibilidades y los degradados son la opción más potente.
No se preocupe si está un poco perdido en algunas de las explicaciones. Siempre recomiendo algunos de mis artículos antiguos donde detallo más algunos de los conceptos que reciclamos para este reto.
Me iré con una última demostración para esperar hasta el próximo artículo de esta serie. Esta vez uso radial-gradient()
para crear otro divertido efecto de sujeción. Te dejaré analizar el código para entender cómo funciona. ¡Hazme preguntas en los comentarios si te quedas atascado!
Serie de decoración de imágenes de lujo
- Magia de un elemento— Estás aquí
- Máscaras y efectos extendidos de mouse-over (llegando el 21 de octubre )
- Contornos y animaciones complejas (próximo 28 de octubre )
Deja una respuesta