Blazor CSS Isolation
Vue d’ensemble
Le CSS Isolation (ou CSS isolé) est une fonctionnalité de Blazor qui permet d’associer des styles CSS spécifiquement à un composant, évitant ainsi les conflits de styles avec d’autres composants ou bibliothèques. Cette approche améliore la maintenabilité et la modularité des applications Blazor.
Comment activer le CSS Isolation?
Pour définir des styles spécifiques à un composant, il suffit de créer un fichier .razor.css
qui porte le même nom que le fichier .razor
du composant, dans le même dossier.
Par exemple, pour un composant MonComposant
dans un fichier MonComposant.razor
, créez un fichier MonComposant.razor.css
à côté :
MonComposant.razor :
<div class="container">
<h1>Mon Titre</h1>
<p class="description">Description de mon composant</p>
</div>
MonComposant.razor.css :
.container {
background-color: #f0f0f0;
padding: 20px;
border-radius: 8px;
}
h1 {
color: #333;
font-size: 2rem;
margin-bottom: 1rem;
}
.description {
color: #666;
font-style: italic;
}
Comment cela fonctionne en interne
Lors de la compilation, Blazor réécrit automatiquement les sélecteurs CSS pour qu’ils correspondent au balisage rendu par le composant. Le framework génère un identifiant de portée unique au format b-{STRING}
(où {STRING}
est une chaîne de 10 caractères générée automatiquement) et l’ajoute comme attribut HTML aux éléments du composant.
HTML généré :
<div class="container" b-3xxtam6d07>
<h1 b-3xxtam6d07>Mon Titre</h1>
<p class="description" b-3xxtam6d07>...</p>
</div>
CSS généré :
.container[b-3xxtam6d07] {
background-color: #f0f0f0;
padding: 20px;
border-radius: 8px;
}
h1[b-3xxtam6d07] {
color: #333;
font-size: 2rem;
margin-bottom: 1rem;
}
.description[b-3xxtam6d07] {
color: #666;
font-style: italic;
}
Avantages du CSS Isolation
✅ Encapsulation des styles
- Les styles sont automatiquement limités au composant, évitant les conflits avec d’autres parties de l’application
- Pas de risque de “fuites” de styles vers d’autres composants
✅ Maintenabilité améliorée
- Organisation claire : chaque composant a ses propres styles
- Facilite la refactorisation et la maintenance du code
- Réduction des dépendances aux styles globaux
✅ Performance optimisée
- Bundling automatique des styles au moment de la compilation
- Génération d’un seul fichier CSS pour toute l’application
- Pas de surcharge à l’exécution
✅ Simplicité d’utilisation
- Aucune configuration particulière nécessaire
- Syntaxe CSS standard
- Compatible avec les préprocesseurs CSS (Sass, Less, etc.)
Inconvénients et limitations
❌ Complexité avec les composants enfants
- Les styles ne s’appliquent pas automatiquement aux composants enfants
- Nécessite l’utilisation du pseudo-élément
::deep
pour cibler les descendants
❌ Limitation sur les composants Razor
- ⚠️ L’identifiant généré n’est pas appliqué aux composants Blazor que vous utilisez, seulement aux éléments HTML
❌ Structure HTML contrainte
- Parfois nécessaire d’ajouter des éléments HTML supplémentaires pour utiliser
::deep
correctement - Peut impacter la sémantique HTML
❌ Debugging plus complexe
- Les noms de classes générés automatiquement peuvent compliquer le débogage
- Nécessite une compréhension du mécanisme de génération d’identifiants
Styliser les composants enfants avec ::deep
L’un des défis majeurs du CSS Isolation est le styling des composants enfants. Par défaut, les styles isolés ne s’appliquent qu’au composant parent.
Le problème
Parent.razor :
@page "/parent"
<h1>Composant Parent</h1>
<MyChildComponent />
Parent.razor.css :
/* This style will NOT apply to the child component. */
h1 {
color: blue;
}
MyChildComponent.razor :
<h1>MyChildComponent</h1>
La solution avec ::deep
Pour appliquer des styles aux composants enfants, utilisez le pseudo-élément ::deep
:
Parent.razor.css :
/* This style will apply to the h1 of the parent AND the children. */
::deep h1 {
color: blue;
}
Point crucial : Nécessité d’un élément HTML conteneur
Problème : L’identifiant généré n’est pas appliqué aux composants Razor eux-mêmes, mais seulement aux éléments HTML qu’ils contiennent. Pour utiliser ::deep
correctement, il est souvent nécessaire d’ajouter un élément HTML conteneur.
Exemple incorrect (ne fonctionnera pas) :
<!-- Parent.razor -->
<h1>Parent</h1>
<MyChildComponent />
Exemple correct (fonctionnera) :
<!-- Parent.razor -->
<div>
<h1>Parent</h1>
<MyChildComponent />
</div>
Parent.razor.css :
/* Maintenant ::deep peut fonctionner correctement */
::deep h1 {
color: red;
}
Le div
conteneur reçoit l’identifiant de portée, permettant à ::deep
de fonctionner sur les éléments descendants.
Exemples pratiques
Composant Card avec isolation CSS
Card.razor :
<div class="card">
<div class="card-header">
<h3>@Title</h3>
</div>
<div class="card-content">
@ChildContent
</div>
</div>
@code {
[Parameter] public string Title { get; set; } = "";
[Parameter] public RenderFragment? ChildContent { get; set; }
}
Card.razor.css :
.card {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-bottom: 1rem;
}
.card-header {
background: #f8f9fa;
padding: 1rem;
border-bottom: 1px solid #ddd;
border-radius: 8px 8px 0 0;
}
.card-header h3 {
margin: 0;
color: #333;
}
.card-content {
padding: 1rem;
}
Page utilisant le composant Card
MaPage.razor :
@page "/ma-page"
<div class="page-container">
<Card Title="Première carte">
<p>Contenu de la première carte</p>
</Card>
<Card Title="Seconde carte">
<p>Contenu de la seconde carte</p>
</Card>
</div>
MaPage.razor.css :
.page-container {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
}
/* Styliser les cartes depuis le parent */
::deep .card {
transition: transform 0.2s ease;
}
::deep .card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
Configuration avancée
Personnaliser l’identifiant de portée
Vous pouvez personnaliser le format de l’identifiant de portée dans le fichier projet :
<ItemGroup>
<None Update="Components/MonComposant.razor.css" CssScope="mon-identifiant-custom" />
</ItemGroup>
Désactiver le CSS Isolation
Pour désactiver complètement le CSS Isolation dans un projet :
<PropertyGroup>
<ScopedCssEnabled>false</ScopedCssEnabled>
</PropertyGroup>
Bonnes pratiques
- Organisez vos styles : Gardez les fichiers
.razor.css
à côté de leurs composants respectifs - Utilisez des noms de classes explicites : Même si les styles sont isolés, des noms clairs améliorent la lisibilité
- Minimisez l’usage de ::deep : Préférez la composition de composants plutôt que la modification de styles enfants
- Ajoutez des conteneurs HTML : Quand vous devez utiliser
::deep
, assurez-vous d’avoir un élément HTML conteneur approprié - Testez la compatibilité : Vérifiez que vos styles fonctionnent correctement avec les différents navigateurs
Conclusion
Le CSS Isolation de Blazor est un outil puissant pour maintenir des styles organisés et éviter les conflits. Bien qu’il présente quelques limitations, notamment avec les composants enfants et la nécessité d’ajouter parfois des éléments HTML conteneurs, ses avantages en termes de maintenabilité et d’encapsulation en font un choix judicieux pour la plupart des applications Blazor.
La compréhension du fonctionnement interne, notamment le fait que l’identifiant généré ne s’applique qu’aux éléments HTML et non aux composants Razor eux-mêmes, est essentielle pour utiliser efficacement cette fonctionnalité.