NEW 289072
flexbox container leads to complete freeze of WebKit
https://bugs.webkit.org/show_bug.cgi?id=289072
Summary flexbox container leads to complete freeze of WebKit
sikulin94
Reported 2025-03-03 22:31:01 PST
In case of nested elements when display: "flex" and flexDirection: "column" properties are set results in significant slowdown (~10x slower in Safari in comparison to Chrome). Culprit of slowdown was identified as problematic situation when some elements height is set to "auto" (at least implicitly) and its child has height set to "100%", so that should basically mean that parents height should be based on child (content), but childs height according to parents height and thats probably related to cause of the problem. When display: "flex" is removed things works reasonably, same in case height: "100%" is removed, so its probably related to how flex layout handles nested items. IMHO when such situation occurs parent height should be 0 or min-height. That is - at the begining childs size should be based on parent that at origin has 0 or min. value, so parents size should be its own size intermediate through its child (height: 100% or flex-grow: 1 for example). Related issue resolved many years ago: https://bugs.webkit.org/show_bug.cgi?id=150445. Reproduction of the problem (check console with "Took" message and compare result with Chrome on same device and platform): https://reactplayground.vercel.app/#N4IgLgziBcBmCGAbCBTANCAbrK1QEsA7AExQA8A6AK1xHwFsAHAewCcwACAQUcY9lbN6HAOQUA9D0bUIZEQB1CDFuw4AlFPADGnAUNGtNOhUqZtOwDlsPwwKNc2acAvv0HCRNnQFpiQ8VqI+CiEYCaKWsyEEJyRofBEKKwcALwcfloArvQhYBQA5ihgAKKIKDmhAEIAngCSxAAUno5hAJQRUTEcgk6pVjZ2Dk4NcWAJhEnthD15hiRJDYoc6kZ51pp2peW5i4TLyxraeQDKYKz4OgCyzKRoS-uEmYiId3v7hzoU67YoWxVgDSkU2WU1aIAwUhkZBgdDMqg+YDQHEsmVQGlgSNRKFOP0xqGKsFgKB0HFceg8XjCikUZU4MXg7CRIWI1MIcS6Uj6DVaqQAfMj7vTVGkACI-CiEZgAd25rOWWIJRJ0DW5fIFb2WzL6YrsEulso1Vk6zDKFEQzHyixAABVHABraDycEcLXeDhCsDA0lIgDaAF0vfdDGBMqw9rt9gAeABiZTIAGEomNEslEPBqkkIClgAAmAAMrjTGdY2YAjK5xLz7lNnKz2ZxY+RE-EU1zGIJGBAeSl+cB7vhYBwGu3mJ2zemkhx+SOx0XMzy+4bg6G9o9nvda4ag0UV0P7stI8R8Jh3WBqmVs8AABYofD5K9gaAcJ2lvN5gCkTqRR4gjCLT6dWA4y-fg4xFfBDB0fAogAkBIkQbJCCdZxnCrQ0DyPTA0P2HCOEPY9T3PFBLxvO8H1g18P2Q1D91wg9GwTJNxknOdWCzYAZwgcdiwgQsJxLYAAGpBM47ikgrbC6Lw8RMMknDIxk485KjWTaPkzDCIvYBr1ve9H2fEBKM-EAUOUuiYzjZtkwmVN+PY0TWN4jhWOzYSHP4iS1KjRSsK8hTVMNfylOrRRN1ZcgVE4UgECeTgpHBEAYiIr4IFoCgACMwD2RdllgJNvAgfAAC8UCfHNDHoABuUKTOcIA
Attachments
Demo (1.08 KB, application/x-zip-compressed)
2025-03-10 00:50 PDT, sikulin94
no flags
console in safari, firefox, chrome (1.43 MB, image/png)
2025-03-10 01:34 PDT, Karl Dubost
no flags
demo2 (1.08 KB, application/x-zip-compressed)
2025-03-10 02:05 PDT, sikulin94
no flags
perf testcase (1.99 KB, text/html)
2025-03-10 05:06 PDT, Karl Dubost
no flags
Radar WebKit Bug Importer
Comment 1 2025-03-04 13:48:05 PST
Karl Dubost
Comment 2 2025-03-09 22:13:47 PDT
Hi sikulin, Thanks for the report. so using the link you provided in the bug report: I get: * 1648 / STP 214 (Safari 18.4, WebKit 20622.1.2.111.3) (I got once 229) * 448 / Firefox Nightly 138.0a1 (2025-03-09) (aarch64) * 1457 / Chrome Canary 135.0.7039.0 (Official Build) canary (arm64) * 200 / Chrome Canary 136.0.7059.0 (Official Build) canary (arm64) I have the feeling there is more to it than just this number. There should be a better way to compute these differences. And probably not use a playground, but just the code that needs to be measured to avoid external pertubances.
sikulin94
Comment 3 2025-03-09 22:54:01 PDT
Hi, I consistently measured follwing values: Chrome 133.0.6943.142 (arm64): ~280 - 300ms Safari 18.3: ~2400 - 4900ms Thats order of magnitude higher. You can increase count of layers (by 10 multiplications I recommend) to get more significant differences. Slowdown occures in dependence on nesting depth. I cannot demonstrete problem in different way since its must run inside of the browser, so playground is appropriate considering same device and platform. But you can copy paste aforementioned code into your custom enviroment of course. In our case problem was successfully eliminated through elimination of aforementioned problematic parent-child relationship, but users (programmers that use browser) should be aware of that problem and browser incosistencies via some mention on MDN at least.
Karl Dubost
Comment 4 2025-03-09 23:09:11 PDT
I meant an individual testcase independent of react machinery, etc, which would be testing only what needs to be tested without external noise.
sikulin94
Comment 5 2025-03-09 23:28:07 PDT
I undestand, but you can spin your local dev server for react app under 15mins with usage of following tools. Its highly unprobable that playground env. is related to slowdown - its just for demostration since problem was found in context of our app that use CRA and runs locally. I can send files of example in pure htlm, css, js if you want. But its again highly unprobable that these techologies around are culprit since problem was already resolved just by change in css related to sizing inside of flex layout. https://vite.dev/ https://create-react-app.dev/docs/getting-started/
Karl Dubost
Comment 6 2025-03-09 23:33:23 PDT
I know that I can spin a react server. It's not what I'm saying. :) I agree there is a difference. I just want to make a pure html/css/js testcase without any additional interference to avoid the extra noise when testing. :) > I can send files of example in pure htlm, css, js if you want. One file self contained is enough. I will do it later probably. Minimal test cases are always better to compare apples to apples.
sikulin94
Comment 7 2025-03-10 00:50:14 PDT
sikulin94
Comment 8 2025-03-10 00:50:27 PDT
So, here is simple example in pure html, css, js. Results are a lot less significant, but still consistently with meaningful difference. Chrome: ~150ms Safari: ~350 - 400ms Thats ~2.5x longer for Safari. But in our app CPU was 100% and app completely unsuable till tab was killed. Perf. improved to normal state just by removal of display: "flex" or through elimination of parent-child problem when parent is sized implicitly according to content and child had height: "100%" and flex-grow: 1 (both of these found problematic). Changes were made only in css. Count of nested containers was 20. Thats potentialy related to how React handles elements and more complex context, but due to changes being made were only in css and differences so extreme its most probably related to browser engine.
Karl Dubost
Comment 9 2025-03-10 01:34:28 PDT
Created attachment 474509 [details] console in safari, firefox, chrome As designed, the current code is creating * 315 Safari: Uncaught InternalError: allocation size overflow * 165 Firefox: Uncaught RangeError: Invalid string length * 108 Chrome: RangeError: Out of memory So the number is not significative. Let's change the number container.innerHTML = createFlexContainerHtml(20, 1) 20 instead of 200. I get: * Safari: 17-26 ms * Firefox: 131-145 ms * Chrome: 241-294 ms So if anything the current test doesn't show the right thing with container.innerHTML = createFlexContainerHtml(200, 1) as it fails in error, but seems to show Safari more performant with container.innerHTML = createFlexContainerHtml(20, 1) Maybe there is an issue but this test shows the opposite.
Karl Dubost
Comment 10 2025-03-10 01:39:56 PDT
If we change the code to be const start = performance.now(); container.innerHTML = createFlexContainerHtml(20, 1); const end = performance.now(); const duration = end - start; console.log("container.innerHTML took " + duration + " ms"); We get more convergence for the results. but with Safari being more performant. Safari ~ 17 ms Firefox ~ 27 ms Chrome ~ 38 ms
sikulin94
Comment 11 2025-03-10 02:05:35 PDT
sikulin94
Comment 12 2025-03-10 02:09:28 PDT
I changed code little bit to better approximate situation with nested flex layouts and parent-child sizing problem that occured in context of our app and now it seems to be really close. layers: 20 Chrome: ~275ms Safari: CPU in 100% and then tab killed after meaningful time (measurement not completed) This simulates whole situation better and results seem to reflect it.
sikulin94
Comment 13 2025-03-10 02:12:44 PDT
There is probably some infinite loop or loop with too many interations (maybe rather recursive call) related to parent-child relationship. I dont know of course, but whole situation seems to point that way.
Karl Dubost
Comment 14 2025-03-10 05:06:18 PDT
Created attachment 474512 [details] perf testcase OK thanks a lot. Here we are. Working together. I modified the testcase to be self contained and using performanceMark API. The testcase is executing in Firefox and Chrome and is freezing Safari. Firefox: Start loading before container: 2 ms after container: 35 ms DOMContentLoaded: 186 ms Chrome Start loading before container: 0.2 ms after container: 26.6 ms DOMContentLoaded: 292.7 ms ​ Safari… (100% CPU)
sikulin94
Comment 15 2025-03-21 05:52:18 PDT
Hi, can I ask you about approx. expected time of resolution (or start of resolution) since its quite important for our app that also runs on mobile device with iOS where Chrome with its own rendering engine isn't available yet. Thank you for info, Adam.
Sammy Gill
Comment 16 2025-03-21 16:21:22 PDT
Hi Adam, thanks for the report! Unfortunately, I cannot provide any sort of timeline, but I have taken an initial look into the issue. Would you be willing to or are able to share a URL to the content that is experiencing this problem? The test case that you provided is great at reproducing a bug and is something we could definitely work with, but potentially being able to see the content in question could help us come up with a more targeted fix and, more importantly, make sure that it resolves your specific issue.
sikulin94
Comment 17 2025-03-21 20:05:06 PDT
Ok, I understand. I can overcome problem in question through elimination of problematic parent-child relationship in flex layout related to sizing, but it has other unfavourable consequnces that would be too time consuming to optimize. But, anyway, thank you for info. We will have to deal with that. Adam
Note You need to log in before you can comment on or make changes to this bug.