diff --git a/web/styles/tokens.css b/web/styles/tokens.css index ea89a2f..e0b4b0f 100644 --- a/web/styles/tokens.css +++ b/web/styles/tokens.css @@ -112,6 +112,11 @@ body, height: 100%; } +/* 页面高度跨过视口阈值时滚动条出现消失,内容会横向抖一下;把滚动条的位置常驻留出来 */ +html { + scrollbar-gutter: stable; +} + body { margin: 0; background: var(--c-bg); diff --git a/web/views/InboundDetail.vue b/web/views/InboundDetail.vue index fefd377..6d92ef5 100644 --- a/web/views/InboundDetail.vue +++ b/web/views/InboundDetail.vue @@ -158,23 +158,29 @@ function lockHeight() { } /** - * v-if 内容的展开收起动画:高度在 0 和实际值之间过渡,结束后清掉内联样式。 - * 给配置表单和链式代理段用。auto 高度不可插值,只能量出来做。 + * v-if 内容的展开收起动画:高度和上外边距一起在 0 和实际值之间过渡,结束后清掉 + * 内联样式。给配置表单和链式代理段用。auto 高度不可插值,只能量出来做。 + * 外边距必须一起动:链式代理段顶着 .block + .block 给的 24px margin,它在高度 + * 动画之外,不带上它出现和消失的瞬间就各抖一下。 */ function foldEnter(element: Element, done: () => void) { const el = element as HTMLElement // 先量再压:此刻元素是自然高度,revealBottom 量到的就是折叠结束后的位置 revealBottom() + const margin = getComputedStyle(el).marginTop el.style.height = '0' + el.style.marginTop = '0' el.style.overflow = 'hidden' void el.offsetHeight - el.style.transition = 'height 0.15s ease' + el.style.transition = 'height 0.15s ease, margin-top 0.15s ease' el.style.height = `${String(el.scrollHeight)}px` + el.style.marginTop = margin el.addEventListener( 'transitionend', () => { el.style.transition = '' el.style.height = '' + el.style.marginTop = '' el.style.overflow = '' done() }, @@ -187,8 +193,9 @@ function foldLeave(element: Element, done: () => void) { el.style.height = `${String(el.offsetHeight)}px` el.style.overflow = 'hidden' void el.offsetHeight - el.style.transition = 'height 0.15s ease' + el.style.transition = 'height 0.15s ease, margin-top 0.15s ease' el.style.height = '0' + el.style.marginTop = '0' el.addEventListener('transitionend', done, { once: true }) }