2016-05-10 03:51:23 -04:00
|
|
|
|
block includes
|
|
|
|
|
include ../_util-fns
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
Angular 2 applications are styled with regular CSS. That means we can apply
|
|
|
|
|
everything we know about CSS stylesheets, selectors, rules, and media queries
|
|
|
|
|
to our Angular applications directly.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
Angular 2应用使用标准的CSS来设置样式。这意味着我们可以把关于CSS的那些知识和技能直接用于
|
|
|
|
|
我们的Angular程序中,比如:样式表、选择器、规则,以及媒体查询等。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
On top of this, Angular has the ability to bundle *component styles*
|
|
|
|
|
with our components enabling a more modular design than regular stylesheets.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
在此基础上,Angular还能把*组件样式*紧紧的“捆绑”在我们的组件上,以实现一种比标准样式表更加模块化的设计。
|
|
|
|
|
|
2016-04-18 04:32:46 -04:00
|
|
|
|
In this chapter we learn how to load and apply these *component styles*.
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
在本章中,我们将学到如何加载和使用这些*组件样式*。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
# Table Of Contents
|
2016-05-20 05:53:30 -04:00
|
|
|
|
# 目录
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
* [Using Component Styles](#using-component-styles)
|
2016-05-20 05:53:30 -04:00
|
|
|
|
* [使用组件样式](#using-component-styles)
|
2016-04-05 02:27:10 -04:00
|
|
|
|
* [Special selectors](#special-selectors)
|
2016-05-20 05:53:30 -04:00
|
|
|
|
* [特殊的选择器](#special-selectors)
|
2016-05-10 03:51:23 -04:00
|
|
|
|
* [Loading Styles into Components](#loading-styles)
|
2016-05-20 05:53:30 -04:00
|
|
|
|
* [把样式加载进组件](#loading-styles)
|
2016-05-10 03:51:23 -04:00
|
|
|
|
* [Controlling View Encapsulation: Emulated, Native, and None](#view-encapsulation)
|
2016-05-20 05:53:30 -04:00
|
|
|
|
* [控制视图的包装方式:模拟(Emulated)、原生(Native)或无(None)](#view-encapsulation)
|
2016-04-05 02:27:10 -04:00
|
|
|
|
* [Appendix 1: Inspecting the generated runtime component styles](#inspect-generated-css)
|
2016-05-20 05:53:30 -04:00
|
|
|
|
* [附录1: 审查生成的运行时组件样式](#inspect-generated-css)
|
2016-04-05 02:27:10 -04:00
|
|
|
|
* [Appendix 2: Loading Styles with Relative URLs](#relative-urls)
|
2016-05-20 05:53:30 -04:00
|
|
|
|
* [附录2: 用相对URL加载样式](#relative-urls)
|
2016-05-10 03:51:23 -04:00
|
|
|
|
p
|
|
|
|
|
| #[+liveExampleLink2('Run the live example', 'component-styles')]
|
|
|
|
|
| of the code shown in this chapter.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
p
|
|
|
|
|
| #[+liveExampleLink2('运行本章代码的在线范例', 'component-styles')]
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
.l-main-section
|
|
|
|
|
:marked
|
|
|
|
|
## Using Component Styles
|
2016-05-20 05:53:30 -04:00
|
|
|
|
## 使用组件样式
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
For every Angular 2 component we write, we may define not only an HTML template,
|
|
|
|
|
but also the CSS styles that go with that template,
|
|
|
|
|
specifying any selectors, rules, and media queries that we need.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
对于我们写的每个Angular 2组件来说,除了可以定义HTML模板之外,还有模板上的CSS样式。
|
|
|
|
|
只要需要,我们就可以指定任何选择器、规则和媒体查询。
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
One way to do this is to set the `styles` property in the component metadata.
|
2016-05-10 03:51:23 -04:00
|
|
|
|
The `styles` property takes #{_an_array} of strings that contain CSS code.
|
2016-04-05 02:27:10 -04:00
|
|
|
|
Usually we give it one string as in this example:
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
它的实现方式之一,是在组件的元数据中设置`styles`属性。
|
|
|
|
|
`styles`属性可以接受一个包含CSS代码的字符串数组。
|
|
|
|
|
通常我们只给它一个字符串就行了,例子如下:
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
+makeExample('component-styles/ts/app/hero-app.component.ts')(format='.')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
Component styles differ from traditional, global styles in a couple of ways.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
组件样式在很多方面都不同于传统的、全局性样式。
|
|
|
|
|
|
2016-05-08 17:39:50 -04:00
|
|
|
|
Firstly, the selectors we put into a component's styles *only apply within the template
|
2016-05-10 03:51:23 -04:00
|
|
|
|
of that component*. The `h1` selector in the example above only applies to the `<h1>` tag
|
2016-04-05 02:27:10 -04:00
|
|
|
|
in the template of `HeroAppComponent`. Any `<h1>` elements elsewhere in
|
|
|
|
|
the application are unaffected.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
首先,我们放在组件样式中的选择器,只会应用在组件自身的模板中。上面这个例子中的`h1`选择器只会对
|
|
|
|
|
`HeroAppComponent`模板中的`<h1>`标签生效,而对应用中其它地方的`<h1>`元素毫无影响。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
This is a big improvement in modularity compared to how CSS traditionally works:
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
这种模块化相对于CSS的传统工作方式是一个巨大的改进:
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
1. We can use the CSS class names and selectors that make the most sense in the context of each component.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
1. 只有在每个组件的情境中使用CSS类名和选择器,才是最有意义的。
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
1. Class names and selectors are local to the component and won't collide with
|
|
|
|
|
classes and selectors used elsewhere in the application.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
1. 类名和选择器是仅属于组件内部的,它不会和应用中其它地方的类名和选择器出现冲突。
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
1. Our component's styles *cannot* be changed by changes to styles elsewhere in the application.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
1. 我们组件的样式*不会*因为别的地方修改了样式而被意外改变。
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
1. We can co-locate the CSS code of each component with the TypeScript and HTML code of the component,
|
|
|
|
|
which leads to a neat and tidy project structure.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
1. 我们可以让每个组件的CSS代码和它的TypeScript代码、HTML代码放在一起,这将产生清爽整洁的项目结构。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
1. We can change or remove component CSS code in the future without trawling through the
|
|
|
|
|
whole application to see where else it may have been used. We just look at the component we're in.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
1. 将来我们可以修改或移除组件的CSS代码,而不用遍历整个应用来看它有没有被别处用到,只要看看当前组件就可以了。
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
a(id="special-selectors")
|
|
|
|
|
.l-main-section
|
|
|
|
|
:marked
|
|
|
|
|
## Special selectors
|
2016-05-20 05:53:30 -04:00
|
|
|
|
## 特殊的选择器
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
Component styles have a few special *selectors* from the world of
|
2016-05-10 03:51:23 -04:00
|
|
|
|
[shadow DOM style scoping](https://www.w3.org/TR/css-scoping-1):
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
“组件样式”中有一些特殊的*选择器*,它们是从[范围化CSS](https://www.w3.org/TR/css-scoping-1)的世界里引入的shadow DOM选择器。
|
|
|
|
|
|
|
|
|
|
### :host
|
2016-04-05 02:27:10 -04:00
|
|
|
|
### :host
|
|
|
|
|
|
|
|
|
|
Use the `:host` pseudo-class selector to target styles in the element that *hosts* the component (as opposed to
|
|
|
|
|
targeting elements *inside* the component's template):
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
使用`:host`伪类选择器,用来选择组件*宿主*元素中的元素(相对于组件模板*内部*的元素)。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
+makeExample('component-styles/ts/app/hero-details.component.css', 'host')(format='.')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
This is the *only* way we can target the host element. We cannot reach
|
|
|
|
|
it from inside the component with other selectors, because it is not part of the
|
|
|
|
|
component's own template. It is in a parent component's template.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
这是我们能以宿主元素为目标的*唯一*方式。除此之外,我们将没办法指定它,因为宿主不是组件自身模板的一部分,而是父组件模板的一部分。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
Use the *function form* to apply host styles conditionally by
|
|
|
|
|
including another selector inside parentheses after `:host`.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
要把宿主样式作为条件,就要像*函数*一样把其它选择器放在`:host`后面的括号中。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
In the next example we target the host element again, but only when it also has the `active` CSS class.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
在下一个例子中,我们又一次把宿主元素作为目标,但是只有当它同时带有`active` CSS类的时候才会生效。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
+makeExample('component-styles/ts/app/hero-details.component.css', 'hostfunction')(format=".")
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
### :host-context
|
2016-05-20 05:53:30 -04:00
|
|
|
|
### :host-context
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
Sometimes it is useful to apply styles based on some condition *outside* a component's view.
|
|
|
|
|
For example, there may be a CSS theme class applied to the document `<body>` element, and
|
|
|
|
|
we want to change how our component looks based on that.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
有时候,基于某些来自组件视图*外部*的条件应用样式是很有用的。
|
|
|
|
|
比如,在文档的`<body>`元素上可能有一个用于表示样式主题(Theme)的CSS类,而我们应当基于它来决定组件的样式。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
Use the `:host-context()` pseudo-class selector. It works just like the function
|
|
|
|
|
form of `:host()`. It looks for a CSS class in *any ancestor* of the component host element, all the way
|
|
|
|
|
up to the document root. It's useful when combined with another selector.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
这时可以使用`:host-context()`伪类选择器。它也以类似`:host()`形式使用。它在当前组件宿主元素的*祖先节点*中查找CSS类,
|
|
|
|
|
直到文档的根节点为止。在与其它选择器组合使用时,它非常有用。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
In the following example, we apply a `background-color` style to all `<h2>` elements *inside* the component, only
|
|
|
|
|
if some ancestor element has the CSS class `theme-light`.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
在下面的例子中,只有当某个祖先元素有CSS类`theme-light`时,我们才会把`background-color`样式应用到组件*内部*的所有`<h2>`元素中。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
+makeExample('component-styles/ts/app/hero-details.component.css', 'hostcontext')(format='.')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
### /deep/
|
2016-05-20 05:53:30 -04:00
|
|
|
|
### /deep/
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
Component styles normally apply only to the HTML in the component's own template.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
“组件样式”通常只会作用于组件自身的HTML上。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
We can use the `/deep/` selector to force a style down through the child component tree into all the child component views.
|
|
|
|
|
The `/deep/` selector works to any depth of nested components, and it applies *both to the view
|
|
|
|
|
children and the content children* of the component.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
我们可以使用`/deep/`选择器,来强制一个样式对各级子组件的视图也生效,它*不但作用于组件的子视图,也会作用于组件的内容*。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
In this example, we target all `<h3>` elements, from the host element down
|
|
|
|
|
through this component to all of its child elements in the DOM:
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
在这个例子中,我们以所有的`<h3>`元素为目标,从宿主元素到当前元素再到DOM中的所有子元素:
|
2016-04-05 02:27:10 -04:00
|
|
|
|
+makeExample('component-styles/ts/app/hero-details.component.css', 'deep')(format=".")
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
The `/deep/` selector also has the alias `>>>`. We can use either of the two interchangeably.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
`/deep/`选择器还有一个别名`>>>`。我们可以任意交替使用它们。
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
2016-04-06 14:46:21 -04:00
|
|
|
|
.alert.is-important
|
2016-04-05 02:27:10 -04:00
|
|
|
|
:marked
|
|
|
|
|
The `/deep/` and `>>>` selectors should only be used with **emulated** view encapsulation.
|
|
|
|
|
This is the default and it is what we use most of the time. See the
|
2016-05-10 03:51:23 -04:00
|
|
|
|
[Controlling View Encapsulation](#view-encapsulation)
|
2016-04-05 02:27:10 -04:00
|
|
|
|
section for more details.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
`/deep/`和`>>>`选择器只能被用在**模拟(Emulated)**视图包装方式下。
|
|
|
|
|
这种方式是默认值,也是用得最多的方式。要了解更多,请参阅[控制视图包装方式](#view-encapsulation)一节。
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
a(id='loading-styles')
|
|
|
|
|
.l-main-section
|
|
|
|
|
:marked
|
|
|
|
|
## Loading Styles into Components
|
2016-05-20 05:53:30 -04:00
|
|
|
|
## 把样式加载进组件中
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
We have several ways to add styles to a component:
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
我们有几种方式来把样式加入组件:
|
2016-04-05 02:27:10 -04:00
|
|
|
|
* inline in the template HTML
|
2016-05-20 05:53:30 -04:00
|
|
|
|
* 内联在模板的HTML中
|
2016-04-05 02:27:10 -04:00
|
|
|
|
* by setting `styles` or `styleUrls` metadata
|
2016-05-20 05:53:30 -04:00
|
|
|
|
* 设置`styles`或`styleUrls`元数据
|
2016-04-05 02:27:10 -04:00
|
|
|
|
* with CSS imports
|
2016-05-20 05:53:30 -04:00
|
|
|
|
* 通过CSS文件导入
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
The scoping rules outlined above apply to each of these loading patterns.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
上述范围化规则对所有这些加载模式都适用。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
### Styles in Metadata
|
2016-05-20 05:53:30 -04:00
|
|
|
|
### 元数据中的样式
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
2016-05-10 03:51:23 -04:00
|
|
|
|
We can add a `styles` #{_array} property to the `@Component` #{_decorator}.
|
|
|
|
|
Each string in the #{_array} (usually just one string) defines the CSS.
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
我们可以给`@Component`#{_decoratorCn}添加一个`styles`数组型属性。
|
|
|
|
|
这个数组中的每一个字符串(通常也只有一个)定义一份CSS。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
+makeExample('component-styles/ts/app/hero-app.component.ts')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
### Template Inline Styles
|
2016-05-20 05:53:30 -04:00
|
|
|
|
### 模板内联样式
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
We can embed styles directly into the HTML template by putting them
|
|
|
|
|
inside `<style>` tags.
|
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
我们也可以把它们放到`<style>`标签中来直接在HTML模板中嵌入样式。
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
+makeExample('component-styles/ts/app/hero-controls.component.ts', 'inlinestyles')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
### Style URLs in Metadata
|
2016-05-20 05:53:30 -04:00
|
|
|
|
### 元数据中的样式表URL
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
We can load styles from external CSS files by adding a `styleUrls` attribute
|
2016-05-10 03:51:23 -04:00
|
|
|
|
into a component's `@Component` or `@View` #{_decorator}:
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
2016-05-20 05:53:30 -04:00
|
|
|
|
我们还可以通过给组件的`@Component`或`@View`#{_decoratorCn}中添加一个`styleUrls`属性来从外部CSS文件中加载样式:
|
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
+makeExample('component-styles/ts/app/hero-details.component.ts', 'styleurls')
|
|
|
|
|
|
2016-05-10 03:51:23 -04:00
|
|
|
|
block style-url
|
|
|
|
|
.alert.is-important
|
|
|
|
|
:marked
|
|
|
|
|
The URL is ***relative to the application root*** which is usually the
|
|
|
|
|
location of the `index.html` web page that hosts the application.
|
|
|
|
|
The style file URL is *not* relative to the component file.
|
|
|
|
|
That's why the example URL begins `app/`.
|
|
|
|
|
See [Appendix 2](#relative-urls) to specify a URL relative to the
|
|
|
|
|
component file.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
URL是***相对于应用程序根目录的***,它通常是应用的宿主页面`index.html`所在的地方。
|
|
|
|
|
这个样式文件的URL*不是*相对于组件文件的。这就是为什么范例中的URL用`app/`开头儿。
|
|
|
|
|
参见[附录2](#relative-urls)来了解如何指定相对于组件文件的URL。
|
2016-05-10 03:51:23 -04:00
|
|
|
|
|
|
|
|
|
block module-bundlers
|
|
|
|
|
.l-sub-section
|
|
|
|
|
:marked
|
|
|
|
|
Users of module bundlers like Webpack may also use the `styles` attribute
|
|
|
|
|
to load styles from external files at build time. They could write:
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
像Webpack这类模块打包器的用户可能会使用`styles`属性来在构建时从外部文件中加载样式。他们可能这样写:
|
2016-05-10 03:51:23 -04:00
|
|
|
|
|
|
|
|
|
`styles: [require('my.component.css')]`
|
|
|
|
|
|
|
|
|
|
We set the `styles` property, **not** `styleUrls` property! The module
|
|
|
|
|
bundler is loading the CSS strings, not Angular.
|
|
|
|
|
Angular only sees the CSS strings *after* the bundler loads them.
|
|
|
|
|
To Angular it is as if we wrote the `styles` array by hand.
|
|
|
|
|
Refer to the module bundler's documentation for information on
|
|
|
|
|
loading CSS in this manner.
|
2016-05-20 05:53:30 -04:00
|
|
|
|
|
|
|
|
|
注意,这时候我们是在设置`styles`属性,**而不是**`styleUrls`属性!
|
|
|
|
|
是模块打包器在加载CSS字符串,而不是Angular。
|
|
|
|
|
Angular看到的只是打包器加载它们之后的CSS字符串。
|
|
|
|
|
对Angular来说,这跟我们手写了`styles`数组没有任何区别。
|
|
|
|
|
要了解这种CSS加载方式的更多信息,请参阅相应模块打包器的文档。
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
### Template Link Tags
|
|
|
|
|
|
|
|
|
|
We can also embed `<link>` tags into the component's HTML template.
|
|
|
|
|
|
2016-05-10 03:51:23 -04:00
|
|
|
|
As with `styleUrls`, the link tag's `href` URL is relative to the
|
|
|
|
|
application root, not relative to the component file.
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
+makeExample('component-styles/ts/app/hero-team.component.ts', 'stylelink')
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
### CSS @imports
|
|
|
|
|
|
|
|
|
|
We can also import CSS files into our CSS files by using the standard CSS
|
|
|
|
|
[`@import` rule](https://developer.mozilla.org/en/docs/Web/CSS/@import).
|
|
|
|
|
|
2016-05-10 03:51:23 -04:00
|
|
|
|
block css-import-url
|
|
|
|
|
:marked
|
|
|
|
|
In *this* case the URL is relative to the CSS file into which we are importing.
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
|
|
|
|
+makeExample('component-styles/ts/app/hero-details.component.css', 'import', 'app/hero-details.component.css (excerpt)')
|
2016-05-10 03:51:23 -04:00
|
|
|
|
|
|
|
|
|
a#view-encapsulation
|
2016-04-05 02:27:10 -04:00
|
|
|
|
.l-main-section
|
|
|
|
|
:marked
|
|
|
|
|
## Controlling View Encapsulation: Native, Emulated, and None
|
|
|
|
|
|
|
|
|
|
As discussed above, component CSS styles are *encapsulated* into the component's own view and do
|
|
|
|
|
not affect the rest of the application.
|
|
|
|
|
|
|
|
|
|
We can control how this encapsulation happens on a *per
|
|
|
|
|
component* basis by setting the *view encapsulation mode* in the component metadata. There
|
|
|
|
|
are three modes to choose from:
|
|
|
|
|
|
|
|
|
|
* `Native` view encapsulation uses the browser's native [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
|
|
|
|
|
implementation to attach a Shadow DOM to the component's host element, and then puts the component
|
|
|
|
|
view inside that Shadow DOM. The component's styles are included within the Shadow DOM.
|
|
|
|
|
|
|
|
|
|
* `Emulated` view encapsulation (**the default**) emulates the behavior of Shadow DOM by preprocessing
|
|
|
|
|
(and renaming) the CSS code to effectively scope the CSS to the component's view.
|
|
|
|
|
See [Appendix 1](#inspect-generated-css) for details.
|
|
|
|
|
|
|
|
|
|
* `None` means that Angular does no view encapsulation.
|
|
|
|
|
Angular adds the CSS to the global styles.
|
|
|
|
|
The scoping rules, isolations, and protections discussed earlier do not apply.
|
|
|
|
|
This is essentially the same as pasting the component's styles into the HTML.
|
|
|
|
|
|
|
|
|
|
Set the components encapsulation mode using the `encapsulation` property in the component metadata:
|
|
|
|
|
|
|
|
|
|
+makeExample('component-styles/ts/app/quest-summary.component.ts', 'encapsulation.native')(format='.')
|
2016-05-10 03:51:23 -04:00
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
:marked
|
|
|
|
|
`Native` view encapsulation only works on [browsers that have native support
|
|
|
|
|
for Shadow DOM](http://caniuse.com/#feat=shadowdom). The support is still limited,
|
|
|
|
|
which is why `Emulated` view encapsulation is the default mode and recommended
|
|
|
|
|
in most cases.
|
|
|
|
|
|
2016-05-10 03:51:23 -04:00
|
|
|
|
a#inspect-generated-css
|
2016-04-05 02:27:10 -04:00
|
|
|
|
.l-main-section
|
|
|
|
|
:marked
|
|
|
|
|
## Appendix 1: Inspecting The CSS Generated in Emulated View Encapsulation
|
|
|
|
|
|
|
|
|
|
When using the default emulated view encapsulation, Angular preprocesses
|
|
|
|
|
all component styles so that they approximate the standard Shadow CSS scoping rules.
|
|
|
|
|
|
|
|
|
|
When we inspect the DOM of a running Angular application with emulated view
|
|
|
|
|
encapsulation enabled, we see that each DOM element has some extra attributes
|
|
|
|
|
attached to it:
|
|
|
|
|
|
|
|
|
|
code-example(format="").
|
|
|
|
|
<hero-details _nghost-pmm-5>
|
|
|
|
|
<h2 _ngcontent-pmm-5>Mister Fantastic</h2>
|
|
|
|
|
<hero-team _ngcontent-pmm-5 _nghost-pmm-6>
|
|
|
|
|
<h3 _ngcontent-pmm-6>Team</h3>
|
|
|
|
|
</hero-team>
|
|
|
|
|
</hero-detail>
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
We see two kinds of generated attributes:
|
|
|
|
|
* An element that would be a Shadow DOM host in native encapsulation has a
|
|
|
|
|
generated `_nghost` attribute. This is typically the case for component host elements.
|
|
|
|
|
|
|
|
|
|
* An element within a component's view has a `_ngcontent` attribute
|
|
|
|
|
that identifies to which host's emulated Shadow DOM this element belongs.
|
|
|
|
|
|
|
|
|
|
The exact values of these attributes are not important. They are automatically
|
|
|
|
|
generated and we never refer to them in application code. But they are targeted
|
|
|
|
|
by the generated component styles, which we'll find in the `<head>` section of the DOM:
|
|
|
|
|
|
|
|
|
|
code-example(format="").
|
|
|
|
|
[_nghost-pmm-5] {
|
|
|
|
|
display: block;
|
|
|
|
|
border: 1px solid black;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h3[_ngcontent-pmm-6] {
|
|
|
|
|
background-color: white;
|
|
|
|
|
border: 1px solid #777;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:marked
|
|
|
|
|
These are the styles we wrote, post-processed so that each selector is augmented
|
|
|
|
|
with `_nghost` or `_ngcontent` attribute selectors.
|
|
|
|
|
These extra selectors enable the scoping rules described in this guide.
|
|
|
|
|
|
|
|
|
|
We'll likely live with *emulated* mode until shadow DOM gains traction.
|
|
|
|
|
|
2016-05-10 03:51:23 -04:00
|
|
|
|
a#relative-urls
|
2016-04-05 02:27:10 -04:00
|
|
|
|
.l-main-section
|
|
|
|
|
:marked
|
|
|
|
|
## Appendix 2: Loading Styles with Relative URLs
|
|
|
|
|
|
|
|
|
|
It's common practice to split a component's code, HTML, and CSS into three separate files in the same directory:
|
|
|
|
|
|
|
|
|
|
code-example(format='').
|
|
|
|
|
quest-summary.component.ts
|
|
|
|
|
quest-summary.component.html
|
|
|
|
|
quest-summary.component.css
|
2016-05-10 03:51:23 -04:00
|
|
|
|
|
2016-04-05 02:27:10 -04:00
|
|
|
|
:marked
|
|
|
|
|
We include the template and CSS files by setting the `templateUrl` and `styleUrls` metadata properties respectively.
|
|
|
|
|
Because these files are co-located with the component,
|
|
|
|
|
it would be nice to refer to them by name without also having to specify a path back to the root of the application.
|
|
|
|
|
|
2016-05-10 03:51:23 -04:00
|
|
|
|
block module-id
|
|
|
|
|
:marked
|
|
|
|
|
We'd *prefer* to write this:
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
2016-05-10 03:51:23 -04:00
|
|
|
|
+makeExample('component-styles/ts/app/quest-summary.component.ts', 'urls')(format='.')
|
2016-04-05 02:27:10 -04:00
|
|
|
|
|
2016-04-06 14:46:21 -04:00
|
|
|
|
:marked
|
2016-05-10 03:51:23 -04:00
|
|
|
|
We can't do that by default. Angular can't find the files and throws an error:
|
|
|
|
|
|
|
|
|
|
`EXCEPTION: Failed to load quest-summary.component.html`
|
|
|
|
|
|
|
|
|
|
Why can't Angular calculate the HTML and CSS URLs from the component file's location?
|
|
|
|
|
|
|
|
|
|
Unfortunately, that location is not readily known.
|
|
|
|
|
Angular apps can be loaded in many ways: from individual files, from SystemJS packages, or
|
|
|
|
|
from CommonJS packages, to name a few.
|
|
|
|
|
With this diversity of load strategies, it's not easy to tell at runtime where these files actually reside.
|
|
|
|
|
|
|
|
|
|
The only location Angular can be sure of is the URL of the `index.html` home page.
|
|
|
|
|
So by default it resolves template and style paths relative to the URL of `index.html`.
|
|
|
|
|
That's why we previously wrote our CSS file URLs with an `app/` base path prefix.
|
|
|
|
|
|
|
|
|
|
Although this works with any code loading scheme, it is very inconvenient.
|
|
|
|
|
We move file folders around all the time during the evolution of our applications.
|
|
|
|
|
It's no fun patching the style and template URLs when we do.
|
|
|
|
|
|
|
|
|
|
### *moduleId*
|
|
|
|
|
|
|
|
|
|
We can change the way Angular calculates the full URL be setting the component metadata's `moduleId` property.
|
|
|
|
|
|
|
|
|
|
If we knew the component file's base path, we'd set `moduleId` to that and
|
|
|
|
|
let Angular construct the full URL from this base path plus the CSS and template file names.
|
|
|
|
|
|
|
|
|
|
Our challenge is to calculate the base path with minimal effort.
|
|
|
|
|
If it's too hard, we shouldn't bother; we should just write the full path to the root and move on.
|
2016-05-11 01:15:51 -04:00
|
|
|
|
Fortunately, *certain* module loaders make it relatively easy to find the base path.
|
2016-05-10 03:51:23 -04:00
|
|
|
|
|
2016-05-11 01:15:51 -04:00
|
|
|
|
SystemJS (starting in v.0.19.19) sets a *semi-global* variable to the URL of the component file.
|
|
|
|
|
That makes it trivial to set the component metadata `moduleId` property to the component's URL
|
|
|
|
|
and let Angular determine the module-relative paths for style and template URLs from there.
|
|
|
|
|
|
|
|
|
|
The name of the *semi-global* variable depends upon whether we told TypeScript to transpile to
|
|
|
|
|
'system' or 'commonjs' format (see the `module` option in the
|
|
|
|
|
[TypeScript compiler documentation](http://www.typescriptlang.org/docs/handbook/compiler-options.html)).
|
|
|
|
|
The variables are `__moduleName` and `module.id` respectively.
|
|
|
|
|
|
2016-04-13 13:20:51 -04:00
|
|
|
|
Here's an example in which we set the metadata `moduleId` to `module.id`.
|
2016-05-10 03:51:23 -04:00
|
|
|
|
|
|
|
|
|
+makeExample('component-styles/ts/app/quest-summary.component.ts','', 'app/quest-summary.component.ts')
|
|
|
|
|
|
|
|
|
|
.l-sub-section
|
|
|
|
|
:marked
|
|
|
|
|
With a module bundler like Webpack we are more likely to set the `styles` and `template` properties with the bundler's
|
|
|
|
|
`require` mechanism rather than bother with `styleUrls` and `templateUrl`.
|