Isolamento de CSS do ASP.NET Core Blazor

Observação

Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Por Dave Brock

Este artigo explica como o isolamento de CSS define o CSS para componentes Razor, o que pode simplificar o CSS e evitar colisões com outros componentes ou bibliotecas.

Isole estilos CSS em páginas, exibições e componentes individuais para reduzir ou evitar:

  • Dependências de estilos globais que podem ser desafiadoras de manter.
  • Conflitos de estilo em conteúdo aninhado.

Habilitar o isolamento de CSS

Para definir estilos específicos do componente, crie um arquivo .razor.css que corresponda ao nome do arquivo .razor para o componente na mesma pasta. O arquivo .razor.css é umarquivo CSS com escopo.

Para um componente Example em um arquivo Example.razor, crie um arquivo junto com o componente chamado Example.razor.css. O arquivo Example.razor.css deve estar na mesma pasta que o componente Example (Example.razor). O nome base "Example" do arquivo não diferencia maiú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;
}

Os estilos definidos em Example.razor.css são aplicados apenas à saída renderizada do componente Example. O isolamento de CSS é aplicado a elementos HTML no arquivo Razor correspondente. Quaisquer declarações CSS h1 definidas em outro lugar no aplicativo não entram em conflito com os estilos do componente Example.

Observação

Para garantir o isolamento do estilo quando ocorrer o agrupamento, não há suporte para a importação de CSS em blocos de código Razor.

Agrupamento de isolamento de CSS

O isolamento de CSS ocorre no momento do build. Blazor reescreve os seletores de CSS para fazer a correspondência da marcação renderizada pelo componente. Os estilos CSS reescritos são empacotados e produzidos como um ativo estático. A folha de estilos é referenciada dentro da <head> marca (local do <head> conteúdo). Por padrão, o seguinte elemento <link> é adicionado a um aplicativo criado a partir dos modelos de projeto Blazor, em que o espaço reservado {ASSEMBLY NAME} é o nome do assembly do projeto:

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

O exemplo a seguir é de um aplicativo Blazor WebAssemblyClienthospedado. O nome do assembly do aplicativo é BlazorSample.Client e <link> é adicionado pelo modelo de projeto Blazor WebAssembly quando o projeto é criado com a opção Hospedado (opção -ho|--hosted usando a CLI do .NET ou a caixa de seleção ASP.NET Core Hospedada usando o Visual Studio):

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

Dentro do arquivo agrupado, cada componente está associado a um identificador de escopo. Para cada componente com estilo, acrescenta-se um atributo HTML com o formato b-{STRING}, em que o espaço reservado {STRING} é uma cadeia de dez caracteres gerada pela estrutura. O identificador é exclusivo para cada aplicativo. No componente Counter renderizado, Blazor acrescenta um identificador de escopo ao h1 elemento :

<h1 b-3xxtam6d07>

O arquivo {ASSEMBLY NAME}.styles.css usa o identificador de escopo para agrupar uma declaração de estilo ao seu componente. O seguinte exemplo mostra o estilo do elemento <h1> anterior:

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

No momento da compilação, é criado um pacote de projeto com a convenção obj/{CONFIGURATION}/{TARGET FRAMEWORK}/scopedcss/projectbundle/{ASSEMBLY NAME}.bundle.scp.css, em que os espaços reservados são:

  • {CONFIGURATION}: a configuração de compilação do aplicativo (por exemplo, Debug, Release).
  • {TARGET FRAMEWORK}: a estrutura de destino (por exemplo, net6.0).
  • {ASSEMBLY NAME}: o nome do assembly do aplicativo (por exemplo, BlazorSample).

Suporte a componente filho

Por padrão, o isolamento de CSS só se aplica ao componente associado ao formato {COMPONENT NAME}.razor.css, em que o espaço reservado {COMPONENT NAME} geralmente é o nome do componente. Para aplicar alterações a um componente filho, use o ::deeppseudoelemento para quaisquer elementos descendentes no arquivo .razor.css do componente pai. O pseudo-elemento ::deep seleciona elementos que são descendentes do identificador de escopo gerado por um elemento.

O exemplo a seguir mostra um componente pai chamado Parent com um componente filho chamado Child.

Parent.razor:

@page "/parent"

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

    <Child />
</div>

Child.razor:

<h1>Child Component</h1>

Atualize a declaraçãoh1 em Parent.razor.css com o pseudo-elemento ::deep para simbolizar que a declaração de estilo h1 deve ser aplicada ao componente pai e filhos.

Parent.razor.css:

::deep h1 { 
    color: red;
}

O estilo h1 agora se aplica aos componentes Parent e Child sem a necessidade de criar um arquivo CSS com escopo separado para o componente filho.

O pseudoelemento ::deep funciona somente com elementos descendentes. A marcação a seguir aplica os estilos h1 aos componentes conforme o esperado. O identificador de escopo do componente pai é aplicado ao elemento div, portanto, o navegador sabe herdar estilos do componente pai.

Parent.razor:

<div>
    <h1>Parent</h1>

    <Child />
</div>

No entanto, excluir o elemento div remove a relação descendente. No exemplo a seguir, o estilo não é aplicado ao componente filho.

Parent.razor:

<h1>Parent</h1>

<Child />

O pseudoelemento ::deep afeta onde o atributo de escopo é aplicado à regra. Quando você define uma regra CSS em um arquivo CSS com escopo, o escopo é aplicado ao elemento mais à direita por padrão. Por exemplo: div > a é transformado em div > a[b-{STRING}], em que o espaço reservado {STRING} é uma cadeia de dez caracteres gerada pela estrutura (por exemplo, b-3xxtam6d07). Para que a regra seja aplicada a um seletor diferente, o pseudoelemento ::deep permite essa aplicação. Por exemplo, div ::deep > a é transformado em div[b-{STRING}] > a (por exemplo, div[b-3xxtam6d07] > a).

Poder anexar o pseudo-elemento ::deep a qualquer elemento HTML permite que você crie estilos CSS com escopo que alteram os elementos renderizados por outros componentes quando você pode determinar a estrutura das marcas HTML renderizadas. Para um componente que renderiza uma marca de hiperlink (<a>) dentro de outro componente, verifique se o componente está encapsulado em um div (ou qualquer outro elemento) e use a regra ::deep > a para criar um estilo que somente é aplicado a esse componente quando o componente pai é renderizado.

Importante

O CSS com escopo somente se aplica a elementos HTML e não a componentes Razor ou Auxiliares de Marca, incluindo elementos com um Auxiliar de Marca aplicado, como <input asp-for="..." />.

Suporte para pré-processador de CSS

Pré-processadores de CSS são úteis para aprimorar o desenvolvimento de CSS utilizando recursos como variáveis, aninhamento, módulos, mixins e herança. Embora o isolamento de CSS não dê suporte nativo a pré-processadores CSS, como Sass ou Less, a integração de pré-processadores de CSS é contínua desde que a compilação do pré-processador ocorra antes que Blazor reescreva os seletores de CSS durante o processo de compilação. Usando o Visual Studio, por exemplo, configure a compilação de pré-processador existente como uma tarefa Before Build no Gerenciador do Executor de Tarefas do Visual Studio.

Muitos pacotes NuGet de terceiros, como AspNetCore.SassCompiler, podem compilar arquivos SASS/SCSS no início do processo de compilação antes que ocorra o isolamento de CSS e não será necessária nenhuma configuração adicional.

Configuração do isolamento de CSS

O isolamento do CSS foi feito para funcionar “out-of-the-box”, mas tem configuração para alguns cenários avançados, por exemplo, quando há dependências em ferramentas ou fluxos de trabalho existentes.

Personalizar o formato de identificador de escopo

Por padrão, os identificadores de escopo usam o formato b-{STRING}, em que o espaço reservado {STRING} é uma cadeia de caracteres de dez caracteres gerada pela estrutura. Para personalizar o formato do identificador de escopo, atualize o arquivo de projeto para um padrão desejado:

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

No exemplo anterior, o CSS gerado para Example.razor.css altera o identificador de escopo de b-{STRING} para custom-scope-identifier.

Use identificadores de escopo para obter a herança com arquivos CSS com escopo. No exemplo de arquivo de projeto a seguir, um arquivo BaseComponent.razor.css contém estilos comuns entre componentes. Um arquivo DerivedComponent.razor.css herda esses 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 o operador curinga (*) para compartilhar identificadores de escopo em vários arquivos:

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

Por padrão, os identificadores de escopo usam o formato b-{STRING}, em que o espaço reservado {STRING} é uma cadeia de caracteres de dez caracteres gerada pela estrutura. Para personalizar o formato do identificador de escopo, atualize o arquivo de projeto para um padrão desejado:

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

No exemplo anterior, o CSS gerado para Example.razor.css altera o identificador de escopo de b-{STRING} para custom-scope-identifier.

Use identificadores de escopo para obter a herança com arquivos CSS com escopo. No exemplo de arquivo de projeto a seguir, um arquivo BaseComponent.razor.css contém estilos comuns entre componentes. Um arquivo DerivedComponent.razor.css herda esses estilos.

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

Use o operador curinga (*) para compartilhar identificadores de escopo em vários arquivos:

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

Alterar o caminho base para ativos da Web estáticos

O arquivo scoped.styles.css é gerado na raiz do aplicativo. No arquivo de projeto, use a <StaticWebAssetBasePath>propriedade para alterar o caminho padrão. O seguinte exemplo coloca o arquivo scoped.styles.css e o restante dos ativos do aplicativo no caminho _content:

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

Desabilitar o agrupamento automático

Use a propriedade DisableScopedCssBundling para recusar como Blazor publica e carrega os arquivos com escopo no runtime. Usando essa propriedade, outras ferramentas ou processos são responsáveis por tirar os arquivos CSS isolados do diretório obj e publicá-los e carregá-los em runtime:

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

Desabilitar o isolamento de CSS

Desabilite o isolamento de CSS para um projeto definindo a propriedade <ScopedCssEnabled> como false no arquivo de projeto do aplicativo:

<ScopedCssEnabled>false</ScopedCssEnabled>

Suporte à RCL (biblioteca de classes) Razor

Estilos isolados para componentes em um pacote NuGet ou biblioteca de classesRazor (RCL) são agrupados automaticamente:

  • O aplicativo usa importações CSS para fazer referência aos estilos agrupados da RCL. Para uma biblioteca de classes chamada ClassLib e um aplicativo Blazor com uma folha de estilos BlazorSample.styles.css, a folha de estilos da RCL é importada na parte superior da folha de estilos do aplicativo:

    @import '_content/ClassLib/ClassLib.bundle.scp.css';
    
  • Os estilos agrupados da RCL não serão publicado como um ativo da Web estático do aplicativo que consome os estilos.

Para obter mais informações sobre RCLs, consulte os seguintes artigos: