The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Safari does not use one universal SVG transform order that differs from Chrome and Firefox. Most apparent mismatches come from mixing the SVG transform attribute with CSS transform, or from an unexpected pivot and reference box. For SVG elements, the usual CSS origin is 0 0 and the default reference is the SVG viewBox, not the shape’s own bounds. Make the box and pivot explicit, isolate attribute and CSS transforms, and test the exact Safari build before treating the result as an engine bug.
The short answer
SVG can be transformed through two related but distinct paths:
- The SVG
transformattribute uses SVG user coordinates.rotate(a)rotates around the current user-coordinate origin;rotate(a, x, y)supplies an explicit pivot. - The CSS
transformproperty uses CSS transform-origin and transform-box rules. For most SVG elements, the default origin is0 0, and the default reference box isview-box.
If your rectangle is positioned away from the viewBox origin, a CSS rotation around center can still use the SVG canvas as its reference. The shape appears to orbit or rotate in an unexpected sequence, even though Safari, Blink and Gecko are applying the same kind of matrix operation. A second class of differences occurs when an attribute transform and a CSS transform are both present; WebKit has open or historical reports for specific precedence cases, but those reports do not prove that every Safari release reverses SVG transform order.
Start with MDN’s SVG transform-origin documentation, make the reference box explicit, and reduce the testcase to one element and one transform before comparing engines.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
Two transform systems you must distinguish
SVG transform attributes
An attribute such as transform='translate(20 10) rotate(30)' is parsed as SVG transform data in the element’s user-coordinate system. When the rotation center matters, specify it directly:
<rect x='40' y='20' width='120' height='60'
transform='rotate(30 100 50)' />
Here the rotation pivot is the user-coordinate point (100,50). This avoids depending on CSS percentages or on how a browser resolves a reference box. The syntax and coordinate behavior are documented in MDN’s SVG transform reference.
CSS transforms on SVG elements
CSS applies transform-origin and transform-box before the transform matrix is applied. For most SVG elements, the initial origin is 0 0; root <svg> elements and SVG elements directly inside <foreignObject> are exceptions with a 50% 50% default. Percentages and keywords are resolved against the selected reference box.
The initial transform-box is generally view-box. Therefore, transform-origin:center can mean the center of the SVG viewBox rather than the center of a path or rectangle. To rotate a shape around its own bounds, use:
.shape {
transform-box: fill-box;
transform-origin: center;
transform: rotate(30deg);
}
With fill-box, the origin is the transformed element’s bounding box. Without it, the result can be anchored to the SVG canvas. See MDN’s transform-box reference for the reference-box definitions.
Why a transform can look as if Safari changed the order
The pivot changes the visible path
Transforms are matrix operations, so order and pivot both affect the final coordinates. A rotation followed by a translation is not visually equivalent to a translation followed by a rotation. If one browser resolves the CSS origin against the viewBox while your mental model assumes the shape bounds, the output resembles a reversed transform list even when the list itself has not been reordered.
Attribute and CSS declarations can interact
Keep these cases separate while debugging:
- Only an SVG
transformattribute. - Only a CSS
transformdeclaration. - Both declarations on the same element.
- A CSS reset such as
transform:noneintended to cancel an attribute transform.
WebKit Bug 217286 documents a case where transform:none did not cancel a scale supplied by an SVG transform attribute. The report does not establish the current status in every stable Safari release, so reproduce it with your target version rather than assuming a universal rule.
Presentation-hint precedence can be implementation-specific
WebKit Bug 305181 was marked NEW in the reviewed record. It compares an SVG transform presentation-hint case in Safari Technology Preview 234 with Chrome Canary 145 and Firefox Nightly 148; a later attachment reported the behavior in additional preview and nightly builds. This is evidence of a specific WebKit issue in prerelease builds, not a compatibility guarantee for all stable Safari versions. The report was filed on 2026-01-09 and modified on 2026-03-15: WebKit Bug 305181.
A minimal testcase that exposes the origin problem
Save this as an HTML file and open it in Safari, Chrome and Firefox. The first rectangle uses the default CSS reference behavior; the second makes the intended pivot explicit.
<!doctype html>
<meta charset='utf-8'>
<style>
svg { width: 360px; border: 1px solid #999; }
rect { transform: rotate(30deg); transform-origin: center; }
.own-box { transform-box: fill-box; }
</style>
<svg viewBox='0 0 360 180'>
<rect x='40' y='40' width='100' height='50' fill='tomato' />
<rect class='own-box' x='210' y='40' width='100' height='50' fill='steelblue' />
</svg>
The blue rectangle is the controlled case: fill-box makes center refer to that rectangle’s bounds. If the red rectangle appears to swing around the canvas, that is expected from the default reference semantics, not proof of a Safari-only transform-order bug.
Debugging procedure for a real project
- Record the exact environment. Note Safari or Safari Technology Preview, its version, macOS or iOS version, viewport size, device-pixel ratio and the corresponding Chrome or Firefox build. Preview/nightly results cannot be generalized to stable releases.
- Reduce the SVG. Remove animations, filters, masks, scripts and unrelated shapes. Leave one element, one viewBox and one transform.
- Classify the declaration. In DevTools, determine whether the transform is an SVG attribute, a CSS property, or both. Check author styles, presentation attributes and inherited rules.
- Write down coordinates. Record the viewBox, the element’s
x/yor path bounds, and the pivot you intend. A non-zero or negative viewBox origin is especially easy to overlook. - Make CSS geometry explicit. For a shape-centered CSS rotation, set
transform-box:fill-boxandtransform-origin:center. If the pivot is a fixed SVG coordinate, avoid a percentage and use the attribute form withrotate(angle, x, y). - Compare pixels and computed style separately. Capture a screenshot of the rendered result, then inspect computed
transform,transform-originandtransform-box. A computed-style agreement does not guarantee identical pixels, and a pixel mismatch does not prove computed-style disagreement. - Test the interaction cases. Add the other declaration back one at a time, including the
transform:nonereset case. This identifies precedence problems instead of hiding them in a large stylesheet. - Report a reduced case. Include the smallest HTML/SVG file, expected pivot, actual output, browser build and operating system. A WebKit bug report is actionable only when those details are reproducible.
What the documented WebKit reports do—and do not—show
| Record | What it concerns | How to use it |
|---|---|---|
| Bug 305181 | SVG transform presentation-hint precedence; Safari Technology Preview and prerelease Blink/Gecko builds | Evidence for a specific current WebKit mismatch; do not infer a stable-version matrix |
| Bug 217286 | CSS transform:none failing to cancel an SVG attribute scale in the reported testcase |
Re-test when a CSS reset appears ineffective |
| Bug 174285 | Computed-value behavior; a 2022 comment says Safari, Chrome and Firefox agreed on rendering for that testcase | Reminder to inspect computed values and pixels independently |
| Stack Overflow question (2020) | Historical Safari/iOS/macOS discussion about transform-origin and attribute chains | Useful historical context, not a current compatibility promise |
None of these records supplies a complete stable Safari-versus-Blink-versus-Gecko release range or operating-system matrix. Check the browser versions your users actually run.
Reliable coding patterns
Use one transform mechanism per element
Prefer either a CSS transform system or an SVG attribute for a given element. If a design system must combine them, document which layer owns translation, rotation and scaling, and test the combined case in all supported engines.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteRank #3
Use explicit SVG pivots for fixed geometry
<g transform='rotate(45 80 80)'>
<path d='...' />
</g>
This is deterministic when the pivot is known in SVG user coordinates.
Use explicit CSS boxes for responsive shapes
.icon-path {
transform-box: fill-box;
transform-origin: 50% 50%;
transform: translate(4px, 2px) rotate(45deg) scale(.9);
}
Keep the transform list in the order your design requires, and verify the result after changing the viewBox or path bounds.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting common symptoms
“The shape rotates around the canvas.”
Cause: CSS percentages or center are resolving against the default viewBox reference. Fix: add transform-box:fill-box; then set transform-origin:center.
“Changing transform-origin appears to do nothing.”
Cause: the active transform may be the SVG attribute, not CSS, or another rule may override the property. Inspect both declarations. For an attribute transform, encode the pivot as rotate(a, x, y).
“CSS transform:none does not remove the transform.”
Cause: an attribute transform can remain active in the reported WebKit failure mode. Remove or change the SVG attribute itself, then retest Safari versions; do not rely solely on the reset declaration.
“Computed styles match, but screenshots differ.”
Cause: rendering and computed-value behavior are separate observations. Check viewBox coordinates, device scale, clipping, filters and the actual raster output. Bug 174285 illustrates why both measurements matter.
“The mismatch exists only in Safari Technology Preview.”
Cause: preview builds can contain changes not shipped to stable Safari. Record the preview number, create a reduced case and retest the current stable release before changing production code.
Or skip the browser setup
When you need repeatable page captures for a reduced testcase, ScreenshotNeo provides a website screenshot API and MCP server. It can capture PNG, JPEG, WebP or PDF from one request, so you can archive test pages without maintaining browser automation. The API does not replace cross-engine testing—you should still validate Safari rendering directly—but it removes capture plumbing from your comparison workflow.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11cURL (the complete option list is in the ScreenshotNeo documentation):
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/svg-test.html -o shot.webp
Python:
import requests
r = requests.get(
'https://api.screenshotneo.com/v1/shot',
params={'access_key': 'YOUR_API_KEY', 'url': 'https://example.com/svg-test.html'},
timeout=90,
)
r.raise_for_status()
open('shot.webp', 'wb').write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com/svg-test.html' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
Cookie banners, newsletter popups and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up free for ScreenshotNeo.
FAQ
Does Safari always reverse SVG transform order?
No. The documented evidence covers specific testcases. First eliminate origin, reference-box and attribute-versus-CSS differences.
Should I report a browser bug?
Yes, when a reduced testcase still differs on the exact builds you support. Include source, expected pivot, screenshots, computed styles and platform details.
Is transform-box:fill-box required for every SVG?
No. Use it when CSS percentages or keywords should follow an element’s own bounds. A viewBox-relative origin may be intentional for a diagram or canvas-wide animation.
Can I rely on Safari Technology Preview to predict stable Safari?
No. Preview results identify a build-specific behavior. Verify the stable release range relevant to your users.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

