Maison > interface Web > tutoriel CSS > Les deux lignes de CSS qui ont miné les performances (fps en ps)

Les deux lignes de CSS qui ont miné les performances (fps en ps)

WBOY
Libérer: 2024-09-03 11:09:21
original
953 Les gens l'ont consulté

J'ai récemment publié Learn WCs et si vous l'avez vu, vous avez probablement remarqué l'animation en arrière-plan, où les cercles colorés se déplacent en diagonale sur l'écran. Cela ressemble à ceci :

Cela fonctionne bien sur Chrome et Safari, mais j'ai remarqué une forte baisse des performances sur Firefox.

Les performances étaient si mauvaises que j'ai directement désactivé cette animation dans Firefox.

Comment fonctionne l'animation ?

L'animation est construite à l'aide de deux divs imbriqués. Le div externe est le premier enfant de la balise body du site.

<body>
    <div class="background-mask">
        <div class="background-gradient"></div>
    </div>

    <!-- Rest of content -->
</body>
Copier après la connexion

L'élément .background-gradient est chargé de créer un dégradé qui s'étend sur toute la largeur et la hauteur de son conteneur parent. Comme ça :

The Two Lines of CSS That Tanked Performance (fps to ps)

Le masque .background externe est responsable de deux choses :

  1. Il définit la position sur fixe et fait en sorte que le conteneur remplisse toutes les dimensions de la fenêtre.
  2. Crée un masque en pointillés sur le dégradé

Cela garantit que la couleur des points est la couleur du dégradé directement en dessous :

The Two Lines of CSS That Tanked Performance (fps to ps)

Voici le CSS pour tout ce que j'ai décrit ci-dessus :

.background-mask {
    --mask-size: 24px;

    /* Position Styles */
    position: fixed;
    width: 100%;
    height: 100%;
    z-index: -1;

    /* Mask Styles */
    mask-image: radial-gradient(black 2px, transparent 2px);
    mask-size: var(--mask-size) var(--mask-size);
    mask-position: 0px 0px;
    animation: mask-move 3s infinite linear;
}

.background-gradient {
    background: var(--red);
    background-image: var(--gradient);
    width: 100%;
    height: 100%;
}

@keyframes mask-move {
    0% {
        mask-position: 0px 0px;
    }

    100% {
        mask-position: var(--mask-size) var(--mask-size);
    }
}

@media (prefers-reduced-motion: reduce) {
    .hero-background-mask {
        animation: none;
    }
}
Copier après la connexion

Si vous souhaitez en savoir plus sur les masques en CSS, je peux vous recommander cet article complet d'Ahmad Shadeed

Quelle est la cause de cette baisse de performances ?

Toutes les propriétés CSS ne s’animent pas de la même manière. Sans trop entrer dans les détails de la manière dont le navigateur affiche le code HTML sur la page (même si je l'ai décrit ici), il passe par une poignée d'étapes. Les trois étapes qui nous intéressent sont :

  • Mise en page - Lorsque le navigateur calcule la taille et les positions des éléments sur la page
  • Paint - Dessine tous les aspects visuels de la page, comme les images, les couleurs, les ombres, etc.
  • Composite - Superposer les éléments les uns sur les autres dans le bon ordre

L'ordre du pipeline ressemble à ceci :

Mise en page → Peinture → Composite

Les processus de mise en page et de peinture peuvent être gourmands en CPU, il est donc important d'essayer de réduire le nombre de fois où votre CSS déclenche les étapes du pipeline*.* Le navigateur aide dans une certaine mesure en optimisant les performances de certaines propriétés, d'autres ignorez des étapes entières du pipeline de rendu et d'autres peuvent tirer parti de l'accélération matérielle pour déplacer le calcul du CPU vers le GPU.

L'animation de certaines propriétés, comme translation et opacity , évite de déclencher une mise en page et utilise l'accélération matérielle.

Malheureusement, ce n'est pas le cas lors de l'animation de la position du masque. J'ai jeté un œil à Chrome et j'ai vu que le nombre de peintures pour le div d'arrière-plan augmentait à chaque image. Au bout de quelques secondes, il avait déjà déclenché une peinture plus de 1 000 fois.

The Two Lines of CSS That Tanked Performance (fps to ps)

Même avec ce nombre de peintures élevé, l'animation sur Chrome est fluide. Cependant, cela semble super bizarre sur Firefox. Malheureusement, je n’ai pas trouvé de moyen de mesurer le nombre de peintures sur Firefox, donc toutes les hypothèses que je fais sur les mauvaises performances de Firefox ne sont que des conjectures.

Ce que j'ai remarqué, c'est que l'animation convient aux petits appareils, mais s'aggrave à mesure que la taille de l'écran augmente. Ma théorie de travail est que Firefox ne regroupe pas les déclencheurs de mise en page pour chacun des masques 24x24, ce qui provoque un ralentissement du FPS lorsque davantage de masques 24x24 sont présents. Encore une fois, je me trompe peut-être complètement.

Comment ai-je résolu ce problème ?

Au lieu d'animer des propriétés CSS mal optimisées comme mask-position , j'avais besoin de m'appuyer sur les propriétés plus performantes, comme traduire.

La solution n'était pas de déplacer les masques de 24 pixels, mais de déplacer tout l'élément d'arrière-plan à l'aide de la propriété Translate.

From an abstract standpoint, this is how the animation looks:

Here’s the two line change in the CSS:

/* --mask-size = 24px */

@keyframes mask-move {
    0% {
        transform: translate(calc(var(--mask-size) * -1), calc(var(--mask-size) * -1));
    }

    100% {
        transform: translate(0px, 0px);
    }
}
Copier après la connexion

The browser no longer animates the mask-position, which triggered a layout on each frame. Even though the background moves on each frame, through translate it doesn’t trigger a layout or a paint. You can see that the only paints twice, down from 1,000+ every minute.

The Two Lines of CSS That Tanked Performance (fps to ps)

Eagle-eyed viewers will have spotted a problem. If you remember, the height and width of the background fills the viewport. Shifting the background left and up by 24px leaves us with this empty space in the viewport.

The Two Lines of CSS That Tanked Performance (fps to ps)

Solving it is as simple as adding the mask size to the width and height of the container:

.background-mask {
    --mask-size: 24px;

    width: calc(100% + var(--mask-size));
    height: calc(100% + var(--mask-size));
}
Copier après la connexion

Let’s take a look again in Firefox:

It may not be a perfect solution, but it’s always a little satisfying pulling off a fun smoke and mirrors CSS trick.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal