2017-10-18 30 views
4

我遇到了一个问题,一个内联<svg>元素并不延伸到其原始尺寸,在其viewBox属性声明,当它被包裹在一个绝对定位的父:SVG未能大小适当的绝对定位的父

  • 使用width: 100%似乎只会强制SVG延伸到浏览器定义的默认大小300px。这也会导致<img>未按其原始尺寸调整大小。
  • 使用width: auto使SVG由0像素完全折叠成0像素的尺寸,但<img>现在尺寸以它的天然尺寸

有趣的是,这种行为可以通过使用SVG作为data:image/svg+xml为被复制src属性的<img>元素,所以看起来SVG不会将其原始尺寸“传递”到其包含的父元素(可能是<svg><img>元素)。

所以,我的问题是,如果在CSS中有任何可靠的方法可以强制SVG根据其视图属性来调整其原始大小。我大概可以用JS来强制我的方式,通过阅读viewBox属性和use the fixed aspect ratio hack将我的SVG作为背景图像以固定宽高比<div>元素显示,但我尽力避免这种情况。我可能误解了浏览器的SVG规范的实现,但我似乎无法找到解决方法。


我的问题可以在下面的代码片段中重现。您可以:使用页面

  • 顶部复选框

    • 开启/关闭绝对父定位在<img><svg>元素选择width声明(自动或100%)

    // The JS logic below is only used to dynamically set styles based on checkbox/select changes, has nothing to do with SVG layout 
     
    
     
    // Change positioning strategy 
     
    document.getElementById('absPosToggle').addEventListener('change', function() { 
     
        var parents = document.querySelectorAll('.parent'); 
     
        
     
        if (this.checked) { 
     
        for (var i = 0; i < parents.length; i++) { 
     
         parents[i].classList.remove('no-absolute-positioning'); 
     
        } 
     
        } else { 
     
        for (var i = 0; i < parents.length; i++) { 
     
         parents[i].classList.add('no-absolute-positioning'); 
     
        } 
     
        } 
     
    }); 
     
    
     
    // Change width declaration of <svg>/<img> elements 
     
    document.getElementById('widthSetting').addEventListener('change', function() { 
     
        var images = document.querySelectorAll('img, svg'); 
     
        var value = this.options[this.selectedIndex].value; 
     
        
     
        if (value === '100%') { 
     
        for (var i = 0; i < images.length; i++) { 
     
         images[i].classList.add('width--100'); 
     
        } 
     
        } else { 
     
        for (var i = 0; i < images.length; i++) { 
     
         images[i].classList.remove('width--100'); 
     
        } 
     
        } 
     
    });
    body { 
     
        margin: 0; 
     
        padding: 50px 0 0 0; 
     
    } 
     
    
     
    form { 
     
        position: fixed; 
     
        top: 0; 
     
        left: 0; 
     
        right: 0; 
     
        display: block; 
     
        background-color: #fff; 
     
        z-index: 1; 
     
        padding: 5px; 
     
    } 
     
    
     
    .wrapper { 
     
        width: 100%; 
     
        height: 250px; 
     
        background-color: #eee; 
     
        margin-bottom: 10px; 
     
        position: relative; 
     
        text-align: center; 
     
    } 
     
    
     
    .parent { 
     
        position: absolute; 
     
        top: 50%; 
     
        left: 50%; 
     
        transform: translate(-50%, -50%); 
     
    } 
     
    
     
    .parent.no-absolute-positioning { 
     
        position: relative; 
     
        top: 0; 
     
        left: 0; 
     
        transform: none; 
     
    } 
     
    
     
    img, 
     
    svg { 
     
        display: block; 
     
        width: auto; 
     
    } 
     
    
     
    img.width--100, 
     
    svg.width--100 { 
     
        width: 100%; 
     
    }
    <form> 
     
        <label><input type="checkbox" id="absPosToggle" checked />Toggle absolute positioning</label><br /> 
     
        <label for="widthSetting">Set svg/img widths to:</label><select id="widthSetting"> 
     
        <option value="auto">Auto</option> 
     
        <option value="100%">100%</option> 
     
        </select> 
     
    </form> 
     
    
     
    <!-- <img> --> 
     
    <div class="wrapper"> 
     
        <div class="parent"> 
     
        <img src="https://via.placeholder.com/500x150/173755/ffffff" /> 
     
        </div> 
     
        <span>This is an <code>&lt;img&gt;</code> element</span> 
     
    </div> 
     
    
     
    <!-- Inline <svg> --> 
     
    <div class="wrapper"> 
     
        <div class="parent"> 
     
        <svg viewBox="0 0 500 150" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="500" height="150" fill="#b13131" /><g transform="translate(250, 75)"><text fill="#ffffff" style="text-anchor: middle; font-size: 50; font-family: Arial;" dy="0.35em">500 x 150</text></g></svg> 
     
        </div> 
     
        <span>This is an inline <code>&lt;svg&gt;</code> element</span> 
     
    </div> 
     
    
     
    <!-- <img> with SVG as data:image --> 
     
    <div class="wrapper"> 
     
        <div class="parent"> 
     
        <img src="data:image/svg+xml;charset=utf8,%3Csvg%20viewBox=%220%200%20500%20150%22%20xmlns=%22http://www.w3.org/2000/svg%22%3E%3Crect%20x=%220%22%20y=%220%22%20width=%22500%22%20height=%22150%22%20fill=%22#b13131%22%20/%3E%3Cg%20transform=%22translate(250,%2075)%22%3E%3Ctext%20fill=%22#ffffff%22%20style=%22text-anchor:%20middle;%20font-size:%2050;%20font-family:%20Arial;%22%20dy=%220.35em%22%3E500%20x%20150%3C/text%3E%3C/g%3E%3C/svg%3E" 
     
        /> 
     
        </div> 
     
        <span>This is an <code>&lt;img&gt;</code> element with SVG as data:image</span> 
     
    </div>

  • +1

    提出的问题很好。将宽度和高度属性添加到SVG不是一种选择吗?您是否已经通过https://css-tricks.com/scale-svg/查看是否有任何建议可以解决此问题?我认为问题的根本原因在于,通过绝对定位,您可以使父级的宽度计算方法变为缩小拟合,并且对于没有合适固有宽度的_and_内容,这可能是一种捕获22,可能会解释回落到“标准”300px宽度。 – CBroe

    +0

    @CBroe这实际上是一个很好的观点。在问这个问题之前,我读过那篇文章,并且建议不要设置'width'和'height'属性,而是使用'viewBox'。然而,这种方法的缺点似乎是,SVG将不再保持正确的长宽比,或者在绝对定位时具有折叠大小。解决方法似乎不得不声明一个“宽度”和“高度”。 – Terry

    +0

    _“这种方法的缺点似乎是,SVG将不再保持正确的纵横比”_ - 您是否检查过“preserveAspectRatio”,viewbox'“sidekick”,正如文章所称的那样,无法解决该问题要么? https://css-tricks.com/scale-svg/#article-header-id-4 – CBroe

    回答

    2

    我认为这个问题的根本原因是与绝对定位你为父母的宽度计算方法变成shrink-to-fit,并且对于那些没有合适的内在宽度的内容,这也是一种捕捉22,这可能解释回落到“标准”300px宽度。

    我们想通了,你经历过https://css-tricks.com/scale-svg/已经,而且好像加入widthheight属性的SVG本身可能是唯一的工作方式(在这种特殊情况),得到SVG适当的真正高度,以便它可以“跨越”其绝对定位的父母。

    相关问题