Actuellement en train de construire une application SVG basée sur un navigateur. Dans cette application, l'utilisateur peut styler et positionner diverses formes, notamment des rectangles.
Lorsque j'applique un stroke-width
à un élément SVG rect
de dire 1px
, le trait est appliqué au décalage et à l'insertion de la rect
de différentes manières par différents navigateurs. Cela s'avère gênant, surtout lorsque j'essaie de calculer la largeur extérieure et la position visuelle d'un rectangle et de le positionner à côté d'autres éléments.
Par exemple:
Ma seule solution à ce jour serait de tracer moi-même les frontières réelles (probablement avec l'outil path
) et de placer les frontières derrière l'élément en trait. Mais cette solution est une solution de contournement désagréable, et je préférerais ne pas aller dans cette voie si possible.
Ma question est donc la suivante: pouvez-vous contrôler la manière dont le stroke-width
du SVG est dessiné sur des éléments?
Non, vous ne pouvez pas spécifier si le trait est dessiné à l'intérieur ou à l'extérieur d'un élément. J'ai soumis une proposition au groupe de travail SVG pour cette fonctionnalité en 2003, mais ce dernier n'a reçu aucun soutien (ni discussion).
Comme je l'ai noté dans la proposition,
Edit: Cette réponse pourrait être fausse dans le futur. Il devrait être possible d'obtenir ces résultats avec SVG Vector Effects , en combinant veStrokePath
avec veIntersect
(pour 'à l'intérieur') ou avec veExclude
(pour 'à l'extérieur). Cependant, Vector Effects est toujours un brouillon de travail sans aucune implémentation que je puisse encore trouver.
Edit 2: le projet de spécification SVG 2 comprend une propriété stroke-alignment
(avec le centre | dedans | en dehors des valeurs possibles). Cette propriété peut éventuellement devenir un agent utilisateur.
Edit 3: Amusant et décevant, le groupe de travail SVG a supprimé stroke-alignment
de SVG 2. Vous pouvez voir certaines des préoccupations décrites après la prose ici .
UPDATE: L'attribut stroke-alignment
a été déplacé le 1er avril vers une toute nouvelle spécification appelée SVG Strokes .
Depuis le brouillon de l’éditeur SVG 2.0 du 26 février 2015 (et éventuellement depuis le { 13 février } _), _ { la propriété avec les valeurs stroke-alignment
est présenteinner
, center
(par défaut) et outer
.
Cela semble fonctionner de la même manière que la propriété stroke-location
proposée par @Phrogz et que la plus récente suggestion stroke-position
. Cette propriété est prévue depuis au moins 2011, mais à part une annotation qui dit
SVG 2 doit inclure un moyen de spécifier la position du trait
, il n’a jamais été détaillé dans les spécifications telles qu’elles étaient différées - jusqu’à présent, semble-t-il.
Aucun navigateur ne prend en charge cette propriété, ni, pour autant que je sache, aucune des nouvelles fonctionnalités de SVG 2 pour le moment, mais nous espérons qu'elles le seront bientôt lorsque les spécifications arriveront à maturité. Personnellement, j’ai insisté pour que ce soit un bien, et je suis vraiment heureux que ce soit enfin dans les spécifications.
Il semble y avoir quelques problèmes quant à la manière dont la propriété doit se comporter sur les chemins ouverts ainsi que sur les boucles. Ces problèmes vont probablement prolonger les implémentations sur les navigateurs. Cependant, je mettrai à jour cette réponse avec de nouvelles informations à mesure que les navigateurs commenceront à prendre en charge cette propriété.
J'ai trouvé un moyen facile, qui comporte quelques restrictions, mais qui a fonctionné pour moi:
Voici un exemple de travail:
<svg width="240" height="240" viewBox="0 0 1024 1024">
<defs>
<path id="ld" d="M256,0 L0,512 L384,512 L128,1024 L1024,384 L640,384 L896,0 L256,0 Z"/>
<clipPath id="clip">
<use xlink:href="#ld"/>
</clipPath>
</defs>
<g>
<use xlink:href="#ld" stroke="#0081C6" stroke-width="160" fill="#00D2B8" clip-path="url(#clip)"/>
</g>
</svg>
Voici une fonction qui calculera le nombre de pixels que vous devez ajouter - en utilisant le trait donné - en haut, à droite, en bas et à gauche, tous en fonction du navigateur:
var getStrokeOffsets = function(stroke){
var strokeFloor = Math.floor(stroke / 2), // max offset
strokeCeil = Math.ceil(stroke / 2); // min offset
if($.browser.mozilla){ // Mozilla offsets
return {
bottom: strokeFloor,
left: strokeFloor,
top: strokeCeil,
right: strokeCeil
};
}else if($.browser.webkit){ // WebKit offsets
return {
bottom: strokeCeil,
left: strokeFloor,
top: strokeFloor,
right: strokeCeil
};
}else{ // default offsets
return {
bottom: strokeCeil,
left: strokeCeil,
top: strokeCeil,
right: strokeCeil
};
}
};
Vous pouvez utiliser CSS pour définir l'ordre des traits et des remplissages. C’est-à-dire que vous commencez par remplir, puis que vous remplissez ensuite, pour obtenir l’effet souhaité.
MDN sur Paint-order
: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Paint-order
Code CSS:
Paint-order: stroke;
Comme les personnes ci-dessus l'ont déjà noté, vous devrez recalculer un décalage par rapport aux coordonnées du tracé du trait ou doubler sa largeur, puis masquer un côté ou l'autre, car SVG ne prend pas en charge de manière native l'alignement du trait d'Illustrator, mais PostScript ne le permet .
La spécification des traits dans le Manuel PostScript d'Adobe, 2e édition, indique: " 4.5.1 Stroking: L'opérateur stroke dessine une ligne d'une certaine épaisseur le long du tracé actuel. segment incurvé dans la trajectoire, stroke trace une ligne qui est centrée sur le segment avec les côtés parallèle au segment. " (emphase les leurs)
Le reste de la spécification n'a aucun attribut permettant de compenser la position de la ligne. Lorsque Illustrator vous permet d’aligner à l’intérieur ou à l’extérieur, il recalcule le décalage du chemin réel (car il reste moins coûteux en calcul que pour la surimpression et le masquage). Les coordonnées de chemin dans le document .ai sont des références, pas ce qui est raster ou exporté dans un format final.
Le format natif d'Inkscape étant SVG, il ne peut pas offrir une fonctionnalité manquante.
Voici une solution de contournement pour inner borderedrect
, en utilisant symbol
et use
.
Exemple: https://jsbin.com/yopemiwame/edit?html,output
SVG:
<svg>
<symbol id="inner-border-rect">
<rect class="inner-border" width="100%" height="100%" style="fill:rgb(0,255,255);stroke-width:10;stroke:rgb(0,0,0)">
</symbol>
...
<use xlink:href="#inner-border-rect" x="?" y="?" width="?" height="?">
</svg>
Remarque: Assurez-vous de remplacer le ?
dans use
par des valeurs réelles.
Background: cela s’explique par le fait que symbol crée une nouvelle fenêtre en remplaçant symbol
par svg
et en créant un élément dans le DOM fantôme. Cette svg
du DOM fantôme est ensuite liée à votre élément SVG
actuel. Notez que svg
s peut être imbriqué et chaque svg
crée une nouvelle fenêtre d'affichage, qui clipse tout ce qui se chevauche, y compris la bordure se chevauchant. Pour un aperçu beaucoup plus détaillé de ce qui se passe, lisez cet article fantastique de Sara Soueidan.
Je ne sais pas à quel point cela sera utile mais dans mon cas, je viens de créer un autre cercle avec une bordure uniquement et de le placer «à l’intérieur» de l’autre forme.
Une solution possible (sale) consiste à utiliser des motifs,
voici un exemple avec un triangle à l'intérieur:
https://jsfiddle.net/qr3p7php/5/
<style>
#triangle1{
fill: #0F0;
fill-opacity: 0.3;
stroke: #000;
stroke-opacity: 0.5;
stroke-width: 20;
}
#triangle2{
stroke: #f00;
stroke-opacity: 1;
stroke-width: 1;
}
</style>
<svg height="210" width="400" >
<pattern id="fagl" patternUnits="objectBoundingBox" width="2" height="1" x="-50%">
<path id="triangle1" d="M150 0 L75 200 L225 200 Z">
</pattern>
<path id="triangle2" d="M150 0 L75 200 L225 200 Z" fill="url(#fagl)"/>
</svg>