Advertisement
  1. Web Design
  2. HTML/CSS
  3. HTML

Usando SVGs en línea con HTML5

Scroll to top
Read Time: 18 min

() translation by (you can also view the original English article)

No hace falta decir que SVG no se usa tanto como muchas personas de la comunidad de desarrollo web creerían que debería ser usado. Dejando el debate a un lado, en este tutorial demostraré cómo usar SVGs en línea, cubriendo una variedad de técnicas y explorando la interacción entre página web y gráfico. Cuando se usan junto con otros estándares emergentes en HTML5, JavaScript y CSS3, los SVGs en línea pueden aportar significativamente a la experiencia del usuario.


Paso 1: Crea una página HTML5

Puedes interactuar con los elementos SVG usando técnicas DOM, como lo harías con otros elementos de una página web.

En este tutorial vamos a trabajar con un ejemplo práctico de un SVG en línea, creando un componente simple que representará a un tocadiscos. El disco girará y el usuario podrá interactuar con él, presionándolo para reducir su velocidad y soltándolo para acelerarlo nuevamente. El SVG también contendrá un botón en el que los usuarios pueden hacer clic para cambiar el disco, ocasionando que la apariencia de este último cambie ligeramente. Los  elementos SVG visibles serán mejorados con gradientes y filtros de sombras.

Prueba la demostración ahora para que tengas una idea clara de lo que estamos construyendo.

Como probablemente sepas, los SVGs en línea se encuentran dentro de los estándares emergentes de HTML5, así que el código que vamos a usar en este tutorial no será totalmente compatible con todos los navegadores. Si bien los SVGs en línea son compatibles en teoría con todas las versiones actuales de los principales navegadores, las animaciones internas y los efectos interactivos que usaremos todavía no son del todo compatibles. El resultado final debería funcionar correctamente en las versiones actuales de Firefox, Chrome y Opera. Como siempre, cuando se trata de las técnicas de HTML5 asegúrate de no confiar en estos efectos en ningún sitio en funcionamiento en el que estés trabajando, e incluye alternativas en donde sea posible.

Adentrémonos en el tema y comencemos creando la estructura de una página HTML5, de esta manera:

1
<!DOCTYPE html>
2
<html>
3
<head>
4
<script>
5
6
</script>
7
<style>
8
9
</style>
10
</head>
11
<body>
12
13
</body>
14
</html>

Una de las principales ventajas del uso de SVG es su capacidad de ser escalable. Para aprovechar esto, vamos a usar principalmente valores relativos para definir el contenido SVG. Agrega un elemento contenedor para el SVG en el cuerpo de la página:

1
<div id="picHolder">
2
3
</div>

Para ver la manera en la que el SVG se ajusta dentro del elemento contenedor, agrega lo siguiente a la sección style (estilo) en el encabezado de tu página:

1
#picHolder {background:#dedeff; border:1px solid #666666;}

Paso 2: Agrega el elemento SVG

En el elemento contenedor del cuerpo de tu página, agrega la estructura del elemento SVG, como se muestra a continuación:

1
<svg version="1.1"
2
       baseProfile="full"
3
     	xmlns="https://www.w3.org/2000/svg" 
4
     	height="100%" width="100%">
5
6
</svg>

Hemos establecido el valor del ancho (width) y alto (height) en 100%, ya que vamos a especificar el ancho del elemento contenedor. Sin embargo, en vez de especificar las dimensiones explícitamente usaremos una función de JavaScript para revelar la facilidad con la que puedes escalar el SVG para aumentar o reducir su tamaño. Puedes incluir un ancho y alto fijos en la etiqueta de apertura del SVG o en la sección style (estilo).


Paso 3: Crea las definiciones

Las figuras visibles del gráfico serán definidas dentro del elemento SVG. Antes de eso vamos a trabajar en la sección defs. La sección defs es donde colocas las definiciones a las que puedes hacer referencia posteriormente al crear tus figuras. Para este tutorial, la sección defs va a contener definiciones para algunos rellenos de tipo gradiente y un par de sombras. Agrega esta nueva sección dentro del elemento SVG:

1
<defs>
2
3
</defs>

Los elementos que colocamos en esta sección no aparecerán realmente en la imagen, pero serán usados como rellenos y filtros para las figuras que sí aparecerán. Vamos a incluir varios rellenos de tipo gradiente; trabajemos entonces en cada elemento, uno a la vez.

Gradientes

En primer lugar tenemos un gradiente lineal:

1
2
<linearGradient id="backGrad" x1="0%" y1="0%" x2="0%" y2="100%">
3
	<stop offset="10%" style="stop-color:#990000; stop-opacity:1" />
4
	<stop offset="90%" style="stop-color:#cccc00; stop-opacity:1" />
5
</linearGradient>

Este gradiente se especificará como el relleno para el área rectangular de fondo. Los atributos x1 e y1 representan los puntos de inicio del gradiente dentro de la figura rellenada, con el gradiente apareciendo a partir de ahí y hasta el punto representado por x2 e y2. En este caso, el gradiente se mostrará de arriba a abajo. Los elementos stop (parada) representan puntos de color en el gradiente. El primero indica que 10% del inicio del gradiente será de color rojo oscuro sólido y el segundo que el 90% del final del gradiente será de color amarillo. Entre estos dos puntos, el gradiente combinará los colores entre sí. Ambos colores tienen una opacidad total.

A continuación vamos a añadir un gradiente para el disco en sí. Este es un poco más complejo; se trata de un gradiente radial con varios stops de color:

1
<radialGradient id="recordGrad" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
2
	<stop offset="30%" style="stop-color:#000000; stop-opacity:1" />
3
	<stop offset="35%" style="stop-color:#222222; stop-opacity:1" />
4
	<stop offset="45%" style="stop-color:#000000; stop-opacity:1" />
5
	<stop offset="85%" style="stop-color:#000000; stop-opacity:1" />
6
	<stop offset="95%" style="stop-color:#222222; stop-opacity:1" />
7
	<stop offset="100%" style="stop-color:#000000; stop-opacity:1" />
8
</radialGradient>

Un gradiente lineal comienza desde el interior del círculo, con las partes más internas y externas del círculo definidas por cx, cy, fx y fy, enumeradas junto con el radio. En este caso, el gradiente lineal va a ocupar la totalidad de la figura circular del disco. La mayor parte del disco será de color negro, con dos anillos de un color ligeramente más claro que representarán las secciones más lisas en el centro del disco y sus orillas. Vamos a colocar una etiqueta en el centro del disco también, así que el primer fragmento de color más claro del disco aparecerá justo afuera de ella. A continuación agrega el relleno de tipo gradiente para la etiqueta:

1
<linearGradient id="labelGrad0" x1="0%" y1="0%" x2="100%" y2="0%">
2
	<stop offset="40%" style="stop-color:#000099; stop-opacity:1" />
3
	<stop offset="60%" style="stop-color:#009900; stop-opacity:1" />
4
</linearGradient>

Este es un gradiente lineal simple que será usado como relleno para la etiqueta del disco circular. Sin embargo, nota que el ID del gradiente tiene un cero al final. Esto se debe al hecho de que vamos a agregar una función interactiva que permitirá que el usuario "cambie el disco". Una función de JavaScript alternará entre un rango de rellenos de tipo gradiente para el elemento etiqueta. Para este propósito, agrega otro par de gradientes:

1
<linearGradient id="labelGrad1" x1="0%" y1="0%" x2="100%" y2="0%">
2
	<stop offset="0%" style="stop-color:#990000; stop-opacity:1" />
3
	<stop offset="20%" style="stop-color:#ff6600; stop-opacity:1" />
4
	<stop offset="40%" style="stop-color:#cccc00; stop-opacity:1" />
5
	<stop offset="60%" style="stop-color:#009900; stop-opacity:1" />
6
	<stop offset="80%" style="stop-color:#000099; stop-opacity:1" />
7
	<stop offset="100%" style="stop-color:#990099; stop-opacity:1" />
8
</linearGradient>
9
        
10
<linearGradient id="labelGrad2" x1="0%" y1="0%" x2="100%" y2="0%">
11
	<stop offset="0%" style="stop-color:#330033; stop-opacity:1" />
12
	<stop offset="100%" style="stop-color:#cc00cc; stop-opacity:1" />
13
</linearGradient>

Cada gradiente tiene un ID que termina con un entero incremental, para poder iterar a través de ellos en JavaScript. Ahora define otro gradiente para crear un efecto de brillo encima del disco:

1
<linearGradient id="shineGrad" x1="0%" y1="0%" x2="100%" y2="100%">
2
	<stop offset="35%" style="stop-color:#000000; stop-opacity:0" />
3
	<stop offset="50%" style="stop-color:#ffffff; stop-opacity:0.2" />
4
	<stop offset="65%" style="stop-color:#000000; stop-opacity:0" />
5
</linearGradient>

Esta vez el gradiente usa stops de color opaco y alfa transparente; el efecto será un brillo sutil a lo largo del disco. Finalmente necesitamos un relleno metálico para el botón y el eje:

1
<radialGradient id="dialGrad" cx="50%" cy="60%" r="60%" fx="40%" fy="40%">
2
	<stop offset="30%" style="stop-color:#cccccc;stop-opacity:1" />
3
	<stop offset="100%" style="stop-color:#333333;stop-opacity:1" />
4
</radialGradient>

En esta ocasión, el gradiente radial se encuentra ligeramente descentrado para crear una sensación de profundidad y luz, que será complementada con un filtro de sombra.

Filtros

Antes de que terminemos con la sección defs, agrega un par de sombras para darles un poco más de profundidad a algunas de las figuras:

1
<filter id="recordShadow" x="0" y="0" width="200%" height="200%">
2
	<feOffset result="offOut" in="SourceAlpha" dx="5" dy="5" />
3
	<feGaussianBlur result="blurOut" in="offOut" stdDeviation="3" />
4
</filter>

Este va a aparecer detrás del área del fisco. Las propiedades x, y, width y height hacen referencia a la posición y a las dimensiones dentro de la figura usando este filtro. El desplazamiento define a la sombra en relación con la figura original. El desenfoque evita que la figura desplazada sea de un color sólido, de manera que parezca una sombra. En este caso únicamente la sombra aparecerá, no la figura en sí; la sombra será definida por una figura dedicada que será colocada detrás de la figura del disco. Para los controles del usuario, que son circulares y metálicos, también queremos una sombra, pero queremos que la figura en sí también se muestre:

1
<filter id="dialShadow" x="0" y="0" width="200%" height="200%">
2
	<feOffset result="offOut" in="SourceAlpha" dx="2" dy="2" />
3
	<feGaussianBlur result="blurOut" in="offOut" stdDeviation="1" />
4
	<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
5
</filter>

Esta importante diferencia aquí, además de la escala de la sombra, es el elemento de fusión, que conservará la figura original y al mismo tiempo mostrará la sombra a su alrededor.


Paso 4: Crea las figuras

Suficiente con las preparaciones, ¡sigamos con los gráficos!. Cada elemento que agregues al cuerpo del SVG será mostrado encima de los elementos listados anteriormente, así que trabajaremos de abajo hacia arriba, comenzando con las figuras del fondo y terminando con las del frente.

Rectángulo de fondo

Primero agrega una figura rectangular para el fondo:

1
<rect width="90%" height="90%" x="5%" y="5%" fill="url(#backGrad)" />

Las dimensiones y la posición del elemento rect se especifican en relación al SVG contenedor que, si recuerdas, se encuentra en relación al tamaño del elemento contenedor. Configuraremos esto posteriormente en JavaScript. Usaremos valores de tamaño y posición relativos cada vez que sea posible, de manera que la imagen completa, además de la animación e interacción, puedan ser escaladas para incrementar o disminuir sus tamaños según se requiera. Nota que el elemento fill especifica uno de los gradientes que definimos, usando su atributo ID.

Sombra

Lo que sigue desde la parte inferior es la sombra del disco, usando uno de los filtros de sombra que creamos:

1
<circle cx="50%" cy="50%" r="33%" fill="#000000" filter="url(#recordShadow)" />

La sombra estará detrás del disco, como una figura circular con un radio de aproximadamente un tercio del espacio asignado a la imagen, y colocada en el centro. Ya que el filtro en este caso no aplica una fusión con la imagen, el círculo en sí no aparecerá, solamente su sombra.

Disco

A continuación se encuentra el disco en sí:

1
<circle cx="50%" cy="50%" r="33%" fill="url(#recordGrad)" />

Al igual que con la sombra, los atributos cx y cy representan el centro del disco, que se encuentra centrado en la imagen horizontalmente y verticalmente, con un radio de aproximadamente un tercio. Nuevamente usamos uno de los gradientes que definimos, y esto lo haremos en cada figura.

Etiqueta

Encima del disco se encuentra su etiqueta, así que agrégala a continuación:

1
<circle id="recordLabel" cx="50%" cy="50%" r="10%" fill="url(#labelGrad0)" />

El círculo de la etiqueta tiene el mismo punto central que el disco, y se extiende a través de él en aproximadamente un tercio de su superficie. Comenzamos con la primera de las opciones de gradiente para la etiqueta que definimos, e implementaremos lo necesario para que el usuario cambie entre etiquetas más adelante - incluimos un atributo ID aquí para hacer referencia a este elemento en JavaScript.

Brillo

Ahora coloquemos un poco de brillo sobre el disco:

1
<circle id="shine" cx="50%" cy="50%" r="32%" fill="url(#shineGrad)" />

Cuando el disco gire, este se moverá a la derecha y hacia abajo solo un poco, así que debemos mantener el brillo ligeramente más pequeño que el disco, para que no parezca que se extiende más allá del mismo cuando se mueve. Este elemento también tiene un atributo ID para detectar la interacción con el usuario.

Eje

Para completar, vamos a añadir un pequeño eje en el centro del disco:

1
<circle cx="50%" cy="50%" r="1%" fill="url(#dialGrad)" filter="url(#dialShadow)" />

Esta figura usa el gradiente metálico que creamos. También aplicamos el segundo filtro de sombra, que incluye fusión, para que tanto la figura como la sombra se muestren.

Botón

Por último, pero no por eso menos importante, necesitamos un pequeño botón para que los usuarios controlen el cambio del disco, usando el mismo relleno y filtro del eje:

1
<circle cx="83%" cy="83%" r="3%" fill="url(#dialGrad)" filter="url(#dialShadow)">
2
3
</circle>

Esta vez, en vez de un elemento con cierre automático vamos a separar las etiquetas de apertura y cierre del círculo. Esto es debido a que vamos a animar el botón cuando el usuario haga clic en él, y vamos a incluir el efecto de animación entre estas etiquetas. Nota que hemos podido reutilizar elementos de relleno y filtros de la sección defs. Esta es la apariencia inicial del gráfico una vez que las dimensiones de la página han sido establecidas:

record player initial appearance

Paso 5: Agrega animación

Cada elemento que agregues al cuerpo del SVG será mostrado encima de los elementos previamente enumerados.

Ahora tenemos nuestros elementos visuales en su lugar, vamos a añadir un poco de animación. Podemos hacer que el disco gire usando transformaciones de animación en SVG, que son una extensión de la animación SMIL. Estos efectos animados se definen dentro del marcado de SVG. Un efecto se aplica a cualquier elemento SVG que aparezca en el interior. Puedes usar transformaciones CSS3 en elementos SVG, pero las alternativas basadas en SMIL te proporcionan un mayor nivel de control.

Vamos a incluir dos animaciones simples: el disco va a girar y el botón se va a mover un poco cuando el usuario haga clic en él. Comencemos con la animación para el botón, que es ligeramente más sencilla.

Dentro del elemento de la figura del botón, entre las etiquetas de apertura y cierre del círculo que creamos, agrega la transformación de animación como se muestra aquí:

1
<animateTransform 
2
	attributeType="XML"
3
	attributeName="transform" 
4
	type="translate"
5
	from="0, 0" to="1, 1"
6
	dur="0.1s" begin="click"
7
	repeatCount="1"
8
	/>

La animateTransform (transformación de animación) se aplica a un atributo XML dentro del elemento en el que aparezca. En este caso, es un transformación de tipo translate (trasladar). Los atributos from (desde) y to (hasta) representan las posiciones inicial y final del elemento, y son relativas a su posición inicial, de manera que el botón se va a mover a la derecha y hacia abajo un solo píxel. La transformación comenzará cuando un usuario haga clic, transcurrirá durante más de una décima de segundo y se ejecutará una vez. El botón regresará a su posición original cuando la animación termine. Sugerencia: Para mantener un elemento en la posición final después de una animación, especifica fill="freeze".

Ahora, para hacer girar el disco. Una animateTransform se aplica sobre un elemento SVG, pero necesitamos que el giro se aplique sobre más de un elemento - específicamente sobre el disco y la etiqueta (no sobre el brillo ni la sombra). En vez de crear animaciones separadas para cada elemento y ejecutarlas al mismo tiempo, podemos usar una sola transformación agrupando estos elementos entre sí. Antes del elemento círculo que representa al disco (con "recordGrad" como relleno) agrega una etiqueta de apertura de grupo:

1
<g>

Cierra el grupo después del círculo que representa a la etiqueta:

1
</g>

Ahora agrega la transformación antes de esta etiqueta de cierre de grupo, para que sea aplicada al grupo completo:

1
<animateTransform id="spinTrans"
2
	attributeType="XML"
3
	attributeName="transform" 
4
	type="rotate" 
5
	by="360, 1, 1"
6
	dur="1s"
7
	repeatCount="indefinite"
8
	/>

Esta vez el efecto de animación es una transformación de tipo rotate (giro). El elemento girará 360 grados y, para añadir al efecto, se moverá a la derecha y hacia abajo un solo píxel en cada giro, durante un período de un segundo, y se repetirá indefinidamente. Esta transformación también incluirá un atributo from (desde), ya que es necesario para especificar la posición inicial de los elementos que están siendo girados. Si no especificas esta posición, los elementos girarán alrededor del punto 0, 0 de forma predeterminada. Sin embargo, en este momento no puedes proporcionar valores relativos (es decir, porcentajes) a estos atributos, solamente valores fijos. Por este motivo vamos a establecer el atributo from cuando especifiquemos las dimensiones del SVG en JavaScript.


Paso 6: Agrega interacción

Ahora vamos a implementar nuestras funciones interactivas: hacer clic en el botón para cambiar el disco y presionar el disco para reducir su velocidad.

Cambia el disco

Primero, en la sección script del encabezado de tu página agrega estas variables para contar y mantener control sobre los diseños de las etiquetas:

1
//keep track of current record label

2
var currLabel = 0;
3
//alter this for a different number of labels

4
var numLabels = 3;

Ahora, dentro de la etiqueta de apertura del elemento círculo que representa al botón (que ahora tiene una animación entre sus etiquetas), agrega el siguiente detector de eventos clic:

1
onclick="changeRecord()"

De vuelta en la sección script del encabezado agrega la estructura de la función:

1
function changeRecord() {
2
3
}

Cada vez que el usuario presione el botón nos moveremos a la siguiente etiqueta, volviendo a la primera cuando lleguemos a la última de ellas:

1
//move to next label

2
currLabel++;
3
4
//reset if at highest number

5
if (currLabel > numLabels - 1) currLabel = 0;
6
7
//set the fill attribute to the next gradient

8
document.getElementById("recordLabel").setAttribute("fill", "url(#labelGrad"+currLabel+")");

La última línea muestra cómo puedes interactuar con los elementos SVG usando técnicas DOM, como lo harías con otros elementos de una página web. Aquí configuramos el atributo fill del círculo de la etiqueta para usar el siguiente relleno de tipo gradiente, especificando el ID del relleno.

record label alternative

Reduce su velocidad

Ahora agrega los siguientes atributos de evento al elemento correspondiente al brillo del disco (con "shineGrad" como relleno), ya que vamos a usar eventos para detectar cuando el botón del ratón sea presionado y soltado sobre él, con el fin de reducir la velocidad del disco e incrementarla de nuevo:

1
onmousedown="onRecord()" onmouseup="offRecord()"

De vuelta en la sección script, agrega la función para cuando un usuario esté presionando el disco:

1
//function called when user is pressing record

2
function onRecord() { 
3
4
}

Dentro de esta función podemos reducir la velocidad de la animación para el giro del disco alterando el atributo de duración de animateTransform. También modificamos la opacidad del brillo para crear la impresión de que estamos presionando el disco:

1
//slow the animation duration

2
document.getElementById("spinTrans").setAttribute("dur", "5s");
3
//decrease the shine opacity

4
document.getElementById("shine").style.opacity="0.7";

Cuando el usuario suelte el disco queremos regresar a la apariencia y velocidad normales, así que agrega la función "mouse up" a continuación:

1
//function called when user releases record

2
function offRecord() {
3
	//reset to normal speed

4
	document.getElementById("spinTrans").setAttribute("dur", "1s");
5
6
	//set opacity back to normal

7
	document.getElementById("shine").style.opacity="1.0";
8
}

Paso 7: Especifica el tamaño

Finalmente podemos configurar el tamaño general del SVG. Agrega una nueva variable en la parte superior de la sección script:

1
//desired size of SVG

2
var size = 300;

Inicialmente vamos a usar 300 píxeles para el ancho (width) y para el alto (height) del gráfico, pero siéntete en la libertad de modificar esto en cualquier momento. Define una función en la sección script para establecer estas dimensiones:

1
//function to set SVG dimensions

2
function setSize() {
3
	//set css and transform size

4
	var holder = document.getElementById("picHolder");
5
6
	holder.style.height=size+"px";
7
	holder.style.width=size+"px";
8
	document.getElementById("spinTrans").setAttribute("from", "0, "+size/2+", "+size/2+"");
9
}

Establecemos el tamaño del elemento div contenedor. Tómate un momento para analizar la línea final de esta función. Dado que la animación de la transformación de giro no puede usar valores porcentuales relativos, debemos establecer el valor del elemento from usando la variable del tamaño (dividida entre dos para el punto central del disco). Teniendo el valor de 300 como tamaño del SVG, esta es la manera en la que la transformación se vería con valores fijos:

1
<animateTransform id="spinTrans"
2
	attributeType="XML"
3
	attributeName="transform" 
4
	type="rotate" 
5
	from="0, 150, 150"
6
	by="360, 1, 1"
7
	dur="1s"
8
	repeatCount="indefinite"
9
	/>

Si quieres usar valores fijos en tu SVG, puedes hacerlo. Solamente estamos empleando esta técnica para demostrar el uso de dimensiones relativas. Finalmente, invoca esta función al final de la sección script:

1
window.addEventListener("DOMContentLoaded", setSize, false);

Conclusión

¡Nuestra animación SVG interactiva ahora está terminada! abre tu página en un navegador compatible para ver el efecto; no olvides intentar interactuar con el disco y el botón. Intenta modificando la variable del tamaño para ver de qué manera se adaptan a ella los elementos SVG, incluyendo las animaciones e interacciones.

Si deseas explorar SVG más a fondo, algunos temas a considerar son rutas, texto, enmascaramiento y recortes. También hay una serie de opciones de animación adicionales a considerar. Desde luego, estos efectos no funcionarán para todos los usuarios en la actualidad, pero esperemos que pronto lo hagan...

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.