scale embedded svg without white space in chrome

2019-03-31 01:48发布

I need to embed an svg into html and style it in a responsive way. For regular images this worked nicely for me:

img {
  max-width: 100%;
}

img[height] { 
  height: auto; /* if the <img> tag provides a width keep aspect ratio */
}

unfortunately this doesn't work for embedded svgs. Here is an example how it works for both an embedded svg and a svg within an img tag.

Here is an example markup:

<div>Embedded SVG:
  <svg xmlns="http://www.w3.org/2000/svg" width="300px" height="300px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet"><circle cx="50" cy="50" r="50" /></svg>
</div>

 <div>SVG as image tag:  
   <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMDBweCIgaGVpZ2h0PSIzMDBweCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIG1lZXQiPjxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjUwIiAvPjwvc3ZnPg0K" />
 </div>

and css:

div {
    resize: both;
    outline: 1px solid red;
    margin-bottom: 3em;
    padding: 1em;
}

svg,
img {
  display: block;
  outline: 1px solid blue;
  max-width: 100%;
  height: auto;
}

scaled down both images preserve aspect their ratio but the embedded svg keeps its original height (the blue outline)

How can I avoid the embedded svg creating a white space?

You can find an example on jsfiddle.

I'd love to post screenshots but I have not enough reputation for that :/

Edit: the bug appears only in chrome. changed the title accordingly

2条回答
SAY GOODBYE
2楼-- · 2019-03-31 02:28

This isn't technically a Chrome bug, but rather a gap in the SVG specifications. In particular:

Similarly, if there are positioning properties specified on the referencing element or on the outermost svg element that are sufficient to establish the height of the viewport, then these positioning properties establish the viewport's height; otherwise, the ‘height’ attribute on the outermost svg element establishes the viewport's height.

That tells the browser to use the <svg>'s height attribute as the height, unless there is conflicting CSS styles setting a different height, regardless of any consideration of the aspect ratio of the image. Now, most of us would argue that

  • if there is enough information on the <svg> to establish an intrinsic aspect ratio,
  • then any CSS that explicitly defines the width should be considered "positioning properties ... sufficient to establish the height of the viewport".

But the specs never explicitly say that. And while Firefox interprets it that way, Chrome does not.

The non-intuitive solution is to remove the height and width attributes from the <svg> element, use the viewBox attribute to establish the aspect ratio, and use CSS to specify min and max height and width.

<div>
  Embedded SVG:
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" 
       preserveAspectRatio="xMidYMid meet">
     <circle cx="50" cy="50" r="50" />
  </svg>
</div>

CSS:

svg,
img {
  display: block;
  outline: 1px solid blue;
  width:300px;
  max-width: 100%;
  max-height:300px;
  height: auto;
}

http://jsfiddle.net/78cpD/3/

Note that the height:auto; style is required, because the default height style is 100% when you don't specify it as an attribute.

All of which is way simpler than the method I'd been using previously, that involved wrapping the SVG in a <div> and defining a fixed aspect ratio using padding.

查看更多
Evening l夕情丶
3楼-- · 2019-03-31 02:30

Someone here came up with a jquery based workaround. that works quite well so far

$(window).bind('resize', function() {
  resizeSvg(context);
});
function resizeSvg(context) {
  $('svg', context).each(function(k,svg) {
    $Svg = $(svg);
    $Svg.removeAttr('style');

    var wantedWidth = parseInt(svg.getAttribute('width'));
    var wantedHeight = parseInt(svg.getAttribute('height'));
    var currentWidth = parseInt($Svg.width());
    var currentHeight = parseInt($Svg.height());
    if (wantedWidth != currentWidth) {
      var ratio = wantedHeight / wantedWidth;
      var newHeight = ratio * currentWidth;
      $Svg.css({'height': newHeight});
    }
  }
}
查看更多
登录 后发表回答