fix: blank chat messages on iOS home screen apps and in-app browsers (#29734)

Chat messages are virtualized with content-visibility: auto, which WebKit paints incorrectly and can leave blank. #26805 skipped that on Safari by looking for the Safari token in the user agent, but iOS in-app browsers, home screen apps and iPadOS desktop-class standalone windows send no such token, so those users still get empty assistant responses.

Check the navigator vendor string as well, which every WebKit surface reports regardless of user agent. The user agent check stays, because non-Apple WebKit ports can compile a different vendor string while shipping the same paint bug.

That earlier fix also withheld the message-listitem class entirely, and the class doubles as the styling hook the sidebar hover preview reaches through, so hover previews have rendered at full chat spacing and width on Safari since v0.11.0. Only the content-visibility rule is gated now, on its own class, and the hook stays on every message. Safari hover previews become compact like every other engine.

Verified across fourteen engine cases: virtualization is off on every Apple WebKit surface, unchanged on Chromium, Firefox and Android, the hover preview overrides apply again on Safari, and the screenshot export still captures every message on both.

Refs #26712, #29688
This commit is contained in:
Classic298 2026-09-06 21:21:09 +02:00 committed by GitHub
parent 68a74da70b
commit a3c90e5aac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 10 additions and 6 deletions

View file

@ -49,16 +49,20 @@
export let topPadding = false;
export let onInsertToNote: ((content: string) => void) | null = null;
// Safari's content-visibility implementation has paint bugs that leave
// WebKit's content-visibility implementation has paint bugs that leave
// on-screen messages blank (#26712), so skip virtualization there
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
// iOS WebViews and home screen apps carry no Safari token, hence the vendor check
const isWebKit =
navigator.vendor === 'Apple Computer, Inc.' ||
/^((?!chrome|android).)*safari/i.test(navigator.userAgent);
</script>
<div
role="listitem"
class="flex flex-col justify-between px-3.5 mb-3 w-full {($settings?.widescreenMode ?? null)
? 'max-w-full'
: 'max-w-[58rem]'} mx-auto rounded-lg group {isSafari ? '' : 'message-listitem'}"
: 'max-w-[58rem]'} mx-auto rounded-lg group message-listitem"
class:message-virtualized={!isWebKit}
>
{#if history.messages[messageId]}
{#if history.messages[messageId].role === 'user'}
@ -154,7 +158,7 @@
/* Browser-native virtualization: skip rendering of off-screen messages
without destroying their component trees. Replaces the JS-based
culling that caused catastrophic mount/destroy thrashing. */
.message-listitem {
.message-virtualized {
content-visibility: auto;
contain-intrinsic-size: auto 150px;
}

View file

@ -105,7 +105,7 @@
document.body.appendChild(clonedElement);
// Override content-visibility so html2canvas can capture all messages
clonedElement.querySelectorAll('.message-listitem').forEach((el) => {
clonedElement.querySelectorAll('.message-virtualized').forEach((el) => {
el.style.contentVisibility = 'visible';
});

View file

@ -120,7 +120,7 @@
document.body.appendChild(clonedElement);
// Override content-visibility so html2canvas can capture all messages
clonedElement.querySelectorAll('.message-listitem').forEach((el) => {
clonedElement.querySelectorAll('.message-virtualized').forEach((el) => {
el.style.contentVisibility = 'visible';
});