Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor: Improve render performance (scrolling and typing) #23568

Closed
wants to merge 9 commits into from
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions packages/block-editor/src/components/inserter/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ $block-inserter-tabs-height: 44px;
@include break-medium {
position: relative;
}

&__content {
// This improves render performance when scrolling.
// It promotes this element to a dedicated "layer" in the browser. The rendering
// is then assisted by the GPU, which improves performance.
// See: https://aerotwist.com/blog/on-translate3d-and-layer-creation-hacks/
transform: translate3d(0, 0, 0);
}
}

.block-editor-inserter__popover .block-editor-inserter__menu {
Expand Down
1 change: 1 addition & 0 deletions packages/edit-post/src/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ function Layout() {
<KeyboardShortcutHelpModal />
<WelcomeGuide />
<Popover.Slot />
<Popover.Slot name="block-toolbar" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this slot was not rendered her for a valid reason. Otherwise, it just duplicated the slot that is above it. cc @ellatrix

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@youknowriad Hmm! Interesting.. I wasn't aware of that !

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be rendered in the content scroll container, because when you scroll while the pointer is over the toolbar, the content still needs to scroll.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have commented here 😅
There might be other reasons I'm forgetting.

<PluginArea />
</FocusReturnProvider>
</>
Expand Down
18 changes: 16 additions & 2 deletions packages/edit-post/src/components/layout/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@
}
}

.edit-post-layout .interface-interface-skeleton__content {
background-color: $light-gray-700;
.edit-post-layout {
.interface-interface-skeleton__content {
background-color: $light-gray-700;
}
}

.edit-post-layout__inserter-panel {
Expand Down Expand Up @@ -136,3 +138,15 @@
height: 100%;
}
}

.edit-post-sidebar {
// This improves render performance when scrolling.
// It promotes this element to a dedicated "layer" in the browser. The rendering
// is then assisted by the GPU, which improves performance.
// See: https://aerotwist.com/blog/on-translate3d-and-layer-creation-hacks/
transform: translate3d(0, 0, 0);

> .components-panel {
transform: translate3d(0, 0, 0);
}
}
2 changes: 0 additions & 2 deletions packages/edit-post/src/components/visual-editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
__experimentalBlockSettingsMenuFirstItem,
__experimentalUseResizeCanvas as useResizeCanvas,
} from '@wordpress/block-editor';
import { Popover } from '@wordpress/components';

/**
* Internal dependencies
Expand All @@ -38,7 +37,6 @@ function VisualEditor() {
>
<VisualEditorGlobalKeyboardShortcuts />
<MultiSelectScrollIntoView />
<Popover.Slot name="block-toolbar" />
<Typewriter>
<CopyHandler>
<WritingFlow>
Expand Down
1 change: 1 addition & 0 deletions packages/interface/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"dependencies": {
"@babel/runtime": "^7.9.2",
"@wordpress/components": "file:../components",
"@wordpress/compose": "file:../compose",
"@wordpress/data": "file:../data",
"@wordpress/element": "file:../element",
"@wordpress/i18n": "file:../i18n",
Expand Down
18 changes: 16 additions & 2 deletions packages/interface/src/components/interface-skeleton/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';
import { useEffect, useRef } from '@wordpress/element';
import { navigateRegions } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { useObserveInterfaceHeight } from './utils';

function useHTMLClass( className ) {
useEffect( () => {
const element =
Expand All @@ -36,6 +41,11 @@ function InterfaceSkeleton( {
} ) {
useHTMLClass( 'interface-interface-skeleton__html-container' );

const bodyNodeRef = useRef();
const { resizeListener } = useObserveInterfaceHeight( {
ref: bodyNodeRef,
} );

const defaultLabels = {
/* translators: accessibility text for the top bar landmark region. */
header: __( 'Header' ),
Expand All @@ -60,6 +70,7 @@ function InterfaceSkeleton( {
'interface-interface-skeleton'
) }
>
{ resizeListener }
{ !! header && (
<div
className="interface-interface-skeleton__header"
Expand All @@ -70,7 +81,10 @@ function InterfaceSkeleton( {
{ header }
</div>
) }
<div className="interface-interface-skeleton__body">
<div
className="interface-interface-skeleton__body"
ref={ bodyNodeRef }
>
{ !! leftSidebar && (
<div
className="interface-interface-skeleton__left-sidebar"
Expand Down
21 changes: 21 additions & 0 deletions packages/interface/src/components/interface-skeleton/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,27 @@ html.interface-interface-skeleton__html-container {
overscroll-behavior-y: none;
}

.interface-interface-skeleton__content,
.interface-interface-skeleton__left-sidebar,
.interface-interface-skeleton__sidebar {
// This improves render performance when interacting with the DOM.
// The Interface scrollable elements use adaptive CSS properties to calculate
// height on initial render. However, anytime interactions happen
// (e.g. typing), the browser needs to recalculate layout measurements
// in order to adjust scroll height.
// The --wp-editor--body-height CSS variable is calculated by JavaScript.
// It provides a fixed (px) value, which reduces the browser's need to
// recalculate height values on interaction. The height value is updated
// on resize-based events.
height: var(--wp-editor--body-height, 100%);

// This improves render performance when scrolling.
// It promotes this element to a dedicated "layer" in the browser. The rendering
// is then assisted by the GPU, which improves performance.
// See: https://aerotwist.com/blog/on-translate3d-and-layer-creation-hacks/
transform: translate3d(0, 0, 0);
}

.interface-interface-skeleton__content {
flex-grow: 1;

Expand Down
40 changes: 40 additions & 0 deletions packages/interface/src/components/interface-skeleton/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';
import { useResizeObserver } from '@wordpress/compose';

const SKELETON_BODY_HEIGHT_CSS_PROP = '--wp-editor--body-height';

export function useObserveInterfaceHeight( { ref } ) {
const [ resizeListener, sizes ] = useResizeObserver();

/*
* This calculates and sets a body height for the inner
* content, sidebar, and complementary areas. This improves performance,
* as we can avoid having the browser (re)calculate layout values on
* interaction (e.g. typing).
*/
const setBodyHeightValue = () => {
const bodyHeight = ref.current?.clientHeight;
if ( bodyHeight ) {
const nextHeight = window.innerHeight - bodyHeight;
// We're using calc with a 100vh offset improve responsiveness
// when resizing the browser's height. Using a fixed pixel value
// directly may result in double scrollbar flickering.
const nextHeightValue = `calc(100vh - ${ nextHeight }px)`;

// We'll set the value as a custom CSS variable.
// The inner content, sidebar, and complementary areas are
// "subscribed" to this value using CSS.
document.documentElement.style.setProperty(
SKELETON_BODY_HEIGHT_CSS_PROP,
nextHeightValue
);
}
};

useEffect( setBodyHeightValue, [ sizes.height ] );

return { resizeListener };
}