5. 컴포넌트 스타일
Angular 애플리케이션의 스타일은 표준 CSS를 사용해서 지정한다. 따라서 기존에 사용하고 있는 CSS 스타일시트, 셀렉터, 룰, 미디어 쿼리도 Angular 애플리케이션에 그대로 사용할 수 있다.
Angular는 여기에 추가로 개별 컴포넌트에 컴포넌트 스타일을 적용할 수 있으며, CSS 스타일 외에 다른 스타일 도구도 활용할 수 있다.
이 문서는 컴포넌트 스타일을 어떻게 불러오거나 지정할 수 있는지 안내한다.
이 문서에서 다루는 예제는 라이브 예제 링크 / 다운로드 링크에서 확인하거나 다운받을 수 있다.
1. 컴포넌트 스타일 사용하기
개발자가 만드는 모든 Angular 컴포넌트는 HTML 템플릿 외에 CSS 스타일도 지정할 수 있다. 이 스타일 설정에는 기존에 사용하던 셀렉터, 룰, 미디어 쿼리도 그대로 사용할 수 있다.
가장 간단한 방법은 컴포넌트 메타데이터에 styles
프로퍼티를 사용하는 것이다. styles
프로퍼티에는 CSS 코드를 문자열 배열 형태로 지정하며, 다음과 같이 문자열 하나로도 간단하게 지정할 수 있다:
@Component({
selector: "app-root",
template: `
<h1>Tour of Heroes</h1>
<app-hero-main [hero]="hero"></app-hero-main>
`,
styles: ["h1 { font-weight: normal; }"],
})
export class HeroAppComponent {
/* . . . */
}
2. 스타일 적용 범위
Note
@Component
메타데이터에 지정한 스타일은 그 컴포넌트의 템플릿에만 적용된다.
컴포넌트 스타일은 템플릿 안에 있는 자식 컴포넌트의 템플릿이나 이 컴포넌트에 프로젝트되는 컴포넌트에는 적용되지 않는다.
이 예제로 보면 h1
엘리먼트 스타일은 HeroAppComponent
에만 적용되며, 자식 컴포넌트 HeroMainComponent
나 컴포넌트 외부에 있는 <h1>
태그에는 적용되지 않는다.
그래서 컴포넌트에 적용되는 스타일은 다음과 같은 스타일 모듈 규칙을 따른다.
- 컴포넌트를 구분하기 위해 적절한 CSS 클래스 이름과 셀렉터를 사용할 수 있다.
- 클래스 이름과 셀렉터는 컴포넌트 안에서만 유효하며, 컴포넌트 밖에 있는 클래스와 셀렉터에는 적용되지 않는다.
- 컴포넌트 밖에서 스타일이 동적으로 변경되어도 컴포넌트에는 적용되지 않는다.
- 프로젝트 규모가 작거나 간단하게 테스트 하려면 CSS 코드를 TypeScript 코드나 HTML에 작성할 수 있다.
- 컴포넌트에 적용되는 CSS 코드는 컴포넌트 외부에 적용되지 않기 때문에 걱정없이 변경하거나 제거할 수 있다.
3. Angular 전용 셀렉터
컴포넌트에 스타일 문법에는 섀도우 DOM에 적용할 수 있는 특별한 셀렉터 몇 가지를 사용할 수 있다. 이 셀렉터들은 W3C 사이트의 CSS Scoping Module Level 1에서 정의하는 표준 셀렉터이다.
1) :host
컴포넌트는 컴포넌트 셀렉터와 같은 이름의 엘리먼트 안에 구성된다. 이 엘리먼트는 이후에 템플릿에 렌더링되는데, 이 엘리먼트가 렌더링되는 위치를 호스트 엘리먼트(host element)라고 한다. :host
가상 클래스 셀렉터는 이 호스트 엘리먼트를 가리킨다. 대상 엘리먼트(targeting elements)는 호스트 엘리먼트 안에 들어가는 엘리먼트로, 호스트 엘리먼트와는 반대 개념이다.
@Component({
selector: "app-main",
template: `
<h1>It Works!</h1>
<div>Start editing to see some magic happen :)</div>
`,
})
export class HostSelectorExampleComponent {}
컴포넌트의 호스트 엘리먼트에 스타일을 지정해 보자. :host
셀렉터를 붙여 지정하는 규칙은 호스트 엘리먼트와 그 자식 엘리먼트에 영향을 미친다.
:host
셀렉터는 컴포넌트의 호스트 엘리먼트만 대상으로 지정할 수 있다. 그래서 :host
블록 안에 선언한 스타일은 모두 부모 컴포넌트에 영향을 미치지 않는다.
아래 예제처럼 구현하면 호스트 엘리먼트에 active
CSS 클래스가 지정되었을 때 텍스트를 굵게 표시한다.
:host {
font-style: italic;
}
:host(.active) {
font-weight: bold;
}
:host
셀렉터는 다른 셀렉터와 조합해서 사용할 수 있다. 그래서 :host h2
와 같이 작성하면 모든 컴포넌트 뷰에 있는 엘리먼트 중에서 모든 <h2>
를 대상으로 지정할 수 있다.
Note
:host
셀렉터 앞에는 다른 셀렉터(:host-context
제외)를 사용할 수 없다.:host
셀렉터는 컴포넌트의 뷰를 대상으로 하기 때문에 외부 컨텍스트를 지정할 수 없다.- 외부 컨텍스트와 연동하려면
:host-context
셀렉터를 사용해야 한다.
2) :host-context
때로는 호스트 엘리먼트의 부모 엘리먼트의 조건에 따라 컴포넌트 템플릿의 스타일을 적용해야 하는 경우가 있다. HTML 문서의 <body>
엘리먼트에 CSS 테마 관련 클래스가 지정된다면 이 조건에 따라 컴포넌트의 모습을 변형하는 경우가 그렇다.
이 때 :host-context
가상 클래스 셀렉터를 사용하면 :host()
를 사용할 때와 비슷하게 컴포넌트 밖에 있는 엘리먼트를 가리킬 수 있다. :host-context()
셀렉터는 컴포넌트가 위치하는 호스트 엘리먼트의 부모 엘리먼트로부터 HTML 문서의 루트 노드까지 적용된다. 이 셀렉터는 다른 셀렉터와 마찬가지로 조합해서 사용할 수도 있다.
아래 예제 코드는 호스트 엘리먼트의 부모 엘리먼트 중에 active
CSS 클래스가 지정되었을 때 텍스트에 이탤릭 스타일을 지정하는 예제 코드이다.
호스트 엘리먼트와 그 자식 엘리먼트만 영향을 받는다는 것이 중요하다. active
클래스가 지정된 호스트 엘리먼트의 부모 엘리먼트는 영향을 받지 않는다.
4. 컴포넌트 스타일 지정하기
컴포넌트에 스타일을 지정하려면 다음과 같은 방법을 활용할 수 있다.
- 컴포넌트 메타데이터에
style
이나styleUrls
사용하기 - 템플릿 HTML에 인라인으로 지정하기
- 외부 CSS 파일 불러오기
1) 컴포넌트 메타데이터로 스타일 지정하기
@Component
데코레이터에는 styles
프로퍼티를 지정할 수 있다.
이 프로퍼티는 문자열 배열을 사용하는데, 컴포넌트에 지정될 CSS 스타일을 문자열로 각각 지정한다.
@Component({
selector: "app-root",
template: `
<h1>Tour of Heroes</h1>
<app-hero-main [hero]="hero"></app-hero-main>
`,
styles: ["h1 { font-weight: normal; }"],
})
export class HeroAppComponent {
/* . . . */
}
Note
- 이 방법으로 지정하는 스타일은 이 컴포넌트에만 적용된다.
- 템플릿 안에 있는 자식 컴포넌트나, 이 컴포넌트에 프로젝트되는 다른 컨텐츠에도 적용되지 않는다.
Angular CLI로 ng generate component
명령을 실행할 때 --inline-style
플래그를 지정하면 styles
배열이 비어있는 상태에서 컴포넌트 코드 개발을 시작할 수 있다.
2) 컴포넌트 메타데이터에 외부 스타일 파일 불러오기
컴포넌트의 @Component
데코레이터에 styleUrls
프로퍼티를 사용하면 컴포넌트 외부에 있는 CSS 파일을 불러와서 컴포넌트에 적용할 수 있다.
Note
- 이 방법으로 지정하는 스타일은 이 컴포넌트에만 적용된다.
- 템플릿 안에 있는 자식 컴포넌트나, 이 컴포넌트에 프로젝트되는 다른 컨텐츠에도 적용되지 않는다.
styles
이나styleUrls
프로퍼티에는 한 번에 여러 스타일을 지정하거나 여러 파일을 지정할 수 있다.
Angular CLI로 ng generate component
명령을 실행할 때 --inline-style
플래그를 지정하지 않으면 컴포넌트 이름으로 스타일 파일을 만들고 컴포넌트 메타데이터의 styleUrls
에서 이 파일을 참조한다.
3) 템플릿 인라인 스타일
CSS 스타일은 <style>
태그를 사용해서 HTML 템플릿 안에 지정할 수도 있다.
@Component({
selector: 'app-hero-controls',
template: `
<style>
button {
background-color: white;
border: 1px solid #777;
}
</style>
<h3>Controls</h3>
<button (click)="activate()">Activate</button>
`
})
4) 템플릿 <link>
태그
컴포넌트 HTML 템플릿에는 <link>
태그를 사용할 수도 있다.
@Component({
selector: 'app-hero-team',
template: `
<!-- We must use a relative URL so that the AOT compiler can find the stylesheet -->
<link rel="stylesheet" href="../assets/hero-team.component.css">
<h3>Team</h3>
<ul>
<li *ngFor="let member of hero.team">
{{member}}
</li>
</ul>`
})
Note
- Angular CLI가 애플리케이션을 빌드할 때 링크로 연결된 스타일 파일이
assets
폴더에 있고 빌드 결과에 제대로 포함되는지 꼭 확인한다. - 스타일 파일이
assets
폴더에 있다면 CLI가 이 스타일 파일을 빌드 결과물에 포함시키며, 컴포넌트에서는 애플리케이션 최상위 경로나 컴포넌트 파일의 상대 경로로 이 스타일 파일을 참조할 수 있다.
5) CSS @imports
외부 CSS 파일을 불러올 때는 CSS 표준인 @import
를 사용하는 방법도 있다.
이 경우에는 CSS 파일을 로드하는 컴포넌트에서 시작하는 상대 경로로 외부 CSS 파일의 URL을 지정한다.
/* AOT 컴파일러를 사용한다면 이 파일이 로컬에 있다는 것을 지정하기 위해 주소가 `./`로 시작되어야 합니다. */
@import "./hero-details-box.css";
6) 전역 스타일 파일
Angular CLI로 애플리케이션의 빌드 설정 파일인 angular.json
파일은 빌드에 포함될 모든 외부 자원을 지정하는데, 이 때 외부 스타일 파일을 지정할 수도 있다.
이 때 styles
항목을 활용하면 전역으로 지정될 스타일 파일을 지정할 수 있으며, CLI로 생성한 프로젝트라면 styles.css
파일이 초기값으로 지정된다.
7) CSS 이외의 스타일 파일
Angular CLI를 사용한다면 sass나 less를 사용할 수도 있으며, 이렇게 만든 스타일 파일은 @Component.styleUrls
메타데이터에 다음과 같이 지정할 수 있다:
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
...
그러면 Angular CLI에 정의된 CSS 프리프로세서를 통해 최종 결과물에는 CSS 스타일로 변환된다.
ng generate component
명령으로 컴포넌트를 생성하면 비어있는 CSS 파일(.css
)이 기본으로 생성된다.
Note
@Component.styles
에 문자열로 지정하는 스타일은 반드시 CSS 문법으로 지정해야 한다.- Angular CLI는 인라인 스타일을 처리할 때 CSS 프리프로세서를 별도로 사용하지 않는다.