ホームページ >ウェブフロントエンド >htmlチュートリアル >高性能CSS3アニメーション_html/css_WEB-ITnose

高性能CSS3アニメーション_html/css_WEB-ITnose

WBOY
WBOYオリジナル
2016-06-21 08:54:431006ブラウズ

注: この記事は Tencent AlloyTeam の Yuan Yan によるものです。この記事は github でもご覧いただけます。著作権を尊重してください。転載する場合は出典を明記してください。ありがとうございます~~

PC のシナリオと比較して、高性能モバイル Web では、ますます複雑な要素を考慮する必要があります。トラフィックと電力。消費量と流暢さ。 PC時代ではエクスペリエンスのスムーズさをより重視しますが、モバイル側のリッチなシナリオでは、ユーザー基地局のネットワークトラフィックの使用量や機器の消費電力に特別な注意を払う必要があります。

流暢さに関しては、主にフロントエンド アニメーションに反映されます。既存のフロントエンド アニメーション システムには、通常、JS アニメーションと CSS3 アニメーションの 2 つのモードがあります。 JS アニメーションは、JS を使用してスタイルを動的に書き換えてアニメーション機能を実現するソリューションであり、ローエンドのブラウザーと互換性のある PC に推奨されるソリューションです。モバイル側では、パフォーマンスに優れたネイティブ ブラウザ実装である CSS3 アニメーションを選択します。

ただし、CSS3 アニメーションは、モバイル マルチ端末デバイスのシナリオでは PC よりも多くのパフォーマンスの問題に直面することになります。これは主にアニメーションの途切れやちらつきに反映されます。

現在、モバイル端末で CSS3 アニメーション エクスペリエンスを向上させる主な方法がいくつかあります。

3D 変形を使用して GPU アクセラレーションを有効にするなど、可能な限り多くのハードウェア機能を使用します

-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;  

DOM レイアウトのパフォーマンスを最適化する

このトピックについては、次の例から説明します。 🎜 >

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';  
これらは機能において完全に同等の 2 つのコードですが、明らかな違いは実行順序のみです。しかし、本当にそうなのでしょうか?以下は、説明コメント付きのコード バージョンで、さらなる違いがよく説明されています:

// 触发两次 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  
コメントからルール、offsetWidth/Height 属性の連続読み取り、および幅/高さの連続設定を見つけることができます。属性を使用すると、個々の属性を個別に読み取って設定するよりも 1 回少ない時間でレイアウトをトリガーできます。

結論から言うと、これはブラウザの最適化戦略と関係があるようです。レイアウトをトリガーできるすべての操作は、レイアウト キューに一時的に置かれ、更新する必要がある場合、キュー全体のすべての操作の結果が計算されるため、レイアウトは 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 メソッドを呼び出すコードを検索し、レイアウトをトリガーできる次の操作を取得します。

    要素: clientHeight、clientLeft、clientTop、 clientWidth、focus() 、getBoundingClientRect()、getClientRects()、innerText、offsetHeight、offsetLeft、offsetParent、offsetTop、offsetWidth、outerText、scrollByLines()、scrollByPages()、scrollHeight、scrollIntoView()、scrollIntoViewIfNeeded()、scrollLeft、scrollTop、 scrollWidth
  • フレーム、HTMLImageElement : 高さ、幅
  • 範囲 : getBoundingClientRect()、getClientRects()
  • SVGLocatable : computeCTM()、getBBox()
  • SVGTextContent: getCharNumAtPosition()、getComputedTextLength()、getEndPositionOfChar()、getExtentOfChar()、getNumberOfChars()、getRotationOfChar()、 getStartPositionOfChar()、getSubStringLength ()、selectSubString()
  • SVGUse :instanceRoot
  • ウィンドウ : getComputedStyle()、scrollBy()、scrollTo( )、scrollX、scrollY 、webkitConvertPointFromNodeToPage()、webkitConvertPointFromPageToNode()
  • レイアウトをさらに詳しく見ていきます。上記で更新する必要がある必要な条件は何ですか? より詳細な答えは、Stoyan Stefanov による記事「レンダリング: リペイント、リフロー/リレイアウト、リスタイル」に記載されています。詳細をご覧ください~

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。