ASP.NET Core Blazor CSS 격리

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

작성자: Dave Brock

이 문서에서는 CSS 격리를 통해 CSS의 범위를 Razor 구성 요소로 지정하여 CSS를 간소화하고 다른 구성 요소나 라이브러리와의 충돌을 방지할 수 있는 방법을 설명합니다.

CSS 스타일을 개별 페이지, 뷰 및 구성 요소로 격리하여 다음을 줄이거나 방지합니다.

  • 유지 관리하기 어려울 수 있는 전역 스타일에 대한 종속성.
  • 중첩된 콘텐츠의 스타일 충돌.

CSS 격리 사용

구성 요소별 스타일을 정의하려면 구성 요소에 대한 .razor 파일의 이름과 일치하는 .razor.css 파일을 같은 폴더에 만듭니다. 파일은 .razor.css 범위가 지정된 CSS 파일입니다.

Example.razor 파일의 Example 구성 요소에 대해서는 Example.razor.css라는 구성 요소와 함께 파일을 만듭니다. Example.razor.css 파일은 Example 구성 요소(Example.razor)와 같은 폴더에 있어야 합니다. 파일의 "Example" 기본 이름은 대/소문자를 구분하지않습니다.

Example.razor:

@page "/example"

<h1>Scoped CSS Example</h1>

Example.razor.css:

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

Example.razor.css에 정의된 스타일은 Example 구성 요소의 렌더링된 출력에만 적용됩니다. CSS 격리는 일치하는 Razor 파일의 HTML 요소에 적용됩니다. 앱의 다른 위치에 정의된 모든 h1 CSS 선언이 Example 구성 요소의 스타일과 충돌하지 않습니다.

참고 항목

묶음이 발생할 때 스타일 격리를 보장하기 위해 Razor 블록에서 CSS 가져오기는 지원되지 않습니다.

CSS 격리 묶음

CSS 격리는 빌드 시간에 발생합니다. Blazor는 구성 요소에 의해 렌더링된 태그와 일치하도록 CSS 선택기를 다시 작성합니다. 다시 작성된 CSS 스타일은 번들로 묶여 정적 자산으로 생성됩니다. 스타일시트는 <head> 태그(<head> 콘텐츠의 위치) 내에서 참조됩니다. 다음 <link> 요소는 기본적으로 Blazor 프로젝트 템플릿에서 만든 앱에 추가됩니다. 여기서 자리 표시자 {ASSEMBLY NAME}은 프로젝트의 어셈블리 이름입니다.

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

다음 예제는 호스트 Blazor WebAssemblyClient 된 앱에서 가져옵니다. 앱의 어셈블리 이름은 BlazorSample.Client이고 호스트 옵션(.NET CLI를 사용하는 -ho|--hosted 옵션 또는 Visual Studio를 사용하는 ASP.NET Core 호스트 확인란)으로 프로젝트를 만들 때 Blazor WebAssembly 프로젝트 템플릿에 의해 <link>가 추가됩니다.

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

묶은 파일 내에서 각 구성 요소는 범위 식별자와 연결됩니다. 스타일이 지정된 각 구성 요소에 대해 HTML 특성에 b-{STRING} 형식이 추가됩니다. 여기서 {STRING} 자리 표시자는 프레임워크에서 생성된 10자 문자열입니다. 식별자는 각 앱에 대해 고유합니다. 렌더링된 Counter 구성 요소에서 Blazor는 h1 요소에 범위 식별자를 추가합니다.

<h1 b-3xxtam6d07>

{ASSEMBLY NAME}.styles.css 파일은 범위 식별자를 사용하여 해당 구성 요소로 스타일 선언을 그룹화합니다. 다음 예제에서는 위의 <h1> 요소에 대한 스타일을 제공합니다.

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

빌드 타임에는 규칙 obj/{CONFIGURATION}/{TARGET FRAMEWORK}/scopedcss/projectbundle/{ASSEMBLY NAME}.bundle.scp.css를 사용하여 프로젝트 번들이 생성됩니다. 여기서 자리 표시자는 다음과 같습니다.

  • {CONFIGURATION}: 앱의 빌드 구성(예: Debug, Release)
  • {TARGET FRAMEWORK}: 대상 프레임워크(예: net6.0)
  • {ASSEMBLY NAME}: 앱의 어셈블리 이름(예: BlazorSample)

자식 구성 요소 지원

기본적으로 CSS 격리는 {COMPONENT NAME}.razor.css 형식으로 연결하는 구성 요소에만 적용됩니다. 여기서 {COMPONENT NAME} 자리 표시자는 일반적으로 구성 요소 이름입니다. 자식 구성 요소에 변경 내용을 적용하려면 부모 구성 요소의 .razor.css 파일에 있는 모든 하위 항목 요소에 ::deep의사 요소를 사용합니다. ::deep 의사 요소는 요소의 생성된 범위 식별자의 하위 항목인 요소를 선택합니다.

다음 예제에서는 Child라는 자식 구성 요소가 있는 Parent라는 부모 구성 요소를 보여 줍니다.

Parent.razor:

@page "/parent"

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

    <Child />
</div>

Child.razor:

<h1>Child Component</h1>

::deep 의사 요소로 Parent.razor.cssh1 선언을 업데이트하여 h1 스타일 선언이 부모 구성 요소 및 해당 자식에 적용되어야 함을 나타냅니다.

Parent.razor.css:

::deep h1 { 
    color: red;
}

이제 자식 구성 요소에 대해 별도의 범위가 지정된 CSS 파일을 만들지 않아도 h1 스타일이 ParentChild 구성 요소에 적용됩니다.

::deep 의사 요소는 하위 항목 요소에서만 작동합니다. 다음 태그는 예상대로 h1 스타일을 구성 요소에 적용합니다. 부모 구성 요소의 범위 식별자가 div 요소에 적용되므로 브라우저는 부모 구성 요소에서 스타일이 상속됨을 알고 있습니다.

Parent.razor:

<div>
    <h1>Parent</h1>

    <Child />
</div>

그러나 div를 제외하면 하위 항목 관계가 제거됩니다. 다음 예제에서 스타일은 자식 구성 요소에 적용되지 않습니다.

Parent.razor:

<h1>Parent</h1>

<Child />

::deep 의사 요소는 범위 특성이 규칙에 적용되는 위치에 영향을 미칩니다. 범위가 지정된 CSS 파일에서 CSS 규칙을 정의하면 기본적으로 범위가 가장 적합한 요소에 적용됩니다. 예를 들어 div > adiv > a[b-{STRING}]로 변환됩니다. 여기에서 {STRING} 자리 표시자는 프레임워크에 의해 생성된 10자 문자열입니다(예: b-3xxtam6d07). 대신 규칙이 다른 선택기에 적용되도록 하려면 ::deep 의사 요소를 사용하면 됩니다. 예를 들어 div ::deep > adiv[b-{STRING}] > a로 변환됩니다(예: div[b-3xxtam6d07] > a).

::deep 의사 요소를 HTML 요소에 연결하는 기능을 사용하면 렌더링된 HTML 태그의 구조를 확인할 수 있을 때 다른 구성 요소에 의해 렌더링된 요소에 영향을 주는 범위가 지정된 CSS 스타일을 만들 수 있습니다. 다른 구성 요소 내에서 하이퍼링크 태그(<a>)를 렌더링하는 구성 요소의 경우, 구성 요소를 div(또는 기타 요소)로 래핑하고 ::deep > a 규칙을 사용하여 부모 구성 요소가 렌더링할 때만 해당 구성 요소에 적용되는 스타일을 만듭니다.

Important

범위가 지정된 CSS는 HTML 요소에만 적용되며 태그 도우미가 적용된 요소(예: <input asp-for="..." />)를 포함하여 Razor 구성 요소 또는 태그 도우미에는 적용되지 않습니다.

CSS 전처리기 지원

CSS 전처리기는 변수, 중첩, 모듈, 믹스인 및 상속과 같은 기능을 활용하여 CSS 개발을 개선하는 데 유용합니다. CSS 격리는 Sass 또는 Less 같은 CSS 전처리기를 기본적으로 지원하지 않지만 Blazor가 빌드 프로세스 중 CSS 선택기를 다시 작성하기 전에 전처리기 컴파일이 수행되는 한 CSS 전처리기를 원활하게 통합할 수 있습니다. 예를 들어 Visual Studio를 사용하여 Visual Studio 작업 실행기 탐색기에서 빌드 전 작업으로 기존 전처리기 컴파일을 구성합니다.

같은 AspNetCore.SassCompiler많은 타사 NuGet 패키지는 CSS 격리가 발생하기 전에 빌드 프로세스의 시작 부분에서 SASS/SCSS 파일을 컴파일할 수 있습니다.

CSS 격리 구성

CSS 격리는 바로 작동 가능하도록 설계되었지만 기존 도구나 워크플로에 대한 종속성이 있는 경우처럼 일부 고급 시나리오에 대한 구성을 제공합니다.

범위 식별자 형식 사용자 지정

기본적으로 범위 식별자는 b-{STRING} 형식을 사용합니다. 여기서 {STRING} 자리 표시자는 프레임워크에서 생성된 10자 문자열입니다. 범위 식별자 형식을 사용자 지정하려면 프로젝트 파일을 원하는 패턴으로 업데이트합니다.

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

위의 예제에서 Example.razor.css에 대해 생성된 CSS는 범위 식별자를 b-{STRING}에서 custom-scope-identifier로 변경합니다.

범위가 지정된 CSS 파일을 사용하여 상속을 수행하려면 범위 식별자를 사용하세요. 다음 프로젝트 파일 예제에서 BaseComponent.razor.css 파일은 구성 요소에 걸쳐 일반 스타일을 포함합니다. DerivedComponent.razor.css 파일은 이러한 스타일을 상속합니다.

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

여러 파일에 걸쳐 범위 식별자를 공유하려면 와일드카드(*) 연산자를 사용합니다.

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

기본적으로 범위 식별자는 b-{STRING} 형식을 사용합니다. 여기서 {STRING} 자리 표시자는 프레임워크에서 생성된 10자 문자열입니다. 범위 식별자 형식을 사용자 지정하려면 프로젝트 파일을 원하는 패턴으로 업데이트합니다.

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

위의 예제에서 Example.razor.css에 대해 생성된 CSS는 범위 식별자를 b-{STRING}에서 custom-scope-identifier로 변경합니다.

범위가 지정된 CSS 파일을 사용하여 상속을 수행하려면 범위 식별자를 사용하세요. 다음 프로젝트 파일 예제에서 BaseComponent.razor.css 파일은 구성 요소에 걸쳐 일반 스타일을 포함합니다. DerivedComponent.razor.css 파일은 이러한 스타일을 상속합니다.

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

여러 파일에 걸쳐 범위 식별자를 공유하려면 와일드카드(*) 연산자를 사용합니다.

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

정적 웹 자산에 대한 기본 경로 변경

scoped.styles.css 파일은 앱의 루트에 생성됩니다. 프로젝트 파일에서 <StaticWebAssetBasePath> 속성을 사용하여 기본 경로를 변경합니다. 다음 예제에서는 _content 경로에 scoped.styles.css 파일과 앱의 나머지 자산을 배치합니다.

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

자동 묶음 사용 안 함

Blazor가 런타임에 범위가 지정된 파일을 게시하고 로드하는 방법을 옵트아웃하려면 DisableScopedCssBundling 속성을 사용합니다. 이 속성을 사용하면 다른 도구나 프로세스가 obj 디렉터리에서 격리된 CSS 파일을 가져와 런타임에 게시하고 로드한다는 의미입니다.

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

CSS 격리 사용 안 함

앱의 프로젝트 파일에서 <ScopedCssEnabled> 속성을 false로 설정하여 프로젝트에 대해 CSS 격리를 사용하지 않도록 설정합니다.

<ScopedCssEnabled>false</ScopedCssEnabled>

RCL(Razor 클래스 라이브러리) 지원

NuGet 패키지 또는 RCL(Razor 클래스 라이브러리)의 구성 요소에 대한 격리된 스타일이 자동으로 번들로 묶입니다.

  • 앱은 CSS 가져오기를 사용하여 RCL의 번들 스타일을 참조합니다. ClassLib라는 클래스 라이브러리와 BlazorSample.styles.css 스타일시트를 사용하는 Blazor 앱의 경우 RCL의 스타일시트를 앱 스타일시트 맨 위로 가져옵니다.

    @import '_content/ClassLib/ClassLib.bundle.scp.css';
    
  • RCL의 번들 스타일은 스타일을 사용하는 앱의 정적 웹 자산으로 게시되지 않습니다.

RCL에 대한 자세한 내용은 다음 문서를 참조하세요.