Intelligence de données générative

Les pseudo-classes et les pseudo-éléments des composants Web sont plus simples que vous ne le pensez

Date :

Nous avons beaucoup discuté des aspects internes de l'utilisation de CSS dans ce série en cours sur les composants Web, mais il y a quelques pseudo-éléments et pseudo-classes spéciaux qui, comme de bons amis, sentent volontiers votre haleine peut-être halitotique avant d'aller parler à cet intérêt amoureux potentiel. Vous savez, ils vous aident quand vous en avez le plus besoin. Et, comme un bon ami vous tendra un bonbon à la menthe, ces pseudo-éléments et pseudo-classes vous fournissent des solutions à la fois de dans les le composant Web et à partir de au contrôle le composant Web — le site Web sur lequel se trouve le composant Web.

Je fais spécifiquement référence au ::part ainsi que le ::slotted les pseudo-éléments, et les :defined, :hostet une :host-context pseudo-classes. Ils nous donnent des moyens supplémentaires d'interagir avec les composants Web. Examinons-les de plus près.

Série d'articles

Les ::part pseudo-élément

::part, en bref, vous permet de percer l'arbre d'ombre, ce qui est juste ma façon de dire du Seigneur des Anneaux, il vous permet de styliser des éléments à l'intérieur le DOM fantôme de au contrôle le DOM fantôme. En théorie, vous devriez encapsuler tous vos styles pour le shadow DOM dans le shadow DOM, c'est-à-dire dans un <style> élément dans votre <template> .

Donc, étant donné quelque chose comme ça depuis le tout première partie de cette série, où vous avez un <h2> dans votre <template>, vos styles pour ça <h2> devraient tous être dans le <style> .

<template id="zprofiletemplate"> <style> h2 { font-size: 3em; margin: 0 0 0.25em 0; line-height: 0.8; } /* other styles */ </style> <div class="profile-wrapper"> <div class="info"> <h2> <slot name="zombie-name">Zombie Bob</slot> </h2> <!-- other zombie profile info --> </div>
</template>

Mais parfois, nous pouvons avoir besoin de styliser un élément dans le shadow DOM en fonction des informations qui existent sur la page. Par exemple, disons que nous avons une page pour chaque zombie dans le système d'amour éternel avec des correspondances. Nous pourrions ajouter une classe aux profils en fonction de leur degré de correspondance. Nous pourrions alors, par exemple, mettre en surbrillance le nom d'un match s'il est un bon match. La proximité d'une correspondance varie en fonction de la liste des correspondances potentielles affichées et nous ne connaîtrons pas cette information tant que nous ne serons pas sur cette page, nous ne pouvons donc pas intégrer la fonctionnalité dans le composant Web. Depuis le <h2> est dans le shadow DOM, cependant, nous ne pouvons pas y accéder ou le styler de l'extérieur du shadow DOM, ce qui signifie un sélecteur de zombie-profile h2 sur la page des matchs ne fonctionnera pas.

Mais, si nous apportons un léger ajustement à la <template> balisage en ajoutant un part attribuer à la <h2>:

<template id="zprofiletemplate"> <style> h2 { font-size: 3em; margin: 0 0 0.25em 0; line-height: 0.8; } /* other styles */ </style> <div class="profile-wrapper"> <div class="info"> <h2 part="zname"> <slot name="zombie-name">Zombie Bob</slot> </h2> <!-- other zombie profile info --> </div>
</template>

Comme un spray de Bianca dans la bouche, nous avons maintenant les super pouvoirs pour franchir la barrière de l'ombre DOM et styliser ces éléments de au contrôle des <template>:

/* External stylesheet */
.high-match::part(zname) { color: blue;
}
.medium-match::part(zname) { color: navy;
}
.low-match::part(zname) { color: slategray;
}

Il y a beaucoup de choses à considérer quand il s'agit d'utiliser CSS ::part. Par exemple, styliser un élément à l'intérieur d'une pièce est impossible :

/* frowny-face emoji */
.high-match::part(zname) span { ... }

Mais vous pouvez ajouter un part attribut sur cet élément et stylisez-le via son propre nom de pièce.

Que se passe-t-il si nous avons un composant Web dans un autre composant Web ? Volonté ::part travaille toujours? Si le composant Web apparaît dans le balisage de la page, c'est-à-dire que vous l'insérez, ::part fonctionne très bien à partir du CSS de la page principale.

<zombie-profile class="high-match"> <img slot="profile-image" src="https://assets.codepen.io/1804713/leroy.png" /> <span slot="zombie-name">Leroy</span> <zombie-details slot="zdetails"> <!-- Leroy's details --> </zombie-details>
</zombie-profile>

Mais si le composant Web se trouve dans le DOM modèle/ombre, alors ::part ne peut pas percer les deux arbres d'ombre, juste le premier. Nous devons apporter le ::part dans la lumière… pour ainsi dire. Nous pouvons le faire avec un exportparts attribuer.

Pour illustrer cela, nous ajouterons un "filigrane" derrière les profils à l'aide d'un composant Web. (Pourquoi ? Croyez-le ou non, c'était l'exemple le moins artificiel que j'ai pu trouver.) Voici nos modèles : (1) le modèle pour <zombie-watermark>, et (2) le même modèle pour <zombie-profile> mais avec ajouté un <zombie-watermark> élément à la fin.

<template id="zwatermarktemplate"> <style> div { text-transform: uppercase; font-size: 2.1em; color: rgb(0 0 0 / 0.1); line-height: 0.75; letter-spacing: -5px; } span { color: rgb( 255 0 0 / 0.15); } </style> <div part="watermark"> U n d y i n g L o v e U n d y i n g L o v e U n d y i n g L o v e <span part="copyright">©2 0 2 7 U n d y i n g L o v e U n L t d .</span> <!-- Repeat this a bunch of times so we can cover the background of the profile --> </div> </template>
<template id="zprofiletemplate"> <style> ::part(watermark) { color: rgb( 0 0 255 / 0.1); } /* More styles */ </style> <!-- zombie-profile markup --> <zombie-watermark exportparts="copyright"></zombie-watermark>
</template>
<style> /* External styles */ ::part(copyright) { color: rgb( 0 100 0 / 0.125); }
</style>

Depuis que ::part(watermark) n'est qu'un DOM fantôme au-dessus du <zombie-watermark>, cela fonctionne bien de l'intérieur du <zombie-profile>les styles de modèles de. De plus, puisque nous avons utilisé exportparts="copyright" sur le <zombie-watermark>, la partie du droit d'auteur a été poussée vers le haut dans <zombie-profile>'s shadow DOM et ::part(copyright) fonctionne maintenant même dans les styles externes, mais ::part(watermark) ne fonctionnera pas en dehors de <zombie-profile>le modèle.

Nous pouvons également transmettre et renommer des pièces avec cet attribut :

<zombie-watermark exportparts="copyright: cpyear"></zombie-watermark>
/* Within zombie-profile's shadow DOM */ /* happy-face emoji */
::part(cpyear) { ... } /* frowny-face emoji */
::part(copyright) { ... }

Pseudo-classes structurelles (:nth-child, etc.) ne fonctionnent pas non plus sur les parties, mais vous pouvez utiliser des pseudo-classes comme :hover. Animons un peu les meilleurs noms de match et faisons-les trembler pendant qu'ils recherchent de l'amour. D'accord, j'ai entendu cela et je suis d'accord que c'est gênant. Faisons… euh… rendons-les plus, dirons-nous, perceptibles, avec un peu de mouvement.

.high::part(name):hover { animation: highmatch 1s ease-in-out;
}

Les ::slotted pseudo-élément

Les ::slotted Le pseudo-élément CSS est apparu lorsque nous avons couvert les composants Web interactifs. L'idée de base est que ::slotted représente tout contenu dans un slot dans un composant Web, c'est-à-dire l'élément qui a le slot attribut dessus. Mais où ::part perce le shadow DOM pour rendre les éléments d'un composant Web accessibles aux styles extérieurs, ::slotted reste enfermé dans le <style> élément dans le composant <template> et accède à l'élément qui est techniquement en dehors du DOM fantôme.

Dans notre <zombie-profile> composant, par exemple, chaque image de profil est insérée dans l'élément via le slot="profile-image".

<zombie-profile> <img slot="profile-image" src="photo.jpg" /> <!-- rest of the content -->
</zombie-profile>

Cela signifie que nous pouvons accéder à cette image — ainsi qu'à n'importe quelle image dans n'importe quel autre emplacement — comme ceci :

::slotted(img) { width: 100%; max-width: 300px; height: auto; margin: 0 1em 0 0;
}

De même, nous pourrions sélectionner TOUTE fentes avec ::slotted(*) quel que soit l'élément dont il s'agit. Méfiez-vous simplement de cela ::slotted doit sélectionner un élément - les nœuds de texte sont immunisés contre ::slotted styles de zombies. Et les enfants de l'élément dans la fente sont inaccessibles.

Les :defined pseudo-classe

:defined correspond à tous les éléments définis (je sais, surprenant, n'est-ce pas ?), à la fois intégrés et personnalisés. Si votre élément personnalisé se traîne comme un zombie en évitant les questions du père de sa petite amie sur sa situation "de vie", vous ne voudrez peut-être pas que les cadavres du contenu s'affichent pendant que vous attendez qu'ils reviennent à la vie euh... chargez.

Vous pouvez utiliser le :defined pseudo-classe pour masquer un composant Web avant qu'il ne soit disponible - ou "défini" - comme ceci :

:not(:defined) { display: none;
}

Vous pouvez voir comment :defined agit comme une sorte de menthe dans la bouche de nos styles de composants, empêchant tout contenu cassé de s'afficher (ou la mauvaise haleine de fuir) pendant le chargement de la page. Une fois l'élément défini, il apparaîtra automatiquement car il est maintenant, vous savez, défini et non ne sauraient Défini.

J'ai ajouté un setTimeout de cinq secondes au composant Web dans la démonstration suivante. De cette façon, vous pouvez voir que <zombie-profile> les éléments ne sont pas affichés tant qu'ils ne sont pas définis. le <h1> et par <div> qui détient le <zombie-profile> les composants sont toujours là. C'est juste le <zombie-profile> composant Web qui obtient display: none puisqu'ils ne sont pas encore définis.

Les :host pseudo-classe

Supposons que vous souhaitiez apporter des modifications de style à l'élément personnalisé lui-même. Bien que vous puissiez le faire à partir de au contrôle l'élément personnalisé (comme le serrage de ce N95), le résultat ne serait pas encapsulé et des CSS supplémentaires devraient être transférés là où cet élément personnalisé est placé.

Il serait alors très pratique d'avoir une pseudo-classe pouvant atteindre au contrôle le DOM fantôme et sélectionnez la racine fantôme. Cette pseudo-classe CSS est :host.

Dans les exemples précédents de cette série, j'ai défini le <zombie-profile> largeur du CSS de la page principale, comme ceci :

zombie-profile { width: calc(50% - 1em);
}

Avec :host, cependant, je peux définir cette largeur à partir de à l'intérieur le composant Web, comme ceci :

:host { width: calc(50% - 1em);
}

En fait, il y avait une div avec une classe de .profile-wrapper dans mes exemples que je peux maintenant supprimer car je peux utiliser la racine fantôme comme wrapper avec :host. C'est une bonne façon de réduire le balisage.

Vous pouvez faire des sélecteurs descendants à partir du :host, mais seuls les descendants à l'intérieur du DOM fantôme sont accessibles - rien de ce qui a été inséré dans votre composant Web (sans utiliser ::slotted).

Affiche les parties du code HTML pertinentes pour le pseudo-élément :host.

Cela dit, :host n'est pas un zombie à un tour. Il peut également prendre un paramètre, par exemple un sélecteur de classe, et n'appliquera le style que si la classe est présente.

:host(.high) { border: 2px solid blue;
}

Cela vous permet d'apporter des modifications si certaines classes sont ajoutées à l'élément personnalisé.

Vous pouvez également y transmettre des pseudo-classes, comme :host(:last-child) ainsi que le :host(:hover).

Les :host-context pseudo-classe

Parlons maintenant de :host-context. C'est comme notre ami :host(), mais sous stéroïdes. Tandis que :host vous obtient la racine fantôme, il ne vous dira rien sur le contexte dans lequel vit l'élément personnalisé ou ses éléments parent et ancêtre.

:host-context, d'autre part, jette les inhibitions au vent, vous permettant de suivre l'arbre DOM jusqu'à l'arc-en-ciel jusqu'au lutin dans un justaucorps. Notez juste qu'au moment où j'écris ceci, :host-context n'est pas pris en charge dans Firefox ou Safari. Utilisez-le donc pour une amélioration progressive.

Voici comment cela fonctionne. Nous allons diviser notre liste de profils de zombies en deux divs. La première div aura tous les matchs de zombies élevés avec un .bestmatch classer. La deuxième div contiendra tous les matchs d'amour moyens et faibles avec un .worstmatch classe.

<div class="profiles bestmatch"> <zombie-profile class="high"> <!-- etc. --> </zombie-profile> <!-- more profiles -->
</div> <div class="profiles worstmatch"> <zombie-profile class="medium"> <!-- etc. --> </zombie-profile> <zombie-profile class="low"> <!-- etc. --> </zombie-profile> <!-- more profiles -->
</div>

Supposons que nous voulions appliquer différentes couleurs d'arrière-plan au .bestmatch ainsi que le .worstmatch Des classes. Nous ne sommes pas en mesure de le faire simplement :host:

:host(.bestmatch) { background-color: #eef;
}
:host(.worstmatch) { background-color: #ddd;
}

C'est parce que nos meilleures et pires classes de correspondance ne sont pas sur nos éléments personnalisés. Ce que nous voulons, c'est pouvoir sélectionner les éléments parents des profils à partir du DOM fantôme. :host-context dépasse l'élément personnalisé pour rencontre les, euh, correspondent aux classes que nous voulons styliser.

:host-context(.bestmatch) { background-color: #eef;
}
:host-context(.worstmatch) { background-color: #ddd;
}

Eh bien, merci d'avoir passé du temps malgré toute la mauvaise haleine. (Je sais que vous ne pouviez pas dire, mais ci-dessus quand je parlais de Un flux efficace peut augmenter souffle, je parlais secrètement de my souffle.)

Comment utiliseriez-vous ::part, ::slotted, :defined, :hostet une :host-context dans votre composant Web ? Faites-moi savoir dans les commentaires. (Ou si vous avez des remèdes contre l'halitose chronique, ma femme serait très intéressé à en savoir plus.)

spot_img

Dernières informations

spot_img