Make any SVG responsive with this React component - LogRocket Blog (2024)

If you are putting out digital content into the world wide web to publicize your work, then there is a high chance that your audience will view it on a mobile device. For text and images, this is not a huge problem with modern CSS. But if the content is a data visualization using SVG elements, this might be a problem.

Make any SVG responsive with this React component - LogRocket Blog (1)

I initially ran into problems on mobile devices with some graphs I was working on creating. After a lot of fumbling, I made some reusable components that can shield me from this pain.

How much space does the SVG have to grow?

There are a few abstractions to consider when working out how much space is available to scale an SVG document.

Make any SVG responsive with this React component - LogRocket Blog (2)

Browser viewport

The browser viewport is the visible area of a web page.

SVG viewport

The SVG viewport is analogous to the browser’s viewport only it is the visible area of an SVG document. An SVG document can be as high and wide as you want, but only part of the document can be visible at one time.

We want to avoid hardcoded width and height attributes like in the example below because they cannot adapt to the multitude of devices that might be viewing this document:

export const App: React.FC = () => ( <svg width="1000" height="1000"> <rect x="20%" y="20%" width="1000" height="1000" rx="20" style={{ fill: '#ff0000', stroke: '#000000', strokeWidth: '2px' }} /> <rect x="30%" y="30%" width="1000" height="1000" rx="40" style={{ fill: '#0000ff', stroke: '#000000', strokeWidth: '2px', fillOpacity: 0.7 }} /> </svg>);

The above component renders this document:

Make any SVG responsive with this React component - LogRocket Blog (3)

The above SVG document of 2 <rect/> elements is larger than the SVG viewport, and because of this, only part of it is visible.

A magical attribute called the viewBox is the answer to a lot of our SVG responsive needs.

viewBox and coordinate systems

The definition from mdn for the viewBox attribute is:

The viewBox attribute defines the position and dimension, in user space, of an SVG viewport.

I don’t know about you, but I had more questions than answers when I first read that. What on earth is user space?

If you have sat maths to any level, then you will have come across euclidean space with the classic x and y axes:

Make any SVG responsive with this React component - LogRocket Blog (4)

SVG coordinate space is different because the point (0, 0) is at the top left-hand corner and not the center.

If we add a viewBox attribute to the SVG that was created earlier, then we can regain control of the sizing of the SVG viewport:

export const App: React.FC = () => ( <svg preserveAspectRatio="xMaxYMid meet" viewBox="0 0 529 470"> <rect x="20%" y="20%" width="1000" height="1000" rx="20" style={{ fill: '#ff0000', stroke: '#000000', strokeWidth: '2px' }} /> <rect x="30%" y="30%" width="1000" height="1000" rx="40" style={{ fill: '#0000ff', stroke: '#000000', strokeWidth: '2px', fillOpacity: 0.7 }} /> </svg>);

The two <rect/> elements are now smaller than the SVG viewport thanks to this magical attribute.

Over 200k developers use LogRocket to create better digital experiencesLearn more →

Make any SVG responsive with this React component - LogRocket Blog (7)

viewBox math

Below is an example of a viewBox attribute:

viewBox="-200 -100 3000 400"

The magical four numbers in the attribute can shrink or expand the elements and transform their position. But how?

The viewBox does a lot with very little, such as:

  • It defines the aspect ratio of the image
  • It defines how all the lengths and coordinates used inside the SVG should be scaled to fit the space available
  • It defines the origin of the new coordinate system

I like to remember the initial four values like this:

viewBox="minX minY width height"

A new set of coordinates are copied from the existing SVG viewport coordinates with the addition of the viewBox. This new set of coordinates is known as a user space. The mdn cryptic explanation mentioned this:

The viewBox attribute defines the position and dimension, in user space, of an SVG viewport.

The first two values of the viewBox are -200 and -100, and these values will shift the image right and down from the top-left origin:

<svg width="500px" height="100px" viewBox="-200 -100 3000 400">

The last two values, 3000 and 400, allow us to zoom into or away from our SVG image.

The SVG element has a width of 500px and a height of 100px. With the addition of the viewBox attribute, a new user coordinate system of 3000 units and 400 hundred units vertically is at our disposal.

The new user space maps to the viewport coordinate system, and 1 unit of the new space is equal to this calculation:

height = SVG viewport height ÷ viewBox height verticallywidth = SVG viewport width ÷ viewBox width horizontally

Make any SVG responsive with this React component - LogRocket Blog (8)
The viewBox on its own will not cure all our responsive needs. We cannot use hardcoded values in the real world. We need to get new values when the component is mounted, or it resizes.

Responsive SVG

Below is my ResponsiveSVG component from my very own @cutting/svg package:

export function ResponsiveSVG<E extends HTMLElement = HTMLElement>({ elementRef, children, preserveAspectRatio = 'xMinYMin slice', innerRef, className, options = {},}: PropsWithChildren<ParentsizeSVGProps<E>>): JSX.Element | null { const { width, height } = useParentSize(elementRef, options); const aspect = width / height; const adjustedHeight = Math.ceil(width / aspect); return ( <div data-selector="cutting-svg-container" style={{ position: 'relative', overflow: 'visible', height: '1px', }} > <svg style={{ overflow: 'visible' }} className={className} preserveAspectRatio={preserveAspectRatio} viewBox={`0 0 ${width} ${adjustedHeight}`} ref={innerRef} > {children} </svg> </div> );}

The above component makes use of my useParentSize hook that uses a ResizeObserver to watch for changes in a container <div/> element. Any time a change of dimensions happens in the target <div />, a resize event raises new width and height values and the component will re-render in terms of these new values.

To ensure our SVG element keeps its shape at different sizes, we need to calculate its height in terms of its width. This proportional relationship is known as the aspect ratio.

Aspect ratio

Aspect ratio is the ratio of width to height of an image on a screen.

A square image has an aspect ratio of 1:1. An image that is twice as tall as it is wide has an aspect ratio of 1:2.

The calculation for the adjusted height is:

const aspect = width / height;const adjustedHeight = Math.ceil(width / aspect);

These values help us complete the viewBox:

<svg style={{ overflow: 'visible' }} className={className} preserveAspectRatio={preserveAspectRatio} viewBox={`0 0 ${width} ${adjustedHeight}`} ref={innerRef}>

The preserveAspectRatio attribute

The viewBox attribute has a sidekick, preserveAspectRatio. It does not have any effect unless the viewBox exists. The preserveAspectRatio describes how an SVG document should scale if the aspect ratio of the viewBox does not match the aspect ratio of the viewPort. Most of the time, the default behavior works, which is:

preserveAspectRatio="xMidYMid meet"

xMidYMid meet is a bit like the CSS rule background-size: contain;. A slice value will scale the image to fit the more generous dimensions and slice off the extra.

preserveAspectRatio="xMidYMid slice"

The slice value is analogous to the overflow: hidden CSS rule.

Make any SVG responsive with this React component - LogRocket Blog (9)

Epilogue

With my ResponsiveSVG component, I am armed and ready for any device userland can throw at me, and below is how it looks when I resize my browser to something minimal:

Make any SVG responsive with this React component - LogRocket Blog (10)

Get set up with LogRocket's modern React error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to getan app ID
  2. Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, notserver-side

    • npm
    • Script tag
    $ npm i --save logrocket // Code:import LogRocket from 'logrocket'; LogRocket.init('app/id'); 
    // Add to your HTML:<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script><script>window.LogRocket && window.LogRocket.init('app/id');</script> 
  3. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • NgRx middleware
    • Vuex plugin

Get started now

Make any SVG responsive with this React component - LogRocket Blog (2024)
Top Articles
ASUSTOR NAS - How to enable or disable TLS 1.3 in Windows 10?
Aggressive Behavior: Signs, Causes, and Treatment
Star Wars Mongol Heleer
Nybe Business Id
Roblox Roguelike
Tv Guide Bay Area No Cable
7.2: Introduction to the Endocrine System
Owatc Canvas
Obituary Times Herald Record
Ap Chem Unit 8 Progress Check Mcq
Morocco Forum Tripadvisor
Transfer Credits Uncc
Chic Lash Boutique Highland Village
Kris Carolla Obituary
Suffix With Pent Crossword Clue
Vrachtwagens in Nederland kopen - gebruikt en nieuw - TrucksNL
CDL Rostermania 2023-2024 | News, Rumors & Every Confirmed Roster
Hennens Chattanooga Dress Code
Vigoro Mulch Safe For Dogs
Craigslist Appomattox Va
Epguides Strange New Worlds
Grimes County Busted Newspaper
Wemod Vampire Survivors
Best Nail Salons Open Near Me
Reborn Rich Kissasian
Conscious Cloud Dispensary Photos
E32 Ultipro Desktop Version
Barista Breast Expansion
Meta Carevr
Downtown Dispensary Promo Code
Tottenham Blog Aggregator
Turns As A Jetliner Crossword Clue
Himekishi Ga Classmate Raw
Promatch Parts
Devotion Showtimes Near The Grand 16 - Pier Park
Jt Closeout World Rushville Indiana
Bernie Platt, former Cherry Hill mayor and funeral home magnate, has died at 90
Craigslist Gigs Norfolk
The Wichita Beacon from Wichita, Kansas
Texters Wish You Were Here
Darrell Waltrip Off Road Center
Closest 24 Hour Walmart
Family Fare Ad Allendale Mi
What Does Code 898 Mean On Irs Transcript
56X40X25Cm
How to Connect Jabra Earbuds to an iPhone | Decortweaks
Nope 123Movies Full
Take Me To The Closest Ups
How to Find Mugshots: 11 Steps (with Pictures) - wikiHow
Quest Diagnostics Mt Morris Appointment
Ret Paladin Phase 2 Bis Wotlk
Nfl Espn Expert Picks 2023
Latest Posts
Article information

Author: Arielle Torp

Last Updated:

Views: 5872

Rating: 4 / 5 (41 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Arielle Torp

Birthday: 1997-09-20

Address: 87313 Erdman Vista, North Dustinborough, WA 37563

Phone: +97216742823598

Job: Central Technology Officer

Hobby: Taekwondo, Macrame, Foreign language learning, Kite flying, Cooking, Skiing, Computer programming

Introduction: My name is Arielle Torp, I am a comfortable, kind, zealous, lovely, jolly, colorful, adventurous person who loves writing and wants to share my knowledge and understanding with you.