web-dev-qa-db-fra.com

SVG avec viewBox et largeur ne redimensionne pas correctement la hauteur dans IE

J'essaie de construire des SVG en ligne avec des attributs viewBox, mais pas d'attributs de largeur ou de hauteur explicites. Je règle la largeur du SVG à 100% en utilisant CSS. Cela devrait laisser l'échelle SVG à son conteneur d'emballage, en conservant le rapport d'aspect défini par la viewBox. Dans Chrome et Firefox, cela fonctionne parfaitement!

Voici un exemple minimal de codepen de ce dont je parle: http://codepen.io/pcorey/pen/amkGl

HTML:

<div>
  <svg viewBox="0 0 100 10">
    <text x="1" y="9">hello</text>
  </svg>
</div>

CSS:

div {
  width: 400px;
}

svg {
  width: 100%;
  max-height: 100%;
  outline: 1px solid tomato;
}

text {
  font-size: 10px;
}

La viewBox est de 100x10. Le div externe est défini pour avoir une largeur de 400 pixels. Cela signifie que la hauteur du SVG devrait être (et est dans Chrome/Firefox) 40px. MAIS, en IE 11, la largeur est TOUJOURS 150px (même lorsque la largeur du div dépasse 1500px ...)

Existe-t-il un bon moyen de résoudre ce problème dans IE? Pourquoi ne peut pas IE gérer correctement la hauteur inconnue? Je peux utiliser l'astuce " rapport d'aspect intrinsèque ", mais c'est super laid, nécessite un autre élément DOM, et nécessite que je recalcule le padding-top chaque fois que le wrapper se redimensionne.

Pour plus d'informations sur les raisons pour lesquelles je veux faire cela, j'ai écrit un petit article de blog à ce sujet: http://1pxsolidtomato.com/2014/10/08/quest-for-scalable-svg-text/ =

Merci pour l'aide!

24
pcorey

Une solution de contournement qui devrait fonctionner dans tous les navigateurs consiste à ajouter une image vierge au conteneur dans lequel se trouve votre SVG, qui a les mêmes dimensions que votre SVG:

.wrap {
  position: relative;
}
img {
  width: 100%;
  height: auto;
}
.viz {
  position: absolute;
  top: 0;
  left: 0;
}
<div class="wrap">
  <img src="img/blank.png" />
  <div class="viz">
    <svg preserveAspectRatio="xMinYMin slice" viewBox="0 0 1000 600"></svg>               
  </div>
</div>

Dans ce cas, votre image doit avoir des dimensions naturelles de 1000px par 600px et être transparente (ou correspondre à l'arrière-plan de votre conteneur .wrap). Cela correspondra à la taille du conteneur dans lequel se trouve le svg. La position absolue de l'élément .viz lui permettra de s'asseoir au-dessus de l'image, en utilisant sa hauteur pour que rien ne soit coupé.

4
Taylor Plante

Certains navigateurs (IE et safari) utiliseront une taille par défaut pour SVG si vous ne mettez pas une certaine hauteur et largeur. C'est ce qui se passe ici. Vous avez raison, la "ration d'aspect intrinsèque" nécessite un autre Dom et css et sera agréable si nous pouvons surmonter cela.

Il y a une solution à cela, vous pouvez calculer et mettre la bonne hauteur au rembourrage et cela donnera la bonne "hauteur inconnue" que vous voulez. Vous pouvez voir une solution complète ici: http://codepen.io/tomkarachristos/pen/GZPbgZ

<!--
xMidYMin: Align the midpoint X value of the element's viewBox with the midpoint X value of the viewport.
slice : the entire viewport is covered by the viewBox and the viewBox is scaled down as much as possible,
height: if you dont set >= 1px some browsers will not render anything.
-->
<div>
    <svg viewBox="0 0 100 10" preserveAspectRatio="xMidYMin slice"
         width="100%" style="height: 1px;overflow: visible;
         /*without js:padding-bottom:55%*/"><text>hello</text>
  </svg>
    <svg viewBox="0 0 100 10" preserveAspectRatio="xMidYMin slice"
         width="100%" style="height: 1px;overflow: visible;"><text>Age</text>
  </svg>
</div>

et javascript:

/*
Here we do the hack.
With the math type: percent * height/width
we are adjust the total height of an element who is depend in width using the padding-bottom.
You can put an inline padding-bottom if you want in html.
*/

$(function() {
  $('svg').each(function() {
    var svg = $(this);
    var text = svg.find('text');
    var bbox = text.get(0).getBBox();
    //the hack
    var calcString = "calc(100% * " + bbox.height/bbox.width + ")";
    svg.css("padding-bottom",calcString);

    svg.get(0).setAttribute('viewBox',
                           [bbox.x,
                            bbox.y,
                            bbox.width,
                            bbox.height].join(' '));
  });
});
3