svg / svgo

⚙️ Node.js tool for optimizing SVG files
https://svgo.dev/
MIT License
20.61k stars 1.38k forks source link

What is the benefit of stripping viewBox? #1128

Closed avwie closed 1 month ago

avwie commented 4 years ago

Some libraries use SVGO for optimizing the SVG and I notice that stripping the viewBox is almost always used. However, I always disable stripping because it breaks proper scaling of the SVG. Unless I totally don't understand, what is the 'optimization' that stripping a viewBox provides?

GreLI commented 4 years ago

Just as any stripping—minimize number of bytes, increase informational density.

avwie commented 4 years ago

According to your readme:

SVG files, especially those exported from various editors, usually contain a lot of redundant and useless information. This can include editor metadata, comments, hidden elements, default or non-optimal values and other stuff that can be safely removed or converted without affecting the SVG rendering result.

Removing viewBox definitely affects the rendering result, since scaling is then made almost impossible. The question is, why is it turned on by default? It isn't simple meta-data, it is critical viewport information.

GreLI commented 4 years ago

Why? It's removed only when width and height attributes are present and equal to, so no information is lost. Finally, one can turn it off if needed.

robertknight commented 4 years ago

Removing viewBox still affects the rendering output when width and height are present and viewBox is equal to 0 0 <width> <height>.

I encountered this issue when an upgrade to svgo broke rendering of some scaled inline SVGs on our website (https://github.com/hypothesis/h/issues/5656).

The SVGs in question had an outer <svg> element like this:

<svg xmlns="http://www.w3.org/2000/svg" width="120" height="120" viewBox="0 0 120 120">
…
</svg>

And were being rendered with a CSS class applied that scaled them down to a much smaller size (eg. 16px x 16px).

GreLI commented 4 years ago

@robertknight that's incorrect usage, nothing to do with SVGO. Of course if you rewrite width and height, you'll get an error, no matter in which way.

robertknight commented 4 years ago

Please excuse the stupid question, but can you explain what you mean by incorrect usage? My understanding is that viewBox specifies the user-space coordinates which are then mapped to the viewport which has a default width and height controlled by the corresponding attributes on the <svg>, but can be overridden using CSS to rescale the image.

FWIW the original SVG file was produced some time ago by a designer using Sketch.

GreLI commented 4 years ago

SVG is an image which may have properties like width and height. Without viewBox attribute it has value equal to 0 0 width height. So if you change size in any way, you have corresponding result. SVG highly depends on the usage way, so do optimizations. That's is why SVGO is highly configurable.

flogy commented 4 years ago

I have also encountered an issue with this in IE11 as described by someone else here: https://stackoverflow.com/questions/27970520/svg-with-width-height-doesnt-scale-on-ie9-10-11.

When I add the viewBox property with 0 0 width height value it worked fine.

I know we can enable/disable the related plugins to not strip viewBox ourselves but wouldn't it be worth thinking about not stripping the property by default in order to avoid those issues?

drewbaker commented 4 years ago

Just ran into this with SVGO defaults. Seems crazy that by default you break SVG scaling using CSS.

// This won't scale using CSS. This is the default.
<svg xmlns="http://www.w3.org/2000/svg" width="21.001" height="13">

// This will scale using CSS, this is better and should be default.
<svg xmlns="http://www.w3.org/2000/svg" width="21.001" height="13" viewBox="0 0 21.001 13">
jdahdah commented 4 years ago

The viewBox needs to be preserved for inline <svg> elements in HTML to properly scale. Leaving out the viewBox breaks this behavior. I don't know enough about the SVG specification to say if it's supposed to default to viewBox="0 0 width height" or not, but the fact is that this issue is present in the latest versions of Chrome, Firefox and Safari. SVGs need to be inlined for a number of common use-cases, usually for changing colors on hover states or different themes like dark mode.

The fact that SVGO is so configurable is really awesome, but many apps like Image Shrinker use the default settings and don't offer options, ultimately breaking SVGs for anyone wanting to scale them inline.

Please see this CodePen: https://codepen.io/dahdah/pen/YzyjRaw This is a very simple SVG run through Image Shrinker. I've restored the viewBox in one of the copies.

Screenshot:

SVGs with and without viewBox

Please reconsider changing the default value of removeViewBox to false. It's a few bytes more with a significant improvement for web developers on a wide range of tools. And finally, to reiterate on what @rj-coding said:

SVG files, especially those exported from various editors, usually contain a lot of redundant and useless information. This can include editor metadata, comments, hidden elements, default or non-optimal values and other stuff that can be safely removed or converted without affecting the SVG rendering result.

The above example shows pretty clearly that this setting does indeed affect the rendering result, and is not in line with what the SVGO readme promises.

drewbaker commented 4 years ago

@GreLI are you prepared to reconsider this?

kylirh commented 3 years ago

Please change this. I spent a couple hours today digging around to figure out what's going on. The current default is super annoying...

Naxit commented 3 years ago

Same for me, the most used case is scalable svgs that doesn't broke with css. I'm here because I have to modify this weird default behavior and I needed to know how to do it, I see I'm not the only one in this case^^ @GreLI Please reconsider this <3

mahnunchik commented 3 years ago

The same issue...

mahnunchik commented 3 years ago

@GreLI Why this and https://github.com/svg/svgo/issues/505 issues are closed?

Naxit commented 3 years ago

I used the --icon prop that set '1em' to height and width and keep the viewbox, if this can help someone... It did the job for me but it's a weird workaround^^

My package.json command line look like this : build:svg": "svgr --icon --ignore-existing (...more stuff...)",

woodreamz commented 3 years ago

I also agree with you, viewBox is very important for the scaling specially for web developper. In previous versions of svgo, removeViewBox was false by default. You should reconsider setting this option to false by default.

JohnAlbin commented 3 years ago

Given this discussion, I created a PR to remove this plugin from the list of default plugins. #1461

In the meantime, this is the svgo.config.js I am using on my website:

const { extendDefaultPlugins } = require('svgo');

module.exports = {
  multipass: true,
  plugins: extendDefaultPlugins([
    // viewBox is required to resize SVGs with CSS.
    // @see https://github.com/svg/svgo/issues/1128
    {
      name: 'removeViewBox',
      active: false,
    },
  ]),
};
lzl124631x commented 2 years ago

@GreLI viewBox is such an important field needed for scaling SVG images. I'm surprised that we remove it by default just for the sake of "minimizing number of bytes". Let's get https://github.com/svg/svgo/pull/1461 in.

JohnAlbin commented 2 years ago

I've updated PR #1461 to fix a merge conflict.

Now that extendDefaultPlugins has been deprecated, this is the svgo.config.js I am using on my website:

module.exports = {
  multipass: true,
  plugins: [
    {
      name: 'preset-default',
      params: {
        overrides: {
          // viewBox is required to resize SVGs with CSS.
          // @see https://github.com/svg/svgo/issues/1128
          removeViewBox: false,
        },
      },
    },
  ],
};
GreLI commented 2 years ago

I understand the issue, sometimes 'viewBox' is really valuable, but it's not a good idea to dictate disabling default optimization by minority of users. Most users are ok with it and they just don't write here, it's totally ok for them. Probably it's a good idea to disable the plugin in some super-safe preset.

bencresty commented 2 years ago

Working daily with svgs intensively I agree very much with above comments: It's great that svgo is configurable and that we can decide ourselves to enable or disable the stripping of the viewBox attributes. But IMO the most logical setting for this is to NOT stip this setting by default. It just breaks the scaling for lots of svg's. I'm clearly not the only one who thinks like this.

sometimes 'viewBox' is really valuable, but it's not a good idea to dictate disabling default optimization by minority of users

I don't agree at all. The attribute is valuable most of the time, not 'sometimes'. Users who don't complain about this are probably users who either don't use svgo, don't take the time to post a message here, only work with simple svg stuff in an image tag or perhaps even don't know how svg works and that something like a viewBox exists.

GreLI commented 2 years ago

The attribute is valuable most of the time…

While most users

…only work with simple svg stuff…

Don't you see a contradiction here?

It's impossible to conform everyone. Unless you're doing nothing. But that will raise a question too.

jdahdah commented 2 years ago

I understand the issue, sometimes 'viewBox' is really valuable, but it's not a good idea to dictate disabling default optimization by minority of users. Most users are ok with it and they just don't write here, it's totally ok for them. Probably it's a good idea to disable the plugin in some super-safe preset.

With respect, @GreLI, I don't understand your conclusion. One should not need a separate preset to preserve the original behavior of the file. We continue to circle around this topic but at the end of the day, the behavior of SVGO is inconsistent with the promises made in the README. SVGs optimized with SVGO behave differently in browsers from SVGs that have not been optimized. It's destructive, as has been demonstrated in multiple comments above, code samples, PR explanations, etc.

Again, this is what the README says:

SVG files, especially those exported from various editors, usually contain a lot of redundant and useless information. This can include editor metadata, comments, hidden elements, default or non-optimal values and other stuff that can be safely removed or converted without affecting the SVG rendering result.

Not affecting the rendering result is a core feature of SVGO. Removing viewBox affects the rendering result in browsers. Why is this point being ignored?

GreLI commented 2 years ago

Perhaps readme should be updated. SVGO mostly optimize without a visible affect on rendering result. One of the most effective optimizations is reducing float numbers precision. Usually, one will not notice a change. However, it can be seen with extreme zoom. Again, it's not a problem in most cases.

But it's an offtopic. Removing viewBox doesn't affect rendering since an image has dimensions (otherwise it's kept as is). Intervening with this dimensions affects the rendering, not removing attribute itself. So, this is pro-usage like editing tool, which is minority of SVGO usage. I'm afraid people here don't get my point, because they don't like it.

woodreamz commented 2 years ago

Perhaps readme should be updated. SVGO mostly optimize without a visible affect on rendering result. One of the most effective optimizations is reducing float numbers precision. Usually, one will not notice a change. However, it can be seen with extreme zoom. Again, it's not a problem in most cases.

But it's an offtopic. Removing viewBox doesn't affect rendering since an image has dimensions (otherwise it's kept as is). Intervening with this dimensions affects the rendering, not removing attribute itself. So, this is pro-usage like editing tool, which is minority of SVGO usage. I'm afraid people here don't get my point, because they don't like it.

You are wrong, removing the viewBox affects rendering. Please read the viewBox documentation on mozilla and check the example, it's the same svg used three times with three different viewBox, I let you check the result.

Another example was previously shared in the comment https://github.com/svg/svgo/issues/1128#issuecomment-628208565

That's being said, I don't understand why you don't want to reconsider the default value of viewBox, you seems to be stuck on your position but it's your choice and we will live with it :v:.

lzl124631x commented 2 years ago

Removing viewBox doesn't affect rendering since an image has dimensions

I think it affects a lot? If we inline an SVG file and scale it using CSS, the SVG has to have a viewBox property to get properly scaled?

Example: https://codepen.io/lzl124631x/pen/jOwbPXv

SVG = Scalable Vector Graphics and removing the viewBox makes it UNscalable. Maybe we can rename svgo to vgo?

GreLI commented 2 years ago

You are wrong, removing the viewBox affects rendering. Please read the viewBox documentation on mozilla and check the example, it's the same svg used three times with three different viewBox, I let you check the result.

Nope. It has nothing with the issue. Please read all I wrote carefully and thoughtfully.

woodreamz commented 2 years ago

You are wrong, removing the viewBox affects rendering. Please read the viewBox documentation on mozilla and check the example, it's the same svg used three times with three different viewBox, I let you check the result.

Nope. It has nothing with the issue. Please read all I wrote carefully and thoughtfully.

Haha, I read correctly 😄 And you just confirmed that you seems to be stuck on your position...

I'm giving up, no matter how we (not only me) show/explain/demonstrate you that viewBox affects the rendering, you still disagree...

drewbaker commented 2 years ago

@woodreamz I support you. You're correct. Anyone who's tried to actually build a website and scale an SVG knows what you're asking for is correct.

flogy commented 2 years ago

I agree as well, as I have posted about this 2 years ago because of rendering issues I experienced in browsers when using the default settings.

I believe the quality/usability improvement this change would provide to SVGO is much bigger than a couple extra bytes of file size in optimized SVGs.

avwie commented 2 years ago

I can't believe we are 2,5 years later after I filed this issue and after multiple people supporting my position nothing has changed including the arguments.

Rendering behavior > stripping bytes.

And if you think viewBox does not appear to affect rendering behavior then you clearly don't understand the varied use-cases of SVG's. Saying that 'an image has dimensions' clearly shows you have no clue what a viewBox does. And calling it a 'pro-usage' editing tool is absolutely not true.

mmcgahan commented 2 years ago

@GreLI please consider approving #1461. I'm sure it's clear that having a viewBox with matching width & height values meets the following criteria for changing the default:

1) it is allowed by the SVG spec linked from the code

  1. browsers will apply different rendering rules based on the presence/absence of viewBox
  2. CSS sizing is commonly applied, and frequently preferred over hard-coding pixel values in HTML
  3. The default configuration should produce a result that is visually indistinguishable from copy-pasting the original SVG element directly into the HTML

We know that some information is lost by removing the viewBox and we know that sizing images using CSS is common (and recommended) practice. At the moment, it sounds like the claim is that the SVGO maintainers are okay with compromising that usage for the benefit of saving ~20 bytes from the processed output of each element, which doesn't seem right.

nicmare commented 2 years ago

I've updated PR #1461 to fix a merge conflict.

Now that extendDefaultPlugins has been deprecated, this is the svgo.config.js I am using on my website:

module.exports = {
  multipass: true,
  plugins: [
    {
      name: 'preset-default',
      params: {
        overrides: {
          // viewBox is required to resize SVGs with CSS.
          // @see https://github.com/svg/svgo/issues/1128
          removeViewBox: false,
        },
      },
    },
  ],
};

i think the issue is solved if you just create your own config file. this is my svgo.config.js in Application Support / com.bohemiancoding.sketch3 / Plugins:

module.exports = {
  plugins: [
    {
      name: 'preset-default',
      params: {
        overrides: {
            removeViewBox: false,
            cleanupIDs: {
                prefix: {
                    toString() {
                        return `${Math.random().toString(36).substr(2, 9)}`;
                    }
                }
            }
        },
      },
    },
  ],
};

it keeps viewbox and creates unique ids if you have many complex inline svgs on one page

mosesoak commented 2 years ago

@GreLI here's a real world example:

Before using SVGO: image

After, with default settings: image

In the past I've been really pleased with the smart decisions SVGO makes in that I almost never have to tweak the default settings and will always get a lot of value out of it. However, SVGs are notoriously hard to size, and viewBox definitely has an affect on how they render as shown here, so I'm agreeing with the crowd here that it should be retained by default. Users who are shooting for aggressive filesize reduction would still be able to change the setting, knowing that it might visually break some things, but even they won't see a very noticeable change from this short string, even across many SVGs.

Appreciate your work, SVGO is invaluable. Thanks for considering changing this default!

jakebraun commented 2 years ago

Just wanted to jump in and write on this issue, because I just learned the hard way we are using this library via another library with Webpack. It looks like an amazing library, and we would definitely use it in the future for projects with more complex SVG optimization needs.

But for now, we had some malformed SVGs and spent quite a bit of time trying to determine why they are broken only on production. I don't know much about the internals of SVGs. But after googling, I found this page, our problem, and our solution.

Not sure who's right on this issue. But if I didn't get lucky with my google search, I may have never found this library. It may be worth considering that an SVG novice (like me) may also not know they have an issue or where to comment when they do.

Hulkmaster commented 2 years ago

i also want to add that removing viewbox breaks default svg behaviour, basically scaling

with viewbox changing width/height results in scaled SVG without viewbox svg persists in corner of the whole svg

hjoelh commented 2 years ago

https://github.com/scriptex/svgo-add-viewbox looks good

Hulkmaster commented 2 years ago

thats unnecessary

you can just disable removing viewbox

(vite config)

    svgLoader({
      svgoConfig: {
        plugins: [
          {
            name: 'removeViewBox',
            active: false,
          },
        ],
      },
    }),
avwie commented 2 years ago

But the issue is that not every consumer of SVGO allows modifying the SVGO config. And the default behavior of removing viewBox is wrong.

oetiker commented 2 years ago

if you want to keep the presets ... try this:

svgoOptions: {
    plugins: [
         {
            name: "preset-default",
            // while https://github.com/svg/svgo/pull/1461
            // is not fixed.
            params: {
                overrides: {
                   removeViewBox: false,
                }
            }
         },
    ]
}
Jessidhia commented 1 year ago

Stripping a viewBox is always incorrect and, in effect, corrupts the SVG data; the viewBox is what specifies the size of the internal coordinate system and is what is referred to by all of the elements inside the SVG tag.

If it's missing the browser/viewer will synthesize a viewBox based on the element size, but the element size does not necessarily match the width/height attributes on the element (e.g. overridden by CSS), and it will make the "scalable" vector graphics, well, not scale at all: it causes the content to be drawn anchored to the top left corner and will be cropped if it doesn't fit.

The only case where it appears correct is when the element is displayed at exactly its intrinsic size (the width/height attributes). Browsers will synthesize a missing width/height from the viewBox and use it as the intrinsic aspect ratio, but they will also expand the SVG to fit all available space, so removing (both) width and height is also not 100% safe.

The safest default would be to preserve both viewBox and (one of) width or height; possibly with an option to strip both width and height if they match the viewBox to make the SVG expand-to-fit. Stripping viewBox instead corrupts the SVG data.

Jessidhia commented 1 year ago

it's not a good idea to dictate disabling default optimization by minority of users. Most users are ok with it and they just don't write here

Also, sorry for my tone, but this is just a headcanon. These "most users" who are "ok with it" are speculative and is impossible to prove correct or incorrect. The users who have been posting on this issue, however, are quantifiable, and the actual arguments placed can be evaluated on the actual arguments' merits.

And two can play the headcanon game: there's also the "most users" who stumble upon this problem and don't comment because someone else has already commented, or who are able to change their config to disable removeViewBox, or who manually edit their svg to dodge the rule, and those who won't even be affected by changing the default as the extra ~20 bytes before gzip are a tiny fraction of each non-trivial svg and will practically disappear after compression.

mangelozzi commented 1 year ago

@GreLI Please see this code snippet here on stack overflow, the SVG can't be scaled without the viewbox, the solution to the problem, is to add the viewport back. SVG stands for Scalable Vector Graphics. Without the viewport is is just VG. Should be called VGO.

It's like saying here's a car, we took the gearbox out by default because I just like to sit in my car and run the aircon, its more efficient not having the gearbox.

A very common task for scalable vector graphics is scaling them. If we never needed to scale them, one might as well use a PNG.

GreLI commented 1 year ago

@mangelozzi you missed the point. If you change size of SVG, you are essentially editing it. Remove sizes then, in that case viewBox will be preserved. Or configure SVGO to do whatever you want, since you want something different that most people do.

wavebeem commented 1 year ago

I understand the point of SVGO is to optimize your SVGs, but it still seems odd to me that an approximate 23 byte savings is worth completely removing one of the core use cases of SVG as a file format.

I respect that the default viewBox behavior is ultimately your decision, even if I disagree with it.

Would you consider adding an easier command-line option for disabling viewBox stripping? Like svgo --preserve-viewbox or svgo -p or something? It's pretty difficult for a new user to figure out how to change this behavior.

image

mangelozzi commented 1 year ago

@mangelozzi you missed the point. If you change size of SVG, you are essentially editing it. Remove sizes then, in that case viewBox will be preserved. Or configure SVGO to do whatever you want, since you want something different that most people do.

By applying CSS styles to scale a Scalable Vector Graphic with CSS rules, one is not editing the image. If you right click and click save image as, it is the same image. Removing the viewBox is actually editing the image, in the way that one is editing the way the scable vector graphic was intended to scale.

Maybe as an idealist and someone who is also a perfectionist (which I respect), you cannot let go of this belief. Maybe then see it as trading a few inperceptible bytes in terms of real world difference, for saving many developers hours of trouble shooting this problem (a real world difference), and for the very important feature of being able to scale the image at various places on a webpage to suit the screen size/page layout (a real world difference).

Lucienest commented 1 year ago

When we're dealing with an arrogant dev like @GreLI

wavebeem commented 1 year ago

When we're dealing with an arrogant dev like @GreLI

I don't think that insulting a project maintainer is gonna get us what we want, @Lucienest...

Lucienest commented 1 year ago

When we're dealing with an arrogant dev like @GreLI

I don't think that insulting a project maintainer is gonna get us what we want, @Lucienest...

I'm not insulting honestly, but I'm just expressing my disappointment @wavebeem have read the entire conversation and found that he'd ignore every valid comment that doesn't satisfy his decision. confirmation bias kills most healthy projects.

viewBox is a crucial part of the SVG, but svgo won't respect this essential behavior.