I'm trying to recreate the look of an iOS app icon using SVG, but with an outline in case the icon is white on a white background.
Example:
<svg width="76" height="76">
<defs>
<mask id="myMask">
<rect fill="#fff" rx="15" ry="15" width="76" height="76"/>
</mask>
</defs>
<rect id="border" mask="url(#myMask)" fill="#000" x="0" y="0" width="76" height="76" />
<rect id="image" mask="url(#myMask)" fill="#fff" x="1" y="1" width="74" height="74" />
</svg>
(https://jsfiddle.net/d4ngtuqa/1/)
To do this, I'm rendering a filled rectangle behind an image rendered 2x2 pixels smaller (or another rect in my simplified example) and then applying an SVG mask to both layers.
However, when I do this, the rounded corners of the border render lighter than the rest of the border. Is this a rendering bug or something? Is there an alternate approach that could avoid this?
You don't need to mask both the image and the border. Just mask the image, then draw a 1px black border on top of it.
<svg width="76" height="76">
<defs>
<mask id="myMask">
<rect fill="#fff" rx="15" ry="15" width="76" height="76"/>
</mask>
</defs>
<rect id="image" mask="url(#myMask)" fill="#fff" x="0" y="0" width="76" height="76" />
<rect id="border" fill="none" stroke="#000" stroke-width="1" x="0.5" y="0.5" width="75" height="75" rx="15" ry="15" />
</svg>
Note that, in order to make the 1px border as neat and clean as possible, we use coordinates for the rect that align to a half-pixel (0.5 and 75.5), so that the line falls cleanly within a line of pixels.