Google Lighthouse and SVGs with preserveAspectRatio="none" - svg

Google Lighthouse has a red triangle error which significantly impacts the Best Practices score:
Displays images with incorrect aspect ratio
I can understand why this would be regarded as an error with fixed-dimension raster images (and also with standard SVG vector images with explicitly set dimensions).
But in this case I'm displaying a small number of SVG flags on a webpage and the SVG flags display with certain dimensions in one part of the page and different dimensions in another part.
To enable using the same single SVG even when multiple instances of that SVG display with different dimensions, I use the attribute:
preserveAspectRatio="none"
This explicitly means (I would hope) that there is no incorrect aspect ratio.
But Google Lighthouse raises the error above, nevertheless.
At normal desktop browser size the graphics are quite small (either 27px x 27px or 27px x 18px) so, yes, I could potentially replace them with .png or .webp images.
But then I'd also need to bear in mind that the flag-image dimensions also increase in size very slightly at narrower responsive design breakpoints, so I would need a full set of fixed-dimension raster images for each breakpoint.
Is there any way I can instruct Google Lighthouse to ignore aspect ratio for SVG images which explicitly state preserveAspectRatio="none"?

Lighthouse reports the error:
Displays images with incorrect aspect ratio
precisely because the SVG includes the preserveAspectRatio="none" attribute.
In two specific contexts:
the SVG has no viewBox attribute
the SVG includes the preserveAspectRatio="none" attribute
the intrinsic dimensions of the SVG default to standard replaced element dimensions:
300px x 150px.
This gives the SVG an intrinsic aspect ratio of 1:2.
At this point, if the SVG is displayed on a webpage with a different aspect ratio, Lighthouse will report the error above.
Including the viewBox attribute
Otherwise, the viewBox attribute will determine the intrinsic dimensions and intrinsic aspect ratio of the SVG.
Like any other <img>, the SVG may be styled via CSS to have any width and any height. But the aspect ratio resulting from these values must be identical to the intrinsic aspect ratio determined by the SVG's viewBox.
Hence, an SVG can have a CSS width and height which scale it infinitely upwards or infinitely downwards - but they cannot alter the shape of the SVG as defined by the viewBox.
If the CSS values change the shape of the SVG, Lighthouse will will report the error above.
Conclusions
To avoid the Lighthouse error above:
The SVG must have a viewBox attribute
The SVG may not use preserveAspectRation="none"
the CSS width vs height aspect ratio and the SVG viewBox aspect ratio must match
Also note:
Declaring the CSS property aspect-ratio or HTML width and height attributes will not help in this situation. Neither CSS nor HTML are capable of overriding the intrinsic dimensions established by the SVG viewBox.
Example:
If you have an SVG with
viewBox="0 0 360 360"
then, using CSS, you can display that SVG as an at any size as long as it maintains an aspect ratio of 1:1.
E.g.
width: 24px; height: 24px;
width: 36px; height: 36px;
width: 48px; height: 48px; etc.
But, should you wish to style the same SVG-based <img> with a different aspect ratio:
width: 36px; height: 24px; // aspect ratio of 3:2
then you must create a new SVG with a viewBox which establishes an aspect ratio consistent with the CSS values:
viewBox="0 0 540 360"
if you don't want Lighthouse to report an incorrect aspect ratio error.

Related

How do I get svg vmin right?

According to the standards I'm reading -- for example https://www.w3.org/TR/css-values-4/#viewport-relative-lengths -- a vmin unit should be 1% of the smallest dimension of the containing viewport.
Going for a minimal example illustrating my dilemma, this is square in my current instance of chrome:
<svg><rect height="30vmin" width="30vmin" fill="red">
But this is not:
<svg><rect height="50vmin" width="50vmin" fill="red">
Playing with variations on this theme (closing tags, adding width and height to the svg element, etc.) suggests that the rect is not using the svg viewport as its reference, but instead is using some containing browser context as its reference viewport.
So, my question is: how do I specify to the browser that I want vmin units to refer to the innermost containing svg viewport? (Specifically when working with svg elements embedded in html documents.)
Browser support for those units that were added in CSS3 may still be spotty. I haven't checked recently.
But the rule is that these units are resolved relative to the whole document. So in a browser, that will be the whole browser window.
This SVGWG issue may help clarify things.
https://github.com/w3c/svgwg/issues/207
how do I specify to the browser that I want vmin units to refer to the innermost containing svg viewport?
You can use percentage values for coordinates,
<rect height="50%" width="50%" fill="red">
However in SVG, percentage values are always relative to their associated axis. So percentage width values are relative to the X axis, and percentage height values are relative to the Y axis.
Alternatively you could use a suitable viewBox and appropriate coordinate values relative to that viewBox. For example, if your viewBox has a width and height of 100:
viewBox="0 0 100 100"
All coordinates values in the SVG would effectively be percentage values. However the same axis rule applies as described above.
svg {
width: 200px;
background-color: linen;
}
<svg viewBox="0 0 100 100">
<!-- rectnagle 50% x 33.3% -->
<rect width="50" height="33.3"/>
</svg>

How to adjust the resizing of a SVG?

I need some help to figure out how I can adjust the resizing of an SVG graphic when displayed on my web page.
Here are joined 2 screenshots of the graphics, one shows the graphics on a desktop wide screen, and the other on a smartphone
My problem is the graphics are too small on the smartphone. How can I make it bigger? I didn't anything about the responsiveness of this graphics, just the plain SVG in my web page. So I guess something can be made but I don't know what exactly.
Here is the beginning of the SVG graphics:
<svg viewbox="0 0 1920 632" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet">
<title>graphics</title>
<g style="isolation:isolate">
<g data-name="before animation starts" id="0482fa28-2c72-43bc-8627-b57f09f318d3">
<path id="main-oval" class="main-oval" d="M1354.63,260.62C1338.38,142.2,1144.68,71,922,101.54c-109.4,15-205.35,51.8-272.82,99.38-69.92,49.26-109.23,110-101,170.29,16.31,118.42,210,189.59,432.62,159.07,110.79-15.17,207.86-52.73,275.44-101.15C1324.59,380.18,1362.8,320.12,1354.63,260.62Z" data-name="oval"></path>...
Thanks
Attribute names in SVG are case-sensitive. So viewbox should be viewBox.
It is possible that there are other things wring, but I can't tell without seeing the complete SVG file.
Because your SVG has a viewBox attribute without a width and height attribute it is by default responsive and will scale to fit it's parent container.
In the case of your mobile view, it is the parent container that is restricting the size rather than anything in your SVG. Try inspecting the width, margin and padding of the parent container to ensure it is 100% wide and your SVG will scale to suit.
If the SVG is still not quite legible after that you will need to modify the graphic using CSS media queries to scale and transform specific elements. That is beyond the scope of the question so I won't go into it here.

Defining viewport and viewbox in SVG to scale shapes with physical real world units

I am confused how to properly define viewport and viewbox in SVG file to convey shapes that have real world physical units.
I am mapping my AutoCAD design to a SVG file. The units in my AutoCAD file are defined in millimeters (mm). Image below shows my AutoCAD design. The orange box (16mm x 9mm) are my boundaries for visible part of the SVG file, thus anything outside the orange box will get cut off. My end application requires a PNG image that is a specific resolution, 1920x1080. (Notice how the aspect ratio is the same).
In my SVG file, all shapes (elements) are defined without units, however I know the values are in millimeters in the physical world. For example, below is an example of a circle. The radius of the circle is 0.474mm as set in the AutoCAD file.
<circle cx="1.22996130982" cy="2.27139057943" r="0.474" />
My question is, how do I properly define the viewport and viewbox in my SVG file? How do I properly define the viewport/viewbox such that the physical units in real world get scaled to fit in my desired image resolution?
I used the following method below to define my viewport/viewbox. However, this approach did not work. The resulting SVG image was a canvas of 1920x1080 however all my shapes were very tiny and it did NOT cut off the shapes desired outside the orange boundary box.
<svg width="1920px" height="1080px" viewbox="0 0 16mm 9mm">
<circle cx="1.22996130982" cy="2.27139057943" r="0.474" />
<!-- Other shapes in SVG here-->
</svg>

SVG viewBox breaks 100% fill of viewPort while preserving aspect ratio

Q: How can I use the viewBox coordinate system whilst still filling the viewPort completely and preserving aspect ratio?
I'm new to svg programming, so hopefully I'm just mis-understanding a basic concept.
I want to create an interactive & responsive map with , based on a background image that the user uploads.
Here's the basic example I'm trying to get to work (JSFiddle):
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="200px"
height="400px"
preserveAspectRatio="xMidYMid meet"
style="border: 1px solid black;">
<image x="0" y="0" width="100%" height="100%"
preserveAspectRatio="xMidYMid meet"
xlink:href="http://www.bized.co.uk/sites/bized/modules/bized_cb_navigation/images/floorplan_info.gif">
</image>
</svg>
This works nicely. since however the viewPort changes, the image always fills it whilst maintaining its aspect ratio. (See wide-Screen example)
Next I add a coordinate system viewBox="0 0 100 100":
the wide-screen view still fills nicely
but the vertical-screen view now does not fill the viewPort anymore
If you take a different image that is wider than tall, then the wide-screen view breaks, and the vertical-screen view still works.
When I inspect the SVG in Chrome DOM Element inspector, for the first two examples without using viewBox="0 0 100 100" The svg element has the same size as the viewPort. Once the viewBox attribute is added, the element becomes a square with sides equal to the lesser of the viewPort's sides.
This behavior is explained in this Tutorial as:
"... the view box is scaled according to the smaller of the two aspect ratios..."
I need the viewBox attribute so that I can zoom and pan on the image within the viewPort.
This is because you effectively have two competing viewBox transformations.
Because of your square viewBox, you are fitting the image into a square, and then fitting the square into your SVG rectangle.
If you make your SVG viewBox the same dimensions as your image (or the same aspect ratio will do), then the problem will be resolved.
viewBox="0 0 155 210"
http://jsfiddle.net/2qexypLs/15/
http://jsfiddle.net/2qexypLs/16/
My current solution is to use JavaScript to dynamically set the viewBox width and height values to the same value as svg width and height values. That way the aspect ratio for x and y are the same and the fill returns to 100% of viewPort. (JsFiddle)
For the interactive elements layer of the map I have a separate coordinate system that is mapped to the background image scaling ratio when the svg viewPort is defined. That means all coordinates need to be recalculated on svg define/change width/height event.
After this first re-calculation, the map can be zoomed and panned by changing the viewBox parameters without any further calculations.

svg viewbox scaling issue

I've a question about svg's viewbox, in my opinion it's like a window on an infinite svg plan, and its boundaries are set in the viewBox attribute of the svg element. It represents the rectangle between the 2 coordinates in the svg plan. So a viewBox of "0 0 1000 500" shows the window between (0,0) and (1000,500) of the svg plan.
And when I make viewBox (2000, 0, 3000 500) i see the window of (2000,0) and (3000,500). x and y scaling is unmodified: in both cases i'm displaying 1000 * 500 units of the svg plan.
But apparantly i go wrong some where. I'm experimenting with animating the viewbox to emulate some kind of ticker display, leaving the y coordinates untouched but changing the x coordinates (without changing the actual number of units displayed) but that goes wrong. Somehow my y-scaling changes.
In a modern browser you can verify yourself (pull the slider to change the viewBox).
What did I miss in the SVG specification?
You missed the preserveAspectRatio attribute in the SVG specification. It forces the aspect ratio of what you see in the viewbox to be preserved by default. Sounds like what you're after is preserveAspectRatio="none"

Resources