Загрузить внешний CSS в компонент

import {Component} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: '<div></div>',
    styleUrls: [
        'http://example.com/external.css',
        'app/local.css'
    ]
})
export class AppComponent {}

external.css не загружается.

Есть ли способ загрузить внешний CSS в Angular 2 Component?

Ответ 1

Смотрите также https://angular.io/docs/ts/latest/guide/component-styles.html

Посмотреть инкапсуляцию

Чтобы позволить внешним стилям влиять на содержимое компонентов, вы можете изменить инкапсуляцию представления (то, что предотвращает "утечку" стилей в компоненты).

@Component({
    selector: 'some-component',
    template: '<div></div>',
    styleUrls: [
        'http://example.com/external.css',
        'app/local.css'
    ], 
    encapsulation: ViewEncapsulation.None, 
})
export class SomeComponent {}

Представление инкапсуляции выполняет цель. Лучший способ - добавить стили непосредственно к компоненту, на который они должны повлиять. ViewEncapsulation устанавливается для каждого компонента и может пригодиться в некоторых ситуациях.

"пирсинг тени"

Вы также можете использовать CSS-комбинатор с прокалыванием теней ::ng-deep (устарели >>> и /deep/) для создания селекторов, которые пересекают границы компонентов, такие как

:host ::ng-deep .ng-invalid {
  border-bottom: solid 3px red;
}

который стилизует все теги с классом ng-invalid в текущем компоненте или любого потомка с красным подчеркиванием, независимо от того, является ли инкапсуляция None или Emulated. От поддержки браузера зависит, работает ли /deep/ с Native (насколько я знаю, это больше не поддерживается ни одним браузером).

Примечание

CSS-комбинаторы с пирсингом в тени похожи на те, что в спецификации DOM теней, где они давно устарели.

В по умолчанию ViewEncapsulation.Emulated используются собственные реализации Angulars /deep/ и ::shadow, которые будут работать даже тогда, когда Chrome удаляет встроенную поддержку.

В ViewEncapsulation.Native Angular использует CSS-комбинаторы Chromes shadow DOM (в любом случае, только Chrome их поддерживал AFAIK). Если Chrome окончательно удалит их, то они не будут работать и в Angular (опять же только ViewEncapsulation.Native).

Глобальные стили

Стили, добавленные глобально (index.html), не учитывают границы компонентов. Такие стили не переписаны Angular2 и ViewEncapsulation.Emulated к ним не относится. Только если задано ViewEncapsulation.Native и в браузере есть встроенная поддержка теневого DOM, глобальные стили не могут кровоточить.

Смотрите также эту связанную проблему https://github.com/angular/angular/issues/5390

Ответ 2

Прежде всего. styles/styleUrls следует использовать только для любых правил CSS, которые непосредственно влияют на стиль элемента из вашего шаблона.

Причина, по которой ваш external.css не получает применения к вашему компоненту, заключается в том, что при загрузке этих правил в external.css из styleUrls или styles при компиляции angular2 будет добавлен уникальный идентификатор компонента как селектор атрибуции к вашим первоначальным селекторам.

Например, в вашем external.css, если есть правило вроде div.container { /*some rules*/ }, оно станет div.container[_ngcontent-cds-2] { /*some rules*/ }. Поэтому независимо от того, насколько сильно ваша попытка заставить ваши правила стать приоритетными правилами, например. добавьте тег !important, он не будет работать - все селекторы в вашем external.css были ограничены на один уровень до селектора атрибутов, только элемент компонента несет один и тот же атрибут. Вот как angular2 ограничивает стили только текущим компонентом.

Конечно, всегда есть обходное решение.

Вот мое решение. Я добавлю службу внешних ресурсов для всех js script, она будет использовать SystemJS для загрузки AMD или Globally, для всех файлов css, будет использоваться простой javascript для создания элемента <link> и добавления его в элемент <head>.

Вот фрагмент моего кода для вас:

loadCSS(url) {
  // Create link
  let link = document.createElement('link');
  link.href = url;
  link.rel = 'stylesheet';
  link.type = 'text/css';
  
  let head = document.getElementsByTagName('head')[0];
  let links = head.getElementsByTagName('link');
  let style = head.getElementsByTagName('style')[0];
  
  // Check if the same style sheet has been loaded already.
  let isLoaded = false;  
  for (var i = 0; i < links.length; i++) {
    var node = links[i];
    if (node.href.indexOf(link.href) > -1) {
      isLoaded = true;
    }
  }
  if (isLoaded) return;
  head.insertBefore(link, style);
}

Ответ 3

Это может быть поздно, надеюсь, это поможет кому-то еще. Чтобы использовать ViewEncapsulation, просто используйте  import { ViewEncapsulation } from '@angular/core';

Ответ 4

Улучшенный подход уже размещен здесь: fooobar.com/questions/12312/...

Вам нужно добавить это только в декларацию вашего компонента:

@Component({
    ...
    encapsulation: ViewEncapsulation.None,
})

Как указано в документации angular: https://angular.io/guide/component-styles

Надеюсь, что это поможет.

Ответ 5

Здесь много сложных ответов, но я всегда обнаруживал, что если я хочу создать какой-то стиль, который влияет на более чем один компонент, то это, по сути, глобальный стиль, поэтому я добавляю его в styles.css. Этот файл CSS является особенным, поскольку он не использует инкапсуляцию стиля, поэтому влияет на каждый компонент.

Это концептуально мне кажется нормальным, просто вы должны использовать это экономно, иначе styles.css становится слишком большим.

Богатый