Skip links

Establecer SVG adaptativo con CSS Media Query – Smash Magazine

He escrito mucho sobre mí recientemente Preparación y optimización El código SVG se utiliza para gráficos estáticos o Animación. Me encanta trabajar con SVG, pero siempre tienen algo que me molesta.

Para ilustrar cómo construí un SVG adaptativo, elegí un episodio Dibujo rápido a McGraw Performance Llamado «BOW WOW BANDIT«Primera transmisión en 1959.

Ilustración Bow Wow Bandit
Show de McGraw de dibujo rápido © Warner Bros. Entertainment Inc. (Vista previa grande)

En él, el dructo rápido McGraw invita a su tabaco de sabueso a rescatar a su compañero Baba Looey. Como la mayoría de las tarjetas de título de Hanna-Barbera de la época, Lawrence Goble realizó la obra de arte.

Dibuje rápidamente el personaje de McGraw y retire la correa del perro para tirar de los folletos del perro del perro.
Bow Wow Bandit Toon Champions Entertainment de Andy Clarke (16: 9). (Vista previa grande)

Supongamos que he diseñado una escena SVG basada en Bow Wow Bandit que tiene una relación de aspecto de 16: 9 viewBox El tamaño es 1920 × 1080. Este SVG escala hacia arriba y hacia abajo (la pista en el nombre), por lo que se ve claro cuando es enorme y un minuto.

16: 9 Evaluación de aspecto y 3: 4.
Izquierda: la relación de aspecto 16: 9 pierde su impacto. Derecha: el formato 3: 4 es más adecuado para el tamaño de la pantalla. (Vista previa grande)

Pero en la pantalla pequeña, la relación de aspecto de 16: 9 (Demostración en vivo) puede no ser el mejor formato y la imagen pierde su impacto. A veces, la orientación del retrato (por ejemplo, 3: 4) encajará mejor con el tamaño de la pantalla.

Bow Wow Bandit Toon Champions Entertainment de Andy Clarke (3: 4).
Bow Wow Bandit Toon Champions Entertainment de Andy Clarke (3: 4). (Vista previa grande)

Pero aquí está el problema viewBox. Esto se debe a que en SVG, la posición del elemento interno está bloqueada en el sistema de coordenadas original viewBoxpor lo que no puede cambiar fácilmente el diseño entre ellos, como los dispositivos de escritorio y móviles. Este es un problema porque la animación y la interactividad generalmente dependen de la posición del elemento cuando viewBox Cambiar.

Izquierda: 16: 9 para pantallas grandes. Derecha: 3: 4 para pantallas más pequeñas.
Izquierda: 16: 9 para pantallas grandes. Derecha: 3: 4 para pantallas más pequeñas. (Vista previa grande)

Mi desafío es dar la versión 1080 × 1440 del Bow Wow Bandit a una pantalla más pequeña, mientras que la pantalla en la pantalla es diferente. Quiero la posición y el tamaño de los elementos internos (como dibujar a McGraw y su tabaco Dawg rápidamente) para adaptarse mejor a ambos diseños. Para resolver este problema, probé varias opciones.

Notas: Por qué no solo lo usamos <picture> Con SVG externo? este <picture> elemento Excelente para imágenes receptivas, pero solo funciona con formatos de trama (como JPEG o WebP) y archivos SVG externos que se consideran imágenes. Esto significa que no puede usar CSS para la animación o el estilo de elementos internos.

Mostrar y esconder svg

La opción más obvia es incluir dos SVG diferentes en mi etiqueta, uno para pantallas pequeñas y la otra para pantallas más grandes, y luego usarlos para mostrarlos u ocultarlos. Consulta de CSS y medios:

<svg id="svg-small" viewBox="0 0 1080 1440">
  <!-- ... -->
</svg>

<svg id="svg-large" viewBox="0 0 1920 1080">
  <!--... -->
</svg>


#svg-small { display: block; }
#svg-large { display: none; }

@media (min-width: 64rem) {
  #svg-small { display: none; }
  #svg-mobile { display: block; }
}

Pero con este método, ambas versiones SVG están cargadas, lo que significa descargar mucho y mucho código innecesario cuando los gráficos son complejos.

Reemplace SVG con JavaScript

He considerado intercambiar un SVG más grande usando JavaScript:

if (window.matchMedia('(min-width: 64rem)').matches) {
  svgContainer.innerHTML = desktopSVG; 
} else {
  svgContainer.innerHTML = mobileSVG;
}

Dejando de lado el hecho de que JavaScript ahora es crítico para la forma en que está diseñado, ya sea SVG generalmente se carga de todos modos, lo que agrega complejidad DOM y peso innecesario. Además, el mantenimiento se convierte en un problema, ya que ahora hay dos versiones de obras de arte que se pueden mantener, duplicando el tiempo para actualizar tan pequeño como una forma de cola de dibujo rápido.

Solución: una biblioteca de símbolos SVG y usos múltiples

Recuerda, mi objetivo es:

  • Proporcione una versión de Bow Wow Bandit a una pantalla más pequeña,
  • Proporcionar diferentes versiones para pantallas grandes,
  • Defina mi obra de arte solo una vez (seca), luego
  • Capacidad para cambiar el tamaño y reposicionar elementos.

No he leído lo suficiente <symbol> Los elementos le permiten definir elementos SVG reutilizables que pueden ocultarse y reutilizarse para mejorar la mantenibilidad y reducir la hinchazón del código. Son como componentes de SVG: Crea una vez y usa donde lo necesite:

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="quick-draw-body" viewBox="0 0 620 700">
    <g class="quick-draw-body">(…)</g>
  </symbol>
  <!-- ... -->
</svg>

<use href="#quick-draw-body" />

uno <symbol> Es como almacenar un papel en una biblioteca. Puedo hacer referencia varias veces según sea necesario para mantener mi código consistente y liviano. usar <use> Elementos, puedo insertar el mismo símbolo varias veces, en diferentes posiciones o tamaños, incluso en diferentes SVG.

Cada <symbol> Debe tener el tuyo viewBoxdefina su sistema de coordenadas internos. Esto significa que se presta especial atención a la exportación de elementos SVG de solicitudes como Sketch.

Exportar cada cuadro de visualización

Lo he escrito antes ¿Cómo exporto los elementos? En la capa, facilite trabajar con ellos. El proceso es algo diferente al crear símbolos.

Mi proceso habitual de exportar elementos de bocetos. (Vista previa grande)

Normalmente, exportaría todos mis elementos usando los mismos viewBoxtamaño. Pero cuando creo un symbolNecesito que tenga su propio específico viewBox.

Los elementos de exportación del boceto como un solo archivo SVG.
Los elementos de exportación del boceto como un solo archivo SVG. (Vista previa grande)

Entonces exporto cada elemento como un SVG de un tamaño separado, lo que me da el tamaño para convertir su contenido en uno symbol. Recogamos el SVG que rápidamente dibuja el sombrero de McGraw, que tiene uno viewBox El tamaño es 294 × 182:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 294 182">
  <!-- ... -->
</svg>

Cambio las etiquetas SVG a <symbol> Y agregue su obra de arte a mi biblioteca SVG:

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="quick-draw-hat" viewBox="0 0 294 182">
    <g class="quick-draw-hat">(…)</g>
  </symbol>
</svg>

Luego repití el proceso de todo el resto de los elementos en la obra de arte. Ahora, si necesito actualizar cualquiera de mis símbolos, los cambios se aplicarán automáticamente a cada instancia que use.

usar <symbol> En múltiples SVGS

Quiero que mis elementos aparezcan en dos versiones de Bow Wow Bandit, un arreglo alternativo para pantallas más pequeñas y pantallas más grandes. Entonces creé dos SVG:

<svg class="svg-small" viewBox="0 0 1080 1440">
  <!-- ... -->
</svg>

<svg class="svg-large" viewBox="0 0 1920 1080">
  <!-- ... -->
</svg>

… e inserte un enlace a mi símbolo en ambos:

<svg class="svg-small" viewBox="0 0 1080 1440">
  <use href="#quick-draw-hat" />
</svg>

<svg class="svg-large" viewBox="0 0 1920 1080">
  <use href="#quick-draw-hat" />
</svg>

Símbolos de posicionamiento

Una vez que puse el símbolo en mi diseño <use>Mi siguiente paso es colocarlos, lo cual es especialmente importante si quiero diseños alternativos para diferentes tamaños de pantalla. El comportamiento del símbolo es como <g> grupo para que pueda usar algo como width,,,,, heighty transform:

<svg class="svg-small" viewBox="0 0 1080 1440">
  <use href="#quick-draw-hat" width="294" height="182" transform="translate(-30,610)"/>
</svg>

<svg class="svg-large" viewBox="0 0 1920 1080">
  <use href="#quick-draw-hat" width="294" height="182" transform="translate(350,270)"/>
</svg>

Puedo poner cada uno <use> Use elementos de forma independiente transform. Esto es poderoso porque no estoy reposicionando elementos en mi SVG <use> referirse a. Mi diseño interno se mantiene limpio y el tamaño del archivo sigue siendo pequeño porque no estoy copiando la obra de arte. El navegador se carga solo una vez, reduciendo el ancho de banda y acelerando la representación de la página. Y porque siempre cito lo mismo symbolindependientemente del tamaño de la pantalla, su apariencia sigue siendo consistente.

Animación <use> elemento

Aquí es donde las cosas se ponen complicadas. Quiero animar parte del personaje, por ejemplo, una inclinación de sombrero rápida y sus piernas patadas. Sin embargo, cuando agrego animación CSS para elementos internos <symbol>no pasó nada.

pista: Puedes animar <use> El elemento en sí, pero no el elemento <symbol>. Si desea que las partes individuales se muevan, haga sus propios símbolos y anime cada símbolo <use>.

Resulta que no puedes dar forma o animación <symbol>porque <use> Crea clones DOM Shadow DOM que no son fáciles de localizar. Entonces, tengo que colarme. Cada interno <symbol> En mi biblioteca SVG, agregué un <g> Quiero animar los elementos por parte de la animación:

<symbol id="quick-draw-hat" viewBox="0 0 294 182">
  <g class="quick-draw-hat">
    <!-- ... -->
  </g>
</symbol>

… y animarlo utilizando el selector de subcadres de atributos href propiedad use elemento:

use(href="#quick-draw-hat") {
  animation-delay: 0.5s;
  animation-direction: alternate;
  animation-duration: 1s;
  animation-iteration-count: infinite;
  animation-name: hat-rock;
  animation-timing-function: ease-in-out;
  transform-origin: center bottom;
}

@keyframes hat-rock {
from { transform: rotate(-2deg); }
to   { transform: rotate(2deg); } }

Una vez que creé dos SVG visibles (uno para pantallas pequeñas y otra para pantallas más grandes), el paso final fue decidir qué versión se mostraba en qué tamaño de pantalla. Utilizo la consulta de medios CSS para ocultar un SVG y mostrar otro SVG. Primero muestro la pantalla pequeña SVG:

.svg-small { display: block; }
.svg-large { display: none; }

Entonces uso min-width Consulta de medios para cambiar a pantalla grande SVG 64rem Y arriba:

@media (min-width: 64rem) {
  .svg-small { display: none; }
  .svg-large { display: block; }
}

Esto asegura que solo se ve un SVG a la vez, manteniendo mi diseño simple y el DOM no tiene una confusión innecesaria. Y porque ambos SVG visibles hacen referencia a los mismos ocultos <symbol> Biblioteca, el navegador solo puede descargar obras de arte una vez, sin importar cuántos <use> Los elementos aparecen en ambos diseños.

El SVG adaptativo final.
Mira mi SVG adaptativo final final Sitio web del título de Toon. (Vista previa grande)

Resumir

Al combinar <symbol>,,,,, <use>Consultas de medios CSS y transformaciones específicas que puedo construir SVG adaptativo Reposicione sus elementos sin duplicar el contenido, cargar activos adicionales o confiar en JavaScript. Necesito definir cada gráfico solo una vez en la biblioteca de símbolos ocultos. Luego puedo reutilizar estos gráficos en varios SVG visibles según sea necesario. Cuando CSS está cambiando el diseño, Resultados rápidos y flexibles.

Esto le recuerda que algunas de las tecnologías más poderosas de la web no requieren grandes marcos o herramientas complejas, solo algunos conocimientos de SVG y uso inteligente de lo básico.

Aplastar editorial
(GG, YK)

Leave a comment

Home
Account
Cart
Search
¡Hola! ¡Pregúntame lo que quieras!
Explore
Drag