mobile: real slide-in + fade on open, list column untouched = zero reflow (batch129)
The reflow that caused the end-of-slide hitch was never the content slide itself — it was SHOWING the list column during the slide and hiding it (display:flex->none) at the end. So keep .chatcol display:none the whole time (untouched) and animate ONLY .content: it pushes in from translateX(12%)->0 with an opacity fade, on its already-promoted GPU layer. Real slide motion, and nothing to reflow when it ends. (This also explains the batch126 breakage: that made .chatcol position:absolute, disturbing the touch/layout target — not touched here.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1113,8 +1113,8 @@
|
|||||||
/* OPEN = instant position + a quick opacity fade. No transform, no parallax, no list-column display
|
/* OPEN = instant position + a quick opacity fade. No transform, no parallax, no list-column display
|
||||||
toggle → there is literally nothing to reflow when it finishes, so the old ~40ms end-of-slide settle
|
toggle → there is literally nothing to reflow when it finishes, so the old ~40ms end-of-slide settle
|
||||||
is gone by construction. The list (chatcol) stays display:none throughout; content fades in over the bg. */
|
is gone by construction. The list (chatcol) stays display:none throughout; content fades in over the bg. */
|
||||||
body.chat-opening .content{display:block!important;opacity:0;}
|
body.chat-opening .content{display:block!important;opacity:0;transform:translateX(12%);}
|
||||||
body.chat-opening .content.chat-fadein{opacity:1;transition:opacity .14s ease-out;}
|
body.chat-opening .content.chat-fadein{opacity:1;transform:translateX(0);transition:opacity .18s ease-out, transform .24s cubic-bezier(.32,.72,0,1);} /* real slide-in from the right + fade. The list column (.chatcol) is NEVER shown during the open — it stays display:none throughout — so there is no display toggle and therefore no reflow when the slide ends. Content is already on its own GPU layer (will-change on body.chat-open), so this is a pure compositor transform. */
|
||||||
/* CLOSE / drag-back: reveal the list underneath (parallax in) while the conversation slides off right
|
/* CLOSE / drag-back: reveal the list underneath (parallax in) while the conversation slides off right
|
||||||
(.content moved by an inline transform in showWelcome()/the edge-drag gesture). */
|
(.content moved by an inline transform in showWelcome()/the edge-drag gesture). */
|
||||||
body.chat-closing .content, body.chat-dragging .content{display:block!important;z-index:2;box-shadow:-12px 0 30px rgba(15,23,42,.18);will-change:transform;}
|
body.chat-closing .content, body.chat-dragging .content{display:block!important;z-index:2;box-shadow:-12px 0 30px rgba(15,23,42,.18);will-change:transform;}
|
||||||
@@ -1146,7 +1146,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="/icons.js?v=6"></script>
|
<script src="/icons.js?v=6"></script>
|
||||||
<script>window.__BUILD='2026-07-19-batch128';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
<script>window.__BUILD='2026-07-19-batch129';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||||
// Emoji are rendered with the OS's own (colour) emoji font — instant, zero network.
|
// Emoji are rendered with the OS's own (colour) emoji font — instant, zero network.
|
||||||
//
|
//
|
||||||
// We used to run Twemoji over every emoji, which swapped each one for an <img> pulled INDIVIDUALLY from
|
// We used to run Twemoji over every emoji, which swapped each one for an <img> pulled INDIVIDUALLY from
|
||||||
@@ -2835,13 +2835,13 @@ function armOpenSlide(){
|
|||||||
if(c) c.classList.remove('chat-fadein');
|
if(c) c.classList.remove('chat-fadein');
|
||||||
flushSlideQueue(); // network reconcile / pins / queued appends run now
|
flushSlideQueue(); // network reconcile / pins / queued appends run now
|
||||||
};
|
};
|
||||||
_slideEndHandler=function(e){ if(e.target===c && e.propertyName==='opacity') done(); };
|
_slideEndHandler=function(e){ if(e.target===c && e.propertyName==='transform') done(); }; // transform is the longer of the two transitions → fires after both finish
|
||||||
if(c) c.addEventListener('transitionend', _slideEndHandler);
|
if(c) c.addEventListener('transitionend', _slideEndHandler);
|
||||||
requestAnimationFrame(()=>{
|
requestAnimationFrame(()=>{
|
||||||
if(window.__slideTok!==token) return;
|
if(window.__slideTok!==token) return;
|
||||||
if(window.__perfProbe) window.__perfProbe('slide'); // TEMP: measure frame timing over the open
|
if(window.__perfProbe) window.__perfProbe('slide'); // TEMP: measure frame timing over the open
|
||||||
if(c) c.classList.add('chat-fadein'); // opacity 0 -> 1 over 140ms (compositor-only)
|
if(c) c.classList.add('chat-fadein'); // slide translateX(12%)->0 + opacity 0->1 (pure compositor)
|
||||||
window.__chatOpenT=setTimeout(done, 240); // fallback if transitionend is missed (140ms + margin)
|
window.__chatOpenT=setTimeout(done, 320); // fallback if transitionend is missed (240ms + margin)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async function openConvo(kind,id){
|
async function openConvo(kind,id){
|
||||||
|
|||||||
Reference in New Issue
Block a user