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

WBOY
リリース: 2016-06-21 08:54:43
オリジナル
996 人が閲覧しました

注: この記事は 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 による記事「レンダリング: リペイント、リフロー/リレイアウト、リスタイル」に記載されています。詳細をご覧ください~

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート