Centering an SVG element Chrome vs Safari - html

I'm trying to center an SVG element in a parent element. However, I'm finding discrepancies between Chrome and Safari. The following code centers the text nicely inside the square on Chrome, but not on Safari:
<svg width="200px" height="200px">
<g transform="translate(70,70)">
<path d="M -40,-40 l 80,0 l 0,80 l -80,0 l 0,-80 z" style="fill: gray"></path>
<g>
<text text-anchor="middle" dominant-baseline="middle" style="fill: white" transform="scale(2)">
<tspan>test</tspan>
</text>
</g>
</g>
</svg>
Result:
I created a jsFiddle with this test case:
https://jsfiddle.net/yq11jot0/
How do I vertically center the text inside the square?

How about just using dy instead of dominant-baseline?
<svg width="200px" height="200px">
<g transform="translate(70,70)">
<path d="M -40,-40 l 80,0 l 0,80 l -80,0 l 0,-80 z" style="fill: gray"></path>
<g>
<text text-anchor="middle" dy="0.25em" style="fill: white" transform="scale(2)">
<tspan>test</tspan>
</text>
</g>
</g>
</svg>

Apparently, Safari wants the inner tspan have the dominant baseline set to middle. So this also works on Safari:
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(50,50)">
<path class="node" d="M -40,-40 l 80,0 l 0,80 l -80,0 l 0,-80" style="fill: rgb(247, 61, 0);"></path>
<g>
<text text-anchor="middle" fill="white"><tspan dominant-baseline="middle">test</tspan></text>
</g>
</g>
</svg>

Try removing all the scaling and translating (can have issues in browsers) ... does this work in Safari?
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0 H200 V200 H0 z" fill="gray" />
<text x="100" y="100" text-anchor="middle" dominant-baseline="middle" fill="white" font-size="100" >test</text>
</svg>
Note the following:
Not using px units
Text positioned to the center of the square using x and y attributes.

Related

How to vertically center a character within a svg path?

I have an svg path with a text and a character like this:
<svg id="svg1" style="overflow:visible">
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<text text-anchor="middle" dy="-30" >
<textPath href="#path1" startOffset="50%" fill="red">Shape</textPath>
<textPath href="#path1" startOffset="50%" fill="red" dominant-baseline="central" >
<tspan font-size="30" dy="-5">⬤</tspan>
</textPath>
</text>
</svg>
And I want the circle (or any character in general) to align perfectly at the center of the line regardless of font-size or any other attribute
I tried changing dy but it's really isn't a universal solution.
Here's what it looks like for different browsers:
for font-size="50" in firefox
for font-size="50" in Brave
for font-size="10" in firefox & Brave
So how do I universally align the character to the vertical center for any given style and/or attribute?
Edit
as mentioned in the comments, I tried this solution but it really doesn't solve the problem for varying font-size nor does it perfectly align to the center cross browser
<svg id="svg1" style="overflow:visible">
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<text text-anchor="middle" dy="-30" >
<textPath href="#path1" startOffset="50%" fill="red">Shape</textPath>
<textPath href="#path1" startOffset="50%" fill="red" dominant-baseline="central"
alignment-baseline="central">
<tspan font-size="30" dy="-5">⬤</tspan>
</textPath>
</text>
</svg>
Unfortunately, there is no reliable way to center text vertically.
Firefox and chrome will interpret dominant-baseline quite differently.
For a consistent rendering, you could use some javaScript.
This approach also requires to measure some character/glyph proportions to calculate an ideal baseline shift.
So we need to get a ratio between font size and character height.
E.g write a capital in Arial at 100 points in inkscape, Illustrator etc. and convert it to paths/outlines and check it's height: 71.582 pt
So the capital to font-size ratio is: 100/71.582 = 0.71582
Example 1: emulate dominant-baseline:central; font-size 10 and 20
<style>
svg{
height:90vmin;
border:1px solid #ccc
}
</style>
<svg viewBox="0 0 50 20">
<line x1="0" x2="100%" y1="50%" y2="50%" stroke="#000" stroke-width="10" /></line>
<text font-size="10" style="font-family:Arial" x="0" y="50%" fill="red" dy="3.5791">I⬤</text>
<text font-size="20" style="font-family:Arial" x="20" y="50%" fill="red" dy="7.1582">I⬤</text>
</svg>
The dy values are calculated like so:
10 (1. font-size) * 0.71582 (capheight ratio) / 2 = 3.5791
20 (2. font-size) * 0.71582 (capheight ratio) / 2 = 7.1582
The bad news: you need to get different ratios for each type of character e.g lowercase letters.
Albeit, it might be enough to check the x-height for lowercase characters.
Example 2: save ratios to data-attribute; calculate dy via js
let texts = document.querySelectorAll('text');
texts.forEach(function(text){
let offsetRatio = parseFloat(text.getAttribute('data-offsetratio'));
let style = window.getComputedStyle(text);
let fontSize = parseFloat(style.fontSize);
let dy = fontSize * offsetRatio /2;
text.setAttribute('dy', dy );
})
svg{
width:100%;
border:1px solid #ccc
}
<svg id="svg1" style="overflow:visible" viewBox="0 30 100 40">
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<path id="path2" stroke="#fff" d="M 0 50 L 100 50" stroke-width="0.25" />
<g font-size="10" style="font-family:Arial,Georgia,'Segoe UI'">
<text data-offsetratio="0.71582" x="0" y="50" fill="red">I⬤</text>
<text data-offsetratio="0.51855" x="15" y="50" fill="red">x</text>
</g>
<g font-size="25" style="font-family:Arial,Georgia,'Segoe UI'">
<text data-offsetratio="0.71582" x="30" y="50" fill="red">I⬤</text>
<text data-offsetratio="0.56409" x="60" y="50" fill="red">●</text>
<text data-offsetratio="0.70081" x="75" y="50" fill="red">•</text>
</g>
</svg>
Vertically aligning a text is done using dominant-baseline, but you can see from this example that it is not easy to do. Here I align ⬤Gga using the values middle and central.
I added a viewBox to <svg> so that it is easier to control the position. But I guess it all depends on the font used.
<svg overflow="hidden" viewBox="0 0 100 65" width="250">
<rect width="100" height="65" fill="#eee" />
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<text text-anchor="middle" dy="-30" fill="red">
<textPath href="#path1" startOffset="50%">Shape</textPath>
<textPath href="#path1" startOffset="50%" dominant-baseline="middle" font-size="30">⬤Gga</textPath>
</text>
</svg>
<svg overflow="hidden" viewBox="0 0 100 65" width="250">
<rect width="100" height="65" fill="#eee" />
<path id="path1" stroke="black" d="M 0 50 L 100 50" stroke-width="10" />
<text text-anchor="middle" dy="-30" fill="red">
<textPath href="#path1" startOffset="50%">Shape</textPath>
<textPath href="#path1" startOffset="50%" dominant-baseline="central" font-size="30">⬤Gga</textPath>
</text>
</svg>

Tick inside circle

I am trying to create tick Inside filled circle.
I did following but, doesn't looks perfect.
<svg height=10 viewBox="0 0 10 10" width=10>
<g fill="none" stroke="#22AE73" stroke-width="1"></g>
<circle cx=5 cy=5 fill='#29AB87' r=5 />
<polyline stroke="#ffffff" stroke-width="2" points="2.5,5.8 4.7,7.9 9.2,2.4 " />
</svg>
Any help would be greatly appreciated.
Your points are reaching the 10 10 part of your viewbox, hence it doesn't fit. You could change your points to lower values.
Alternatively, here's an svg that might work for you that is path based
<svg width="10px" height="10px" viewBox="0 0 10 10" >
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="tick">
<circle id="Oval" fill="#349006" cx="5" cy="5" r="5"></circle>
<path d="M7.26241838,2.25 L8.35843389,3.34601551 L3.9390165,7.76543289 L3.937,7.763 L3.93041937,7.77093389 L1.65,5.49051452 L2.74601551,4.39449901 L3.932,5.58 L7.26241838,2.25 Z" id="Combined-Shape" fill="#FFFFFF"></path>
</g>
</g>
</svg>

Scale inline SVG with DIV wrapper

Is it possible to scale an inline SVG without touching the SVG? So that only the wrapper div is able to change the width / height according to the image ratio?
Here is my code:
https://jsfiddle.net/sekmwfdg/1/
<div id="wrapper">
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-gb" width="640" height="480">
<defs>
<clipPath id="a">
<path fill-opacity=".67" d="M-85.333 0h682.67v512h-682.67z"/>
</clipPath>
</defs>
<g clip-path="url(#a)" transform="translate(80) scale(.94)">
<g stroke-width="1pt">
<path fill="#006" d="M-256 0H768.02v512.01H-256z"/>
<path fill="#fff" d="M-256 0v57.244l909.535 454.768H768.02V454.77L-141.515 0H-256zM768.02 0v57.243L-141.515 512.01H-256v-57.243L653.535 0H768.02z"/>
<path fill="#fff" d="M170.675 0v512.01h170.67V0h-170.67zM-256 170.67v170.67H768.02V170.67H-256z"/>
<path fill="#c00" d="M-256 204.804v102.402H768.02V204.804H-256zM204.81 0v512.01h102.4V0h-102.4zM-256 512.01L85.34 341.34h76.324l-341.34 170.67H-256zM-256 0L85.34 170.67H9.016L-256 38.164V0zm606.356 170.67L691.696 0h76.324L426.68 170.67h-76.324zM768.02 512.01L426.68 341.34h76.324L768.02 473.848v38.162z"/>
</g>
</g>
</svg>
</div>
It should work for all modern Browsers + IE 11
You should add viewBox="0 0 640 480" to you svg tag and it will take width and height from its parent container
<div id="wrapper">
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-gb" viewBox="0 0 640 480">
<defs>
<clipPath id="a">
<path fill-opacity=".67" d="M-85.333 0h682.67v512h-682.67z"/>
</clipPath>
</defs>
<g clip-path="url(#a)" transform="translate(80) scale(.94)">
<g stroke-width="1pt">
<path fill="#006" d="M-256 0H768.02v512.01H-256z"/>
<path fill="#fff" d="M-256 0v57.244l909.535 454.768H768.02V454.77L-141.515 0H-256zM768.02 0v57.243L-141.515 512.01H-256v-57.243L653.535 0H768.02z"/>
<path fill="#fff" d="M170.675 0v512.01h170.67V0h-170.67zM-256 170.67v170.67H768.02V170.67H-256z"/>
<path fill="#c00" d="M-256 204.804v102.402H768.02V204.804H-256zM204.81 0v512.01h102.4V0h-102.4zM-256 512.01L85.34 341.34h76.324l-341.34 170.67H-256zM-256 0L85.34 170.67H9.016L-256 38.164V0zm606.356 170.67L691.696 0h76.324L426.68 170.67h-76.324zM768.02 512.01L426.68 341.34h76.324L768.02 473.848v38.162z"/>
</g>
</g>
</svg>
</div>

Why is this svg not working in safari?

The following svg is working in chrome and firefox, but is not working in Safari. And I haven't been able to test it in ie.
Safari does show the image, but does not apply the mask.
<div class="widget-image-l">
<svg width="645px" height="470px" viewBox="0 0 645 470" version="1.1">
<g stroke="none" fill-rule="evenodd">
<mask id="mask" fill="white">
<path d="M38.5969948,-2.22080132e-11 C16.8456745,30.2125678 3.07305242,70.3781435 0.923015792,123.840504 C-7.15396842,324.681101 174,465.890038 341,469.890015 C508,473.889991 658.942386,367.295224 643.971193,180.147362 C637.875363,103.946248 607.401187,44.0482171 563.7625,-2.35331754e-11 L38.5969948,-1.42108547e-14 Z" id="path"></path>
</mask>
<g mask="url(#mask)">
<image x="-1020" y="0" width="1867.94872" height="470" xlink:href="http://www.castleknockhotel.com/cmsGallery/imagerow/5904/resized/1600x400/cycling_passion_of_life_high_resolution_wallpaper_for_desktop_background_download_cycling_images_free.jpg" transform="scale(-1 1)">
</image>
</g>
</g>
</svg>
</div>

CSS: SVG rotation animation fail

Im trying to rotate blades from it's centre, as a windmill does, I'm new in CSS and I can't make it to spin properly, blades dissapear from the screen. Actually it is not working in some browser, for example in firefox for pc, but it works on safari for OSx an in every Ios browsers. I've pasted the SVG below, but here is my code complete: http://codepen.io/DavidKartF1/pen/mVKwpX
<svg
class="windmill-icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
>
<g transform="translate(0,-952.36217)">
<g id="rotor" style="transform-origin: 48.327% 62.24%; transform: rotate(0deg);">
<path style="" d="m 52.032964,981.03514 c -1.255809,0.0277 -2.456062,0.72451 -3.071613,1.91975 -0.895349,1.73855 -0.212098,3.8744 1.526442,4.76975 1.738541,0.89534 3.874394,0.21209 4.769741,-1.52645 0.895349,-1.73854 0.212099,-3.87439 -1.526442,-4.76974 -0.543294,-0.27979 -1.127305,-0.40591 -1.698128,-0.39331 z" fill="#000000" fill-opacity="1" fill-rule="evenodd" stroke="none" />
<path style="" d="m 56.334032,984.98211 c -0.04983,0.52212 -0.197859,1.04165 -0.452665,1.53642 -0.235879,0.45802 -0.543385,0.85701 -0.902025,1.18618 1.155573,1.33508 3.100732,3.52774 3.660967,3.81626 0.776522,0.39991 11.183654,3.80654 14.660386,4.60925 2.124798,0.49057 7.324796,1.52986 7.794423,0.51214 0.07685,-0.16654 0.02896,-0.38934 -0.181727,-0.67735 -0.588843,-0.80495 -5.351732,-3.30398 -5.65996,-3.46272 -11.276895,-5.95922 -16.673816,-7.27268 -18.919399,-7.52018 z" fill="#000000" fill-opacity="1" fill-rule="evenodd" stroke="none" />
<path style="" d="m 48.100161,953.54009 c -0.182674,0.0167 -0.35154,0.17246 -0.495619,0.49892 -0.402687,0.91243 -0.188457,6.28177 -0.171813,6.62807 0.470537,12.55703 1.99393,17.91869 2.907627,20.05272 0.955097,-0.43748 2.060996,-0.51848 3.10257,-0.17182 0.580003,-1.67633 1.476988,-4.37943 1.447205,-4.99913 -0.04193,-0.87245 -2.290657,-11.59173 -3.333859,-15.00402 -0.637549,-2.08542 -2.339769,-7.10702 -3.456111,-7.00474 z" fill="#000000" fill-opacity="1" fill-rule="evenodd" stroke="none" />
<path style="" d="m 47.908522,985.18366 c -1.716128,0.32806 -4.713996,0.93611 -5.256858,1.28531 -0.734592,0.47253 -8.892997,7.78187 -11.326528,10.39146 -1.730618,1.85582 -6.183724,6.94777 -3.660966,6.67437 0.991531,-0.1075 5.536887,-2.9778 5.828469,-3.1654 10.611197,-6.66826 14.501935,-10.66451 15.902737,-12.52922 -0.819752,-0.68079 -1.33845,-1.63622 -1.486854,-2.65652 z" fill="#000000" fill-opacity="1" fill-rule="evenodd" stroke="none" />
</g>
<g id="stick">
<path style="" d="m 50.751702,993.03361 2.605442,0 1.172837,58.64579 -5.286594,0 z" fill="#000000" fill-opacity="1" fill-rule="evenodd" stroke="none" />
<path style="" d="m 50.755774,988.66999 0,2.99716 2.642451,0 0,-2.98178 c -0.851509,0.19175 -1.762006,0.19601 -2.642451,-0.0154 z" fill="#000000" fill-opacity="1" fill-rule="evenodd" stroke="none" />
<path style="" d="m 50.102459,991.89764 c -0.07744,0 -0.138774,0.1601 -0.138774,0.35684 l 0,0.19164 c 0,0.19675 0.06134,0.35685 0.138774,0.35685 l 3.951729,0 c 0.07743,0 0.138773,-0.1601 0.138773,-0.35685 l 0,-0.19164 c 0,-0.19674 -0.06134,-0.35684 -0.138773,-0.35684 l -3.951729,0 z m 3.9286,0.0463 0.0099,0 c 0.0022,0 0.07599,0.14429 0.07599,0.3205 l 0,0.17181 c 0,0.1762 -0.07053,0.3172 -0.07269,0.3172 l -0.01322,0 c 0.01737,-0.075 0.03635,-0.17784 0.03635,-0.29077 l 0,-0.22798 c 0,-0.11431 -0.01817,-0.21549 -0.03635,-0.29076 z" fill="#000000" fill-opacity="1" fill-rule="evenodd" stroke="none" />
</g>
</g>
The problem is related to finding the rotor's center with transform-origin, and how 48.327% 62.24% should be interpreted when the rotor is drawn around coordinates ~(50,1000) and then hoisted 952px by its parent <g>. You can read about the SVG coordinate system and how it affects transforms here:
https://sarasoueidan.com/blog/svg-transformations/
A solution to your problem that at least works in both Firefox and Chrome is to use pixel values instead of percentages:
.windmill-icon #rotor {
transform-origin: 52px 985px;
...
}
Updated pen (note that I have removed the rotor's style attribute and moved everything to CSS): http://codepen.io/Sphinxxxx/pen/adKVqZ
Read that guide >> SVG animation.
It helps me few months ago :).
Basicly, its better to animate from inside of element, then from css.
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="10" y="10" height="110" width="110"
style="stroke:#ff0000; fill: #0000ff">
<animateTransform
attributeName="transform"
begin="0s"
dur="20s"
type="rotate"
from="0 60 60"
to="360 60 60"
repeatCount="indefinite"
/>
</rect>
</svg>