CAJVO

Chrome 151 ucinał nasze SVG. Od błędu na produkcji do P0 w Chromium.

W Chrome 151 część animowanych SVG na stronie CAJVO zaczęła kończyć się w połowie drogi. Co ciekawe, geometria ścieżki była prawidłowa, endpoint znajdował się we właściwym miejscu, a DevTools nie pokazywał niczego podejrzanego. Problem udało się powiązać z pathLength, vector-effect: non-scaling-stroke i skalą renderowania, a następnie zgłosić do Chromium.

Co się zepsuło

Problem zauważyliśmy na produkcyjnej stronie CAJVO.

W kilku miejscach wykorzystujemy animowane SVG jako connectory pomiędzy elementami interfejsu. Ścieżka jest stopniowo odsłaniana za pomocą stroke-dashoffset, a na jej końcu znajduje się osobno renderowany arrowhead.

W Chrome 151 linia zaczęła kończyć się znacznie wcześniej, niż powinna. Arrowhead nadal znajdował się jednak dokładnie tam, gdzie powinien.

Pierwsza hipoteza była prosta: błąd naszej animacji albo geometrii SVG.

Dalsze testy pokazały jednak, że sam path jest poprawny. Problem pojawiał się dopiero na etapie renderowania.

Najpierw sprawdziliśmy, czy błąd jest po naszej stronie

Dotknięte SVG korzystało z takiej kombinacji:

<path
  pathLength="1"
  vector-effect="non-scaling-stroke"
/>

oraz:

path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

pathLength="1" pozwala znormalizować metrykę długości ścieżki. Dzięki temu animację można prowadzić od stroke-dashoffset: 1 do 0 bez znajomości rzeczywistej długości path.

Po zakończeniu animacji sprawdziliśmy między innymi:

path.getTotalLength();
getComputedStyle(path).strokeDashoffset;

Wyniki były poprawne.

getTotalLength() zwracało właściwą długość, stroke-dashoffset wynosiło 0px, a wyliczony endpoint ścieżki zgadzał się z pozycją arrowheada.

Następnie zaczęliśmy eliminować kolejne zmienne.

Tabela 1 Testowane środowiska

Test

Wynik

Chrome 151

błąd

Chrome 147

poprawnie

Safari

poprawnie

Incognito

błąd

Guest

błąd

Akceleracja GPU wyłączona

błąd

Bez non-scaling-stroke

poprawnie

To coraz mocniej wskazywało na regresję przeglądarki, a nie problem w aplikacji.

Najważniejszy trop: ten sam viewport, inny ekran

Przełomem okazała się zależność od devicePixelRatio.

Na monitorze zewnętrznym:

devicePixelRatio: 1
viewport: 1728 × 586

SVG renderowało się poprawnie.

Na ekranie Retina:

devicePixelRatio: 2
viewport: 1728 × 586

ścieżka była ucięta.

Co istotne, nie zmienialiśmy rozmiaru okna ani zoomu strony.

Wystarczyło przeciągnąć to samo okno Chrome z jednego monitora na drugi. Na ekranie z DPR 2 błąd się pojawiał. Po powrocie na DPR 1 znikał.

Aplikacja nie zawierała żadnej logiki zależnej od DPR.

To mocno wskazywało, że problem znajduje się niżej, w sposobie, w jaki Blink przelicza i renderuje SVG.

Drugim ważnym tropem był:

vector-effect: non-scaling-stroke;

Po jego usunięciu Chrome 151 ponownie renderował pełną ścieżkę.

non-scaling-stroke sprawia, że szerokość stroke nie skaluje się w zwykły sposób razem z geometrią SVG. W Blink wymaga to osobnego przeliczania transformacji wykorzystywanych podczas renderowania stroke.

I właśnie ten fragment implementacji okazał się istotny.

Chromium odtworzyło zgłoszenie i wykonało bisect.

Zakres regresji został zawężony do:

Good: 151.0.7920.0
Bad:  151.0.7922.3

Jako suspect wskazano zmianę dotyczącą migracji SVG New Zoom:

c3046a91b08eda408a3eabb5e5b717b84d8d304d

Commit obejmował między innymi zmiany w obsłudze zoomu i stroke w SVG. Co istotne, jego opis zakładał, że przy wyłączonej fladze zmiana powinna być No-op.

Poprawka, która później trafiła na Chromium main, pokazuje konkretny problem.

W funkcji:

LayoutSVGShape::ComputeNonScalingStrokeTransform()

warunek sprawdzający SvgNewZoom miał odwróconą logikę.

Kluczowa zmiana wyglądała tak:

- if (RuntimeEnabledFeatures::SvgNewZoomEnabled()) {
+ if (!RuntimeEnabledFeatures::SvgNewZoomEnabled()) {

Commit nosi nazwę:

Fix flag-check in LayoutSVGShape::ComputeNonScalingStrokeTransform

a jego opis wprost wskazuje, że należało odwrócić warunek. Do poprawki dodano również test regresyjny dotyczący interakcji zoomu z vector-effect: non-scaling-stroke.

To dobrze tłumaczy także zależność od skali.

Przy skali 1 brak właściwej kompensacji może pozostać niewidoczny. Przy skali 2 różnica staje się istotna.

W połączeniu z pathLength="1" i dashowaniem mogło to prowadzić do sytuacji, w której metryka dasha była liczona względem poprawnej geometrii, podczas gdy stroke był nakładany na ścieżkę przetransformowaną w innej skali.

To rekonstrukcja mechanizmu, a nie literalny opis wszystkich wewnętrznych wartości Blink. Jest jednak zgodna zarówno z kodem, jak i z obserwowanym objawem: geometria pozostawała poprawna, ale widoczny stroke kończył się za wcześnie.

Co zrobiło Chromium

Problem zgłosiliśmy 11 sierpnia 2026 jako Chromium Issue 544748096.

Chromium potwierdziło reprodukcję w Chrome 151 i 152, a później również na Windows, Linux, Androidzie i Android WebView.

Zgłoszenie zostało potraktowane jako regresja, poddane bisekcji i podniesione do P0 jako pilny problem związany z nadchodzącym wydaniem. Severity pozostało na poziomie S2.

Chronologia jest tutaj istotna.

Poprawka źródłowego problemu była już na Chromium main od 4 sierpnia, czyli przed naszym zgłoszeniem. Nie byliśmy autorami poprawki i nie twierdzimy, że jako pierwsi znaleźliśmy sam błąd w Blink.

Nasze zgłoszenie udokumentowało natomiast jego konkretną manifestację w produkcyjnym interfejsie i w wydanych wersjach Chrome, w tym bardzo czytelną zależność od DPR.

Po stronie serwisu nie wdrażaliśmy workaroundu.

Poprawka pozostała po stronie Chromium i znalazła się w linii Chrome 153. Chrome 153 został oficjalnie promowany do Stable 8 września 2026.

Źródła

  1. Chromium Issue 544748096
  2. Chromium: SVG New Zoom, commit wprowadzający regresję
  3. Chromium: poprawka ComputeNonScalingStrokeTransform
  4. SVG 2: pathLength
  5. SVG 2: dashing, stroke-dasharray i stroke-dashoffset
  6. SVG 2: vector-effect: non-scaling-stroke
  7. Chrome 153 Stable release

Wdrożenie i doradztwo

Szukasz wsparcia w tym obszarze?

Tworzymy szybkie, dostępne serwisy zoptymalizowane pod kątem konwersji i widoczności w wyszukiwarkach.

Oferta: Nowoczesne strony internetowe Zobacz realizację: Koqivo (crawler SEO)