注: この記事は Tencent AlloyTeam の Yuan Yan によるものです。この記事は github でもご覧いただけます。著作権を尊重してください。転載する場合は出典を明記してください。ありがとうございます~~
PC のシナリオと比較して、高性能モバイル Web では、ますます複雑な要素を考慮する必要があります。トラフィックと電力。消費量と流暢さ。 PC時代ではエクスペリエンスのスムーズさをより重視しますが、モバイル側のリッチなシナリオでは、ユーザー基地局のネットワークトラフィックの使用量や機器の消費電力に特別な注意を払う必要があります。
流暢さに関しては、主にフロントエンド アニメーションに反映されます。既存のフロントエンド アニメーション システムには、通常、JS アニメーションと CSS3 アニメーションの 2 つのモードがあります。 JS アニメーションは、JS を使用してスタイルを動的に書き換えてアニメーション機能を実現するソリューションであり、ローエンドのブラウザーと互換性のある PC に推奨されるソリューションです。モバイル側では、パフォーマンスに優れたネイティブ ブラウザ実装である CSS3 アニメーションを選択します。
ただし、CSS3 アニメーションは、モバイル マルチ端末デバイスのシナリオでは PC よりも多くのパフォーマンスの問題に直面することになります。これは主にアニメーションの途切れやちらつきに反映されます。
現在、モバイル端末で CSS3 アニメーション エクスペリエンスを向上させる主な方法がいくつかあります。
-webkit-transform: translate3d(0, 0, 0);-moz-transform: translate3d(0, 0, 0);-ms-transform: translate3d(0, 0, 0);transform: translate3d(0, 0, 0);
アニメーション中にちらつきがある場合 (通常はアニメーションの開始時に発生します)、次のハックを試すことができます:
-webkit-backface-visibility: hidden;-moz-backface-visibility: hidden;-ms-backface-visibility: hidden;backface-visibility: hidden;-webkit-perspective: 1000;-moz-perspective: 1000;-ms-perspective: 1000;perspective: 1000;
たとえば、次の要素を 500 ピクセル移動したとします。 translation3d を右に使用すると、アニメーションの滑らかさが left 属性を使用するよりも大幅に向上します:
#ball-1 { transition: -webkit-transform .5s ease; -webkit-transform: translate3d(0, 0, 0);}#ball-1.slidein { -webkit-transform: translate3d(500px, 0, 0);}#ball-2 { transition: left .5s ease; left: 0;}#ball-2.slidein { left: 500px;}
注: 3D 変形はより多くのメモリと電力消費を消費します。実際のパフォーマンスに問題がある場合にのみ使用してください。
ボックス シャドウとグラデーションは、特に 1 つの要素で使用される場合、ページのパフォーマンスを低下させることがよくあります。同時に、フラットデザインを採用してください。
position: fixed; position: absolute;
このトピックについては、次の例から説明します。 🎜 >
var newWidth = aDiv.offsetWidth + 10; aDiv.style.width = newWidth + 'px'; var newHeight = aDiv.offsetHeight + 10; aDiv.style.height = newHeight + 'px';var newWidth = aDiv.offsetWidth + 10; var newHeight = aDiv.offsetHeight + 10; aDiv.style.width = newWidth + 'px'; aDiv.style.height = newHeight + 'px';
// 触发两次 layoutvar newWidth = aDiv.offsetWidth + 10; // Read aDiv.style.width = newWidth + 'px'; // Write var newHeight = aDiv.offsetHeight + 10; // Read aDiv.style.height = newHeight + 'px'; // Write// 只触发一次 layoutvar newWidth = aDiv.offsetWidth + 10; // Read var newHeight = aDiv.offsetHeight + 10; // Read aDiv.style.width = newWidth + 'px'; // Write aDiv.style.height = newHeight + 'px'; // Write
結論から言うと、これはブラウザの最適化戦略と関係があるようです。レイアウトをトリガーできるすべての操作は、レイアウト キューに一時的に置かれ、更新する必要がある場合、キュー全体のすべての操作の結果が計算されるため、レイアウトは 1 回だけ実行でき、パフォーマンスが向上します。
重要なのは、レイアウトをトリガーできる操作です (リフローまたは再レイアウトとも呼ばれます)。
オープンソース Webkit/Blink を例として、ブラウザーのソース コード実装から始めます。レイアウトを更新するために、Webkit は主に Document::updateLayout と Document::updateLayoutIgnorePendingStylesheets の 2 つのメソッドを使用します。 🎜>
updateLayoutIgnorePendingStylesheets メソッドの内部実装から、これが updateLayout メソッドの拡張でもあることがわかります。また、既存のレイアウト更新モードでは、ほとんどのシナリオで updateLayoutIgnorePendingStylesheets を呼び出してレイアウトを更新します。
void Document::updateLayout() { ASSERT(isMainThread()); FrameView* frameView = view(); if (frameView && frameView->isInLayout()) { ASSERT_NOT_REACHED(); return; } if (Element* oe = ownerElement()) oe->document()->updateLayout(); updateStyleIfNeeded(); StackStats::LayoutCheckPoint layoutCheckPoint; if (frameView && renderer() && (frameView->layoutPending() || renderer()->needsLayout())) frameView->layout(); if (m_focusedNode && !m_didPostCheckFocusedNodeTask) { postTask(CheckFocusedNodeTask::create()); m_didPostCheckFocusedNodeTask = true; }}void Document::updateLayoutIgnorePendingStylesheets() { bool oldIgnore = m_ignorePendingStylesheets; if (!haveStylesheetsLoaded()) { m_ignorePendingStylesheets = true; HTMLElement* bodyElement = body(); if (bodyElement && !bodyElement->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) { m_pendingSheetLayout = DidLayoutWithPendingSheets; styleResolverChanged(RecalcStyleImmediately); } else if (m_hasNodesWithPlaceholderStyle) recalcStyle(Force); } updateLayout(); m_ignorePendingStylesheets = oldIgnore;}
Webkit 実装で updateLayoutIgnorePendingStylesheets メソッドを呼び出すコードを検索し、レイアウトをトリガーできる次の操作を取得します。