How to set background image for Angular component? - css

In my angular app I would like to set a background image for a specific view.
To this end, I added the following to the css-file of a component:
body {
background-image: url("../../../assets/images/backgroundImage.jpg");
}
However, the background doesn't change.
This the the file path of the file containing the css-code shown above:
angular-app/src/app/users/profile/profile.component.css
... and this is the file path of the background-image:
angular-app/src/assets/images/backgroundImage.jpg
I also tried
body {
background-image: url("assets/images/backgroundImage.jpg");
}
... but this resulted in a warning during compilation and didn't work either.
What am I doing wrong?
I gave the root element class "root" and then put the following into the css-file:
.root {
background-image: url("../../../assets/images/backgroundImage.jpg");
}
... now the background changes but not for the whole vertical length of the screen (the lower part remains white):

According to Angular, The styles specified in #Component metadata apply only within the template of that component.
you can use a hack like this
In your styless.css file add this
.selector {
background-image: url("../../../assets/images/backgroundImage.jpg");
}
now in your component you can do this
ngOnInit() {
document.body.className = "selector";
}
ngOnDestroy(){
document.body.className="";
}
But this is highly not recommended, i dont know what your code looks like, but there must be another way.
Scale your component to fit whole view-port
set the background on your component
I will work on a plunker and link to this file as an edit when done

I will add another answer for this because its totaly different from my previous answer
in your component import ViewEncapsulation from angular/core
import { ..., ViewEncapsulation } from '#angular/core';
In your #component metatag add encapsulation: ViewEncapsulation.None,
#Component({
...
encapsulation: ViewEncapsulation.None,
...
})
This has a side effect though, all styles in your component will be available to all other components once it loads.
You can check more about it on the Angular page

You probably need to either create a service or use ngrx to communicate between the child component and app.component to switch the style of the app.component.html using ngClass.

Related

NextJS: Modify third-party component CSS in different pages

With third-party components, the way to include their styles is by importing their stylesheet into _app.tsx or importing the stylesheet into your component that uses the third-party component, as described here: https://nextjs.org/docs/basic-features/built-in-css-support#import-styles-from-node_modules or by adding to next.config.js like so:
// next.config.js
const withTM = require("next-transpile-modules")([
"#fullcalendar/common",
"#fullcalendar/daygrid",
"#fullcalendar/timegrid",
"#fullcalendar/interaction",
"#fullcalendar/react",
"#fullcalendar/list",
To modify the third-party stylesheet, you need to create your own stylesheet and add it to _app.tsx; those modifications might look like this:
// styles/modified-fullcalendar.scss
.fc-col-header {
width: 100% !important;
}
Another option, at least for my use case (Full Calendar) is to use CSS variables as described here in technique 2 on this page: https://fullcalendar.io/docs/css-customization. There was a lengthy thread about this on the Full Calendar issues page, as seen here: https://github.com/fullcalendar/fullcalendar/issues/5393
The problem with all of these methods of customization is that they're global, and so anywhere you use this third-party component it'll look the same. However, in my case, I want to use the component on two different pages, with different styling modifications. With most frameworks, I would simply import the relevant modified stylesheet wherever I needed it, but NextJS doesn't allow that. How can I achieve the modifications I want?
The solution is to wrap the component in a div with a specific class name, then do the css overrides in a nested format for each use case in the override file.
Explanation:
Say your third-party component is FullCalendar. It's being imported and used in the files Foo.tsx and Bar.tsx. In Foo, let's say you want the calendar cells to be green.
To make the modification, you create the file modified-fc.scss and do the following:
// modified-fc.scss
.fc-cell {
background: green !important;
}
You then import modified-fc.scss into _app.tsx in order to apply the styles globally, and you're done. However, this prevents you from changing the cell color to orange in Bar. To circumvent this, just wrap the component:
// Foo.tsx
<div className=".wrapper1">
<FullCalendar/>
</div>
// Bar.tsx
<div className=".wrapper2">
<FullCalendar/>
</div>
and then nest the classes:
// modified-fc.scss
.wrapper1 {
.fc-cell {
background: green !important;
}
}
.wrapper2 {
.fc-cell {
background: orange !important;
}
}
OR
.wrapper1 > .fc-cell {
background: green !important;
}
.wrapper2 > .fc-cell {
background: orange !important;
}

Angular: How to add global CSS (e.g. to the body), but only for one specific page?

How can I add separate CSS for one page in Angular?
This is the CSS I need, as per How to remove the URL from the printing page?:
#media print{
#page{
margin:0;
}
body{
margin:30px;
}
}
But putting CSS into the component with ::ng-deep or ViewEncapsulation.None won't help here, because when navigating away from a page, the CSS of the page isn't deleted.
I've added a Stackblitz, which explains the problem clearly.
I've come up with a potential solution, but it doesn't work:
encapsulation: ViewEncapsulation.None
...
constructor(private renderer: Renderer2) {
this.renderer.addClass(document.body, 'special-print');
}
ngOnDestroy() {
this.renderer.removeClass(document.body, 'special-print');
}
....
....
....
#media print{
#page{
margin:0;
}
body.special-print{
margin:30px;
}
}
Why it doesn't work:
While it would help with <body> CSS, it won't help with #page CSS. Perhaps the question would be better summarized as "How to add global CSS, but remove it when we leave the page?".
Solved!
We print the <style> block directly into the component's HTML, and therefore when the component gets removed, our <style> block gets removed too. (Normally this wouldn't work, but thanks to DomSanitizer.bypassSecurityTrustHtml, Angular won't break our code when running optimizations.)
Here's a StackBlitz.
First, create a new component to handle the work:
component.ts: (This is all we need. We don't need an HTML or style.css file.)
//Inside your local component, place this HTML
//<app-local-css [style]="'body{background:green !important;}'"></app-local-css>
// OR
//<app-local-css [scriptURL]="'/path/to/file.css'"></app-local-css>
#Component({
selector: "app-local-css",
template: '<span style="display:none" [innerHTML]="this.safeString"></span>'
})
export class LocalCSSComponent implements OnInit {
constructor(protected sanitizer: DomSanitizer) {}
#Input() scriptURL?: string;
#Input() style?: string;
safeString: SafeHtml;
ngOnInit() {
if (this.scriptURL) {
let string = '<link rel="stylesheet" type="text/css" href="' + this.scriptURL + '">';
this.safeString = this.sanitizer.bypassSecurityTrustHtml(string);
} else if (this.style) {
let string = '<style type="text/css">' + this.style + "</style>";
this.safeString = this.sanitizer.bypassSecurityTrustHtml(string);
}
}
}
And then use it like this:
mySample.component.html:
<app-local-css [style]="'body{background:green !important;}'"></app-local-css>
// OR
<app-local-css [scriptURL]="'/path/to/file.css'"></app-local-css>
Angular is doing client-side rendering, which is bad news, because you do not have separate pages. You have several possible solutions though:
1. Separate page
You can create another page with or without Angular, which includes the CSS you need and load that page. In the most simplistic approach to achieve this, the other page would have a different URL. If having a different URL is not to your liking, then you could hide your page's content and show the other page inside an iframe. It would admittedly be a hacky solution, but it is a solution.
2. Client-side CSS rendering
Instead of just loading the CSS, you could have a component which would control global CSS rules, matched by your view's name. You would have a template value rendered to a property, like:
#media print{
#page{
margin:0;
}
body{
margin:30px;
}
}
And when you visit the page where this needs to be activated, you would simply initialize a property with a style HTML element that was generated based on the template and added to head. Once you leave the given view, your component would detect that event and would remove() that element. If you choose this solution, then it would be wise to make sure that you are supporting this on more general terms, so that if some new views will have their custom global CSS, then they would be easy to integrate into your project in the future.
3. body classes
You could add/remove some custom-print or whatever class to/from body whenever the style is to be changed. This way you could add the CSS exactly once to your HTML and change the rules accordingly, like:
body.custom-print {
margin: 30px;
}
This would be a neat solution, but the problem in your case is that you have a #page rule as well and I'm not sure how you could make that dependant on body classes or some other HTML attributes. I would conduct quite a few experiments about this if I were you.
4. Iframe staging
You could avoid having that CSS in your main page, but would have a hidden iframe where you would have the CSS and would just copy the content into the CSS and once that's loaded, print that.
Don't change the whole body from apple. Instead, there are a few changes to make.
In the app component, hold a boolean for whether or not you are on apple, and use ngClass for class defined in scss.
Track which route you are on in appComponent, and set isApple accordingly
Add a div around all your html, for container to take full size
Add global html, body setting height to 100% so you see color everywhere
Remove body overriding in apple
so,
appComponent.ts:
isApple: Boolean;
constructor(router: Router) {
router.events.subscribe(v => {
if (v instanceof NavigationEnd) {
this.isApple = v.url === "/apple";
}
});
}
appComponent.html:
<div [ngClass]="{'red':isApple}" class="container">
<p>
There are two components: Apple and Banana. Switching between them will show
the problem.
</p>
<router-outlet></router-outlet>
</div>
appComponent.scss
.red {
background-color: red;
}
.container {
height: 100%;
}
apple.component.scss (remove body)
/*Sample "global" CSS, that affects something outside the current component.*/
::ng-deep {
#media print {
#page {
margin: 0;
}
}
}
styles.scss (global)
html, body {
height: 100%;
}
You can see this altogether at this Stackblitz link
You can add different css files in the component (for instance, app-task.component.ts):
#Component({
selector: 'app-task',
templateUrl: './app-task.component.html',
styleUrls: ['./app-task.component.scss', './styles2.scss', './styles3.scss']
})
In this example, the style files are in the same folder that the component, but this is not the best option: you have to put the files in assets, for example. Also, be careful with the thread of the styles, since the first one you put will be put before the second (obviously).

Angular 6, how to configure CSS settings to create a persisting background color on all components?

I'm trying to create a background color that will persist on all of the components in my Angular app.
When I target html background: blue in the styles.css (global style sheet) this works if I change the encapsulation on the app.component.ts to ViewEncapsulation.Native, however it covers every component in the app. Meaning the color is on top of every other component.
I just want to set a background color that that will be behind all components in the app and persist.
I had the same problem and fixed with this. I do not know if is the best approach, try to put into the body tag in index.html:
<body class=".." style="background:#E8EBEE;">
Go to your Style.css or Style.scss file and add this code:
body {
background: #EEE //Your Background Color that will be shown between all components even if the component fails to load.
}
Import Renderer2 as follow:
import { Component, OnInit, Renderer2 } from
'#angular/core';
And If you want to add a custom background when a component being use, you will have to go to your component.ts File and add this code to the constructor:
constructor(private renderer: Renderer2) {
this.renderer.setStyle(document.body, 'background',
'#FFF');
}
That code will apply a background color to the body only when this component is loaded.

Applying CSS stylesheet only to active component

I'm working on a ReactJS app that has a header at the top, a menu on the left, and the "frame" in the middle is where routes and their corresponding components are loaded. I want to be able to apply a CSS stylesheet to specific components only when they are loaded. I also don't want them applied all the time or to the top header or left menu.
My expectation was that adding import 'custom.css'; to a specific component would only apply the stylesheet's styles to that component and it's children when the route is active. Instead, it applies it to the entire page even when the route/component are not loaded.
I understand that an alternative approach is styled components, but, for my use-case, a design company is supplying a stylesheet (which should remain unchanged) that we need to consume only for the sub-module I'm working on and I don't want its styles to affect the rest of the app.
How can I have a stylesheet only applied to my active route/component?
Use simple CSS technique. Suppose you have two components with different css files (say about.css and contact.css). Now consider your both CSS file have one common class with different style properties, like:
about.css
.container{
max-width: 400px;
}
contact.css
.container{
max-width: 500px;
}
Yes in ReactJS both the CSS files will load at the same time and will override any one of the style. so to solve this problem add class to differentiate this styles, like:
about.css
.about-component.container{
max-width: 400px;
}
contact.css
.contact-component.container{
max-width: 500px;
}
If you want apply only when the component is mounted, you can use the lifecycle.
The follow example is based in the idea you are using sass, React, sass-node and have the loaders into webpack.
<pre>
import React from 'react';
import './styles.scss';
class MyComponent {
constructor(props) {
super(props);
this.state = { className: '' }
}
componentDidMount() {
this.setState({
className: 'myOwnClass'
});
}
render(){
return (
<div className={this.state.className}>This is a example</div>
);
}
}
export default myComponent;
</pre>
To be able to only call that specific CSS when you need it you can use CSS Modules. You may need to update your version of react.
When saving your CSS file save it with a ".module.css" eg. "styles.module.css". The CSS in these files can only be used and accessed by hte components where are they are imported. As stated in a tutorial from W3Schools.
Let's say this is your CSS code in styles.module.css:
.container {
color: white;
}
.cont-child {
background-color: red;
}
Then in your JS file you can import the CSS file like this if the JS and CSS files are in the same directory. Make sure you point to the correct path.
import styles from './styles.module.css'
Then in your HTML section you can use it like this:
class Home extends React.Component {
render() {
return(
<main className={ styles.container } >
<div className={ styles["cont-child"]} >
Some div text about something...
</div>
</main>
);
}
}
I currently use both ways to access the selectors, since the styles variable acts like an object. I placed both of them here because the second option is capable of fetching selectors named like "btn-active". Which comes in handy in some situations. Camelcasing is considered cleaner though.
Please note: I originally posted this answer as a reply to a similar question here React CSS - how to apply CSS to specific pages only
I want to be able to apply a CSS stylesheet to specific components
only when they are loaded.
Why not apply the styles inline via React.js?
Step 1. Create the style object for the component:
var componentOneStyle = {
color: 'white',
backgroundColor: 'red'
};
Step 2. Populate the component's style attribute with the style object:
ReactDOM.render(<div style={componentOneStyle}>This is Component One</div>, mountNode);

How to make React CSS import component-scoped?

I have several components which have the following CSS/component structure
About/style.css
.AboutContainer {
# Some style
}
p > code {
# Some style
}
And I import the CSS in the componet as follows
About/index.js
import './style.css';
export default class About extends Component {
render() {
# Return some component
}
}
However, the CSS is imported in the <header> section and stays global-scope.
I was expecting CSS to be:
Component-scoped in a way that the style is only applied to things that are only rendered within this component.
Style for this component would disappear if the component is unmounted.
However, when inspecting from the browser, the styles are specified at the <header> section and gets applied to all the components
<header>
// Stuff
<style type="text/css">style for component About</style>
<style type="text/css">style for component B</style>
<style type="text/css">style for component C</style>
// Stuff
</header>
How do I import CSS to be component-scoped? It seems like I'm understanding CSS import in React ES6 incorrectly.
I was following this tutorial
Edit
Answer by Brett is correct. However, my problem turns out to be somewhere else. I created my app using create-react-app which basically simplifies setups required to do React. It include WebPack, Babel and other things to get started. The default WebPack config that it uses did not set module option for the css-loader so it defaulted to false, and as a result the local-scoping was not enabled.
Just for additional info, it seems like create-react-app does not have straightforward way to customize WebPack config, but there seem to be numerous how-to workarounds on the web.
It sounds like CSS Modules, or many of the other CSS-in-JS packages, does what you want. Others include Emotion (my current favorite), Styled Components, or many of the packages here.
A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. All URLs (url(...)) and #imports are in module request format (./xxx and ../xxx means relative, xxx and xxx/yyy means in modules folder, i. e. in node_modules).
Here's a quick example:
Let's say we have a React component like:
import React from 'react';
import styles from './styles/button.css';
class Button extends React.Component {
render() {
return (
<button className={styles.button}>
Click Me
</button>
);
}
}
export default Button;
and some CSS in ./styles/button.css of:
.button {
border-radius: 3px;
background-color: green;
color: white;
}
After CSS Modules performs it's magic the generated CSS will be something like:
.button_3GjDE {
border-radius: 3px;
background-color: green;
color: white;
}
where the _3DjDE is a randomly generated hash - giving the CSS class a unique name.
An Alternative
A simpler alternative would be to avoid using generic selectors (like p, code, etc) and adopt a class-based naming convention for components and elements. Even a convention like BEM would help in preventing the conflicts you're encountering.
Applying this to your example, you might go with:
.aboutContainer {
# Some style
}
.aboutContainer__code {
# Some style
}
Essentially all elements you need to style would receive a unique classname.
Maybe react-scoped-css will help. Btw, I'm the author of this lib, if you find anything broken or simply want to improve it, you can always raise an issue or send a pr.
Because you mentioned you used create-react-app, the solution here is quite easy change just style.css to style.module.css, it will look like this:
import styles from "./style.module.css"
<button className={styles.button}>blabla</button>
More info on this article:
https://blog.bitsrc.io/how-to-use-sass-and-css-modules-with-create-react-app-83fa8b805e5e
You can use SASS (.scss) to imitate scoped CSS.
Say you need to use bootstrap in only one component (to avoid conflicts). Wrap the component in <div className='use-bootstrap'> and then created a .scss file like so:
.use-bootstrap {
// Paste bootstrap.min.css here
}
Use this file naming convention [name].module.css
and see documentation: https://create-react-app.dev/docs/adding-a-sass-stylesheet
JSX File
import React from 'react';
import styles from './index.module.scss';
const MyPage = () => {
return (
<div className={styles}>
<h1>My Page</h1>
</div>
);
};
export default MyPage;
Styles File
h1 {
color: #f3f3f3;
font-family: "Cambria";
font-weight: normal;
font-size: 2rem;
}
For me, the simple solution (without using: Css-modules or css-in-js) is to add a suffix to your class selectors like this:
className="btn__suffix"
if your component is named: FileUpload.tsx so your __suffix would be __fu, i took the first character of each word (here: File and Upload).
the end result would be:
import './style.css';
export default class About extends Component {
render() {
Return (
<div className="container__fu">
...
</div>
)
}
}
And in the Css part, your file would be:
.container__fu {
...
}
I created a rollup plugin to have scoped scss/css within a vite react project with regular import, you can check it out if it can solve your issue!
https://www.npmjs.com/package/rollup-plugin-react-scoped-css

Resources