Aislamiento de CSS de Blazor de ASP.NET Core

Nota

Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión .NET 8 de este artículo.

Importante

Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.

Para la versión actual, consulte la versión .NET 8 de este artículo.

De Dave Brock

En este artículo se explica cómo el aislamiento de CSS aplica ámbito de CSS a componentes Razor, lo que puede simplificar CSS y evitar conflictos con otros componentes o bibliotecas.

Aísle los estilos CSS a páginas, vistas y componentes individuales para reducir o evitar lo siguiente:

  • Dependencias de estilos globales que pueden ser difíciles de mantener.
  • Conflictos de estilo en el contenido anidado.

Habilitación del aislamiento de CSS

Para definir estilos específicos de un componente, cree un archivo .razor.css cuyo nombre coincida con el del archivo .razor del componente en la misma carpeta. El archivo .razor.css es un archivo CSS con ámbito.

En un componente Example de un archivo Example.razor, cree un archivo junto al componente denominado Example.razor.css. El archivo Example.razor.css debe residir en la misma carpeta que el componente Example (Example.razor). El nombre base "Example" del archivo no distingue mayúsculas de minúsculas.

Example.razor:

@page "/example"

<h1>Scoped CSS Example</h1>

Example.razor.css:

h1 { 
    color: brown;
    font-family: Tahoma, Geneva, Verdana, sans-serif;
}

Los estilos definidos en Example.razor.css solo se aplican a la salida representada del componente Example. El aislamiento de CSS se aplica a los elementos HTML en el archivo Razor coincidente. Cualquier declaración CSS h1 definida en otra ubicación de la aplicación no entra en conflicto con los estilos del componente Example.

Nota

Para garantizar el aislamiento de estilo en el momento de la unión, no se admite la importación de CSS en bloques de código Razor.

Unión del aislamiento de CSS

El aislamiento de CSS se produce en tiempo de compilación. Durante este proceso, Blazor reescribe los selectores de CSS para que coincidan con el marcado representado por el componente. Estos estilos de CSS reescritos se unen y se generan como un recurso estático. Se hace referencia a la hoja de estilos dentro de la etiqueta <head> (ubicación del contenido de <head>). El siguiente elemento <link> se agrega de forma predeterminada a una aplicación creada a partir de las plantillas de proyecto Blazor, donde el marcador de posición {ASSEMBLY NAME} es el nombre del ensamblado del proyecto:

<link href="{ASSEMBLY NAME}.styles.css" rel="stylesheet">

El ejemplo siguiente es de una aplicación Blazor WebAssemblyClient hospedada. El nombre del ensamblado de la aplicación es BlazorSample.Client, y la plantilla de proyecto Blazor WebAssembly agrega <link> cuando el proyecto se crea con la opción Hospedado (opción -ho|--hosted usando la CLI de .NET o la casilla ASP.NET Core hospedado con Visual Studio):

<link href="BlazorSample.Client.styles.css" rel="stylesheet">

En el archivo unido, cada componente está asociado a un identificador de ámbito. Para cada componente con estilo, se anexa un atributo HTML con el formato b-{STRING}, donde el marcador de posición {STRING} es una cadena de diez caracteres generada por el marco. El identificador es único para cada aplicación. En el componente Counter representado, Blazor anexa un identificador de ámbito al elemento h1:

<h1 b-3xxtam6d07>

El archivo {ASSEMBLY NAME}.styles.css usa el identificador de ámbito para agrupar una declaración de estilo con su componente. En el ejemplo siguiente se proporciona el estilo del elemento <h1> anterior:

/* /Components/Pages/Counter.razor.rz.scp.css */
h1[b-3xxtam6d07] {
    color: brown;
}

En tiempo de compilación, se crea un conjunto del proyecto con la convención obj/{CONFIGURATION}/{TARGET FRAMEWORK}/scopedcss/projectbundle/{ASSEMBLY NAME}.bundle.scp.css, donde los marcadores de posición son:

  • {CONFIGURATION}: la configuración de compilación de la aplicación (por ejemplo, Debug, Release).
  • {TARGET FRAMEWORK}: la plataforma de destino (por ejemplo, net6.0).
  • {ASSEMBLY NAME}: el nombre del ensamblado de la aplicación (por ejemplo, BlazorSample).

Compatibilidad de componente secundario

De forma predeterminada, el aislamiento de CSS solo se aplica al componente que se asocia con el formato {COMPONENT NAME}.razor.css, donde el marcador de posición {COMPONENT NAME} suele ser el nombre del componente. Para aplicar cambios a un componente secundario, use el ::deepseudoelemento con los elementos descendientes del archivo .razor.css del componente primario. El seudoelemento ::deep selecciona los elementos que son descendientes del identificador de ámbito generado de un elemento.

En el ejemplo siguiente se muestra un componente primario denominado Parent con un componente secundario denominado Child.

Parent.razor:

@page "/parent"

<div>
    <h1>Parent component</h1>

    <Child />
</div>

Child.razor:

<h1>Child Component</h1>

Actualice la declaración h1 de Parent.razor.css con el seudoelemento ::deep para indicar que la declaración de estilo de h1 debe aplicarse al componente primario y a sus elementos secundarios.

Parent.razor.css:

::deep h1 { 
    color: red;
}

El estilo de h1 ahora se aplica a los componentes Parent y Child sin necesidad de crear un archivo CSS con ámbito independiente para el componente secundario.

El seudoelemento ::deep solo funciona con elementos descendientes. El marcado siguiente aplica los estilos de h1 a los componentes según lo esperado. El identificador de ámbito del componente primario se aplica al elemento div, por lo que se sabe que el explorador hereda los estilos del componente primario.

Parent.razor:

<div>
    <h1>Parent</h1>

    <Child />
</div>

Sin embargo, si se excluye el elemento div, se quita la relación descendiente. En el ejemplo siguiente, el estilo no se aplica al componente secundario.

Parent.razor:

<h1>Parent</h1>

<Child />

El seudoelemento ::deep afecta al lugar donde se aplica el atributo de ámbito a la regla. Al definir una regla CSS en un archivo CSS con ámbito, el ámbito se aplica al elemento situado más a la derecha de forma predeterminada. Por ejemplo: div > a se transforma en div > a[b-{STRING}], donde el marcador de posición {STRING} es una cadena de diez caracteres generada por el marco (por ejemplo, b-3xxtam6d07). Si en su lugar desea que la regla se aplique a un selector diferente, el seudoelemento ::deep le permite hacerlo. Por ejemplo, div ::deep > a se transforma en div[b-{STRING}] > a (por ejemplo, div[b-3xxtam6d07] > a).

La capacidad de asociar el seudoelemento ::deep a cualquier elemento HTML permite crear estilos CSS con ámbito que afecten a los elementos representados por otros componentes cuando pueda determinar la estructura de las etiquetas HTML representadas. En el caso de un componente que represente una etiqueta de hipervínculo (<a>) dentro de otro componente, asegúrese de que el componente esté encapsulado en un elemento div (o cualquier otro elemento) y use la regla ::deep > a para crear un estilo que solo se aplique a ese componente cuando se represente el componente primario.

Importante

CSS con ámbito solo se aplica a elementos HTML y no a componentes ni aplicaciones auxiliares de etiquetas Razor, incluidos los elementos con una aplicación auxiliar de etiquetas aplicada, como <input asp-for="..." />.

Compatibilidad del preprocesador de CSS

Los preprocesadores de CSS son útiles para mejorar el desarrollo de CSS mediante el uso de características como variables, anidamiento, módulos, mixins y herencia. Aunque el aislamiento de CSS no admite de forma nativa preprocesadores de CSS como Sass o Less, la integración de preprocesadores de CSS se realiza sin problemas siempre que se produzca la compilación del preprocesador antes de que Blazor reescriba los selectores de CSS durante el proceso de compilación. Con Visual Studio, por ejemplo, configure la compilación del preprocesador existente como una tarea Antes de la compilación en el Explorador del Ejecutor de tareas de Visual Studio.

Muchos paquetes NuGet de terceros, como AspNetCore.SassCompiler, pueden compilar archivos SASS/SCSS al principio del proceso de compilación antes de que se produzca el aislamiento de CSS.

Configuración del aislamiento de CSS

El aislamiento de CSS está diseñado para poder trabajar de inmediato, pero proporciona configuración para algunos escenarios avanzados, por ejemplo cuando hay dependencias en herramientas o flujos de trabajo existentes.

Personalización del formato del identificador de ámbito

De forma predeterminada, los identificadores de ámbito usan el formato b-{STRING}, donde el marcador de posición {STRING} es una cadena de diez caracteres generada por el marco. Para personalizar el formato de un identificador de ámbito, actualice el archivo del proyecto a un patrón deseado:

<ItemGroup>
  <None Update="Components/Pages/Example.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

En el ejemplo anterior, el CSS generado para Example.razor.css cambia su identificador de ámbito de b-{STRING} a custom-scope-identifier.

Use identificadores de ámbito para lograr la herencia con archivos CSS de ámbito. En el siguiente ejemplo del archivo del proyecto, un archivo BaseComponent.razor.css contiene estilos comunes en todos los componentes. Un archivo DerivedComponent.razor.css hereda estos estilos.

<ItemGroup>
  <None Update="Components/Pages/BaseComponent.razor.css" CssScope="custom-scope-identifier" />
  <None Update="Components/Pages/DerivedComponent.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Use el operador comodín (*) para compartir los identificadores de ámbito en varios archivos:

<ItemGroup>
  <None Update="Components/Pages/*.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

De forma predeterminada, los identificadores de ámbito usan el formato b-{STRING}, donde el marcador de posición {STRING} es una cadena de diez caracteres generada por el marco. Para personalizar el formato de un identificador de ámbito, actualice el archivo del proyecto a un patrón deseado:

<ItemGroup>
  <None Update="Pages/Example.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

En el ejemplo anterior, el CSS generado para Example.razor.css cambia su identificador de ámbito de b-{STRING} a custom-scope-identifier.

Use identificadores de ámbito para lograr la herencia con archivos CSS de ámbito. En el siguiente ejemplo del archivo del proyecto, un archivo BaseComponent.razor.css contiene estilos comunes en todos los componentes. Un archivo DerivedComponent.razor.css hereda estos estilos.

<ItemGroup>
  <None Update="Pages/BaseComponent.razor.css" CssScope="custom-scope-identifier" />
  <None Update="Pages/DerivedComponent.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Use el operador comodín (*) para compartir los identificadores de ámbito en varios archivos:

<ItemGroup>
  <None Update="Pages/*.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Cambio de la ruta de acceso base de recursos web estáticos

El archivo scoped.styles.css se genera en la raíz de la aplicación. En el archivo del proyecto, use la <StaticWebAssetBasePath>propiedad para cambiar la ruta de acceso predeterminada. En el ejemplo siguiente se coloca el archivo scoped.styles.css, y el resto de los recursos de la aplicación, en la ruta de acceso _content:

<PropertyGroup>
  <StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>

Deshabilitación de la unión automática

Para no usar el modo en que Blazor publica y carga archivos con ámbito en tiempo de ejecución, use la propiedad DisableScopedCssBundling. Al usar esta propiedad, otras herramientas o procesos son responsables de tomar los archivos CSS aislados del directorio obj y de publicarlos y cargarlos en tiempo de ejecución:

<PropertyGroup>
  <DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>

Deshabilitación del aislamiento de CSS

Deshabilite el aislamiento de CSS para un proyecto estableciendo la propiedad <ScopedCssEnabled> en false en el archivo de proyecto de la aplicación:

<ScopedCssEnabled>false</ScopedCssEnabled>

Razor Compatibilidad con la biblioteca de clases (RCL)

Los estilos aislados para los componentes de un paquete NuGet o la biblioteca de clases Razor (RCL) se agrupan automáticamente:

  • La aplicación usa importaciones CSS para hacer referencia a los estilos agrupados de la RCL. Para una biblioteca de clases denominada ClassLib y una aplicación Blazor con una hoja de estilos BlazorSample.styles.css, la hoja de estilos de la RCL se importa automáticamente en la parte superior de la hoja de estilos de la aplicación:

    @import '_content/ClassLib/ClassLib.bundle.scp.css';
    
  • Los estilos agrupados de la RCL no se publican como recursos web estáticos de la aplicación que consume la biblioteca.

Para obtener más información sobre RCL, vea los siguientes artículos: