I was wondering what is the best way to style AngularDart components? I'd like to be able to split base styles into a separate CSS file and then just include it somehow (maybe #import, if angular dart supports it) in my component.
Standard NgComponent allows me to add only once CSS file, as in the following example:
#NgComponent(
selector: 'rating',
templateUrl: 'packages/angular_dart_demo/rating/rating_component.html',
cssUrl: 'packages/angular_dart_demo/rating/rating_component.css',
publishAs: 'ctrl',
map: const {
'max-rating': '#maxRating',
'rating': '<=>rating'
})
What if my CSS is somehow split across multiple files, how do I include all of them in a component?
At the moment, I'm starting to notice that although AngularDart components help with making components reusable, they are not the most maintainable - there's lots of copy paste in CSS. If it was possible to split the styles the components would be a lot more maintainable (i.e. One can include base styles in multiple components - instead of copy-pasting them across every css file for each component).
What is the best way to structure components and css within AngularDart environment?
The attribute cssUrl and applyAuhtorStyles can both be applied at the same time, as shown below. As you can see, in addition to inheriting the parent styles (bootstrap for example), you can also add component specific styles (cssUrl) that are only available in the component scope.
#NgComponent(
selector: 'paginate',
templateUrl: 'component/paginate/paginate_component.html',
cssUrl: 'component/paginate/paginate_component.css',
applyAuthorStyles: true,
publishAs: 'ctrl',
map: const {
'page-filter-map' : '<=>pageFilterMap'
}
)
There are also directives that can be used called cssStyle to add even more control, also shown below.
<span ng-style="{color:'red'}">Sample Text</span>
Ok, here's the answer. To get a css into a component you can either use
#import in your css
cssUrls parameter -
https://github.com/angular/angular.dart/pull/315
If you look here:
https://github.com/angular/angular.dart.tutorial/tree/master/Chapter_04/lib/rating
In the .dart file of the component there is an annotation that contains the attribute cssUrl. I am not sure but I think this couples the file to the encapsulating Web Component css.
#NgComponent(
selector: 'rating',
templateUrl: 'packages/angular_dart_demo/rating/rating_component.html',
cssUrl: 'packages/angular_dart_demo/rating/rating_component.css',
publishAs: 'ctrl',
map: const {
'max-rating' : '#maxRating',
'rating' : '<=>rating'
}
)
Note that in order for this packages/ link to work you need to have your files in the /lib folder.
Related
We've two options to keep styles in an Angular 9 app; global styles in styles.css or individual component level styles in the component css file.
If looked at the project from performance perspective;
what should be the preferred way?
Should we keep all styles in a single global style.css file or keep each component related styles in their component.css file?
To answer this question we have to refer to the Angular official doc.
By using Using component styles you will have a better modular design.
Angular can bundle component styles with components, enabling a more
modular design than regular stylesheets.
But, if there are some styles that are common between more than one component it's better to have a shared css and e.g. if you use pre-processor such as .SCSS, LESS, SASS, ..., you can have some _var.scss to define general styles such as base color, fonts, ... and then #import in other component styles or just register global style files in the styles section which, by default, is pre-configured with the global styles.css file.
So, using component styles provide scoping restriction and View encapsulation for your app. This scoping restriction is a styling modularity feature:
You can use the CSS class names and selectors that make the most sense
in the context of each component.
Class names and selectors are local to the component and don't collide with classes and selectors used elsewhere in the application.
Changes to styles elsewhere in the
application don't affect the component's styles.
You 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.
You can
change or remove component CSS code without searching through the
whole application to find where else the code is used.
There are several ways to add Global (Application wide styles) styles to the Angular application. The styles can be added inline, imported in index.html or added via angular-cli.json. The angular allow us to add the component specific styles in individual components, which will override the global styles.
I don't think there is much (if any at all) significant difference in performance. The global or component style distinction is all about the scope of those styles and maintainability of your codebase. Generally its good idea to keep everything in components as they are scoped to themselves and will not accidentally override other same styles from anywhere else. And global styles should stay mostly to theming, utility, helpers etc.
Besides you have an option to make component style global as well, if for some reason you need to do that.
step to define/preferable way for global style
Create _base.scss file in the css folder (first create css folder).
import other helping scss file in _base.scss file
add the entry of _base scss file in style.scss file (style.scss available when we create the folder).
Even if your component stylesheet will be applied in isolation to its component only (e.g. while using the default ViewEncapsulation.Emulated) the class names you will use on your template will still clash with any existent global styling, so you cannot really use more than one single class namespace.
This can lead to always prefixing class names, which in turn can result in very long, weird name groups.
Is there any best practice out there to keep your class names brief and clean (ideally 1-word) without any risk of clashing with any global styling that might be in place?
Real use case example: I can't use class="row" while styling a component-wide custom logical row if I am using bootstrap.
Look at this StackBlitz. I want the header of my a component to be fixed-width and bordered only, but it ends up to also have a red background because of global styling.
Yes. I can use a different word, but I should always be aware of the entire word set that is currently used by global styling, not to mention that I don't know whether more global styles will be added in the future, especially in large applications.
Changing your view encapsulation to native will make Angular use native shadow DOM and avoid the clash of the global style
#Component({
selector: 'app-a',
templateUrl: './a.component.html',
styleUrls: ['./a.component.css'],
encapsulation: ViewEncapsulation.Native
})
The Angular documentation for :host does not mention that we can style all host elements at once. I have added this CSS at a “global” level:
:host {
width: 100%;
}
but there was no effect. However, this works fine in the CSS at the component level:
:host(app-search) {
width: 100%;
}
where app-search is a component, app-search.component.ts.
Is is possible to write a :host selector for all components or must this be declared multiple times at the component level?
By its very definition (or specification), :host can never be used at a global level. It is created to use from component level and to select the parent component (which is called shadow host) from the children (which is called shadow tree).
For more clarification, Angular's :host selector is a special selectors from the world of shadow DOM style scoping (described in the CSS Scoping Module Level 1 page on the W3C site).
The angular documentation clearly specifies that you should use this selector to select the parent component from within the child component. But it may seem unclear to you if you don't have any idea how shadow tree works. see the documentation.
If you need to style any component from a global stylesheet, there is a style.css file automatically added at a global scope in Angular. Just put your CSS in that file and you can find it available globally in all components.
Component level CSS files make your CSS modular. This is a great feature because:
You can use the CSS class names and selectors that make the most
sense in the context of each component.
Class names and selectors are local to the component and don't collide with classes and selectors
used elsewhere in the application.
Changes to styles elsewhere in the
application don't affect the component's styles.
You 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.
You
can change or remove component CSS code without searching through the
whole application to find where else the code is used.
Although it is configurable, I strongly recommend not to use ViewEncapsulation.None. It will make kill all your CSS modularity which you can avail easily using global CSS files without affecting the scoping restriction.
In your app-search.component.ts file, you could set:
encapsulation: ViewEncapsulation.None
like this
#Component({
templateUrl: 'app-search.component.html',
styleUrls: ['app-search.component.css'],
encapsulation: ViewEncapsulation.None
})
This prevents you from having to rewrite styles and enables styles on a global level.
You could also try applying the styles directly into the index.html file. These styles will also be global, preventing you from rewriting styles at the component level.
Angular cli automatically loads css files those are in node_module directory. I am using #swimlane/ngx-dnd and it has css style. But I want to use bootstrap styles for my components. What's standard way for doing this ?
Appreciate any idea and helps.
In your app.component.ts, add:
#Componenent({
encapsulation:ViewEncapsulation.None,
styleUrls:[''], // Add your bootstrap css files
templateUrl: ....
})
If you want to override a package's styles, you can just provide overrides in your own stylesheet or component stylesheet with the same or more specific style definition. Your definition will need to match their style, but must be loaded after their style and/or be more specific so that your style applies correctly.
If you want to exclude their style sheets you will need to use some sort of plugin for webpack to Ignore the css files in the package directory.
I'd recommend the first approach.
If the package you are using creates dynamic markup along with the styling, you may need to change your component encapsulation so that the component you are using can successfully apply your styles to the generated dom elements.
I've got some CSS rules in my Angular 2 app that would be common across various components. Obviously I don't want to copy&paste them into each component's styles. I currently have 2 ideas:
Place common CSS rules in a static CSS file and include it using a link in my index.html's head section.
Place my common CSS rules in one or more files and include them in #Component decorator for each component, e.g.
styleUrls: [ './myComponentStyle.css', '../common/common.css']
First approach look not-so-angular-ish to me, but at the same it's sure to work and simple to implement.
Second one requires some work to be done with each component, but allows more control about what styles are being used by one. It also lets me to organize my common styles into smaller stylesheets and use only ones that are needed.
Do you favor any of those solutions or is there a third, better one? :)
1. This solutions is good, but it's more suitable for any common styles, which should be available for all components. For example, styles for css grids.
To make it more angularish you could set encapsulation for you app component to none:
`#Component({
selector: 'my-app',
template: ` `,
styleUrls: ["shared.style.css"],
encapsulation: ViewEncapsulation.None
}) export class App {}`
Demo could be found here (plunker)
Note: Styles, included by this ways (just adding style tag, or with non encapsulation) will affect all elements on your pages. Sometimes it is want we really want (agreement to use any css framework for hole project). But if just want to share styles between few component - it would be probably not the best way.
Summary:
(+) easy to use
(-) no encapsulation
2. I like this solution, because it is very understandable and has predictable behavior. But there is one problem with it:
It will add style tag with your shared styles every time you use it.
It could be a problem if you have big style file, or many element which are using it.
#Component({
selector: 'first',
template: `<h2> <ng-content> </ng-content> </h2>`,
styleUrls: ["shared.style.css"]
})
export class FirstComponent {}
Demo could be found here (plunker)
Summary:
(+) easy to use
(+) encapsulation
(-) duplicates styles for every usage
3. There is one more option you could use.
Just create one more component which will provide shared styles for it's children.
` <styles-container>
<first> first comp </first>
</styles-container>
<styles-container>
<second> second comp </second>
</styles-container>`
In those case you will have to use /deep/ in your styles to make style available for child components:
:host /deep/ h2 {
color: red;
}
I also worth to be mentioned not to forget use :host to make styles available only for child elements. If you omit it you will get one more global style.
Demo could be found here (plunker)
Summary:
(-) you have to create container and it in templates
(+) encapsulation
(+) no duplicated styles
Notes: Encapsulation of styles is really cool feature. But you also should remember that there no way to limit your deep styles. So if you applied deep styles, it would available absolutely to all children, so use it careful too.
There are 3 ways to use styling in angular2 app (link).
You have mentioned two of those that allows you to reuse styles.
My personal opinion is that for any large application its preferable to go with #2 mainly due to the view encapsulation provided by angular.
#1 can be used for the really very generic styles that are common to all parts of your application. But if you will take into account that the root in your SPA will be angular component anyway - there is no real need to go with another approach of linking styles than #2.
Moreover by working with css in two different ways you will have to remember this (and handle with some extra code) when for example bundling your app and using tools like gulp-inline-ng2-template
For future readers, I think this solution is best.
Let's assume you have 2 components(products and customers), and have common styles to be shared.
1.Create one more component
//customer-products-styles.component.ts
#Component({
selector: "app-customer-products-styles",
template: "",
styleUrls: ["./customer-products-styles.component.scss"],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CustomerProductsStylesComponent {}
//customer-products-styles.component.scss
app-products,
app-customers {
p {
color: coral;
}
}
2.Use it like so
<!-- Customers Component (app-customers) -->
<app-customer-products-styles></app-customer-products-styles>
<p>
customers works!
</p>
<!-- Products Component (app-products) -->
<app-customer-products-styles></app-customer-products-styles>
<p>
products works!
</p>
Benefits
It is lazy-loaded, loads when module chunk is downloaded, initial
main.js is reduced
Adding component selectors (app-customers and
app-products) as a parent for styles make it component scope
No duplicate styles and only load once in the browser, whatever the component request it first
Some Additional points
Set encapsulation to none, but add component selector as parent in the style
I also changed default changeDetection to OnPush, there is no need but to be safe
Working Stackblitz