ng-deep not working when switching between components? - css

I have 2 components A B , in each component's css file I have a ngx-bootstrap datepicker which i need to customize ( align ).
In A component css file I have
::ng-deep .bs-datepicker {
margin-top:-100px
}
In B component css file I have
::ng-deep .bs-datepicker {
margin-top:-80px
}
When I go to component A and inspect element it shows A's css file, which is what i want,
But when go to component B and then come back to component A , It shows B's Css file in Component A, so it shows margin-top:80px in Component A.
How do I segregate styling between these two components without one affecting the other when i switch from one component to other?

You can wrap the bs-datepicker in a container and use it name to capture
::ng-deep .container-one * .bs-datepicker {
margin-top:-100px
}
::ng-deep .container-two * .bs-datepicker {
margin-top:-80px
}
and in HTML files:
<div class="container-one">
<input type="text" bsDatePicker>
</div>
<div class="container-two">
<input type="text" bsDatePicker>
</div>
Those will have different styling
I also recommend stopping using ::ng-deep to prevent unexpected behaviours (just like you had in this situation).
The approach above will also work on styles.scss file without the ::ng-deep with the correct angular.json configuration

Related

How to lower mat-icon with input in angular material?

This is my code:
<mat-form-field>
<input type="tel" matInput placeholder="Home">
<mat-icon matSuffix svgIcon="home" class="mdi-icon"></mat-icon>
</mat-form-field>
And this is the result:
As it is seen icon is to high and I want to lower it to decrease the distance between the bottom line and the icon. I tried:
.mdi-icon {
margin-bottom: -5px;
}
But it didn't help. Could anyone say how to do it?
For the CSS to have any effect on a child component you first need to first get around view encapsulation. View encapsulation will add a unique attribute to all of your HTML elements within the template, something like _ngcontent-nvb-c74="", then it will append that identifier to all of your CSS like [_ngcontent-nvb-c74]. That is how the CSS of one component does not affect others.
We need to make the CSS global. So, we need to use a unique selector or else your CSS will leak into other components. I would use the component name personally. I'm using app-my as an example selector for the component MyComponent. So in all three cases your CSS will look like:
app-my .mdi-icon {
...
}
Your options to get around View Encapsulation are:
1. Disable View Encapsulation for the component - not usually recommended
#Component({
...
encapsulation: ViewEncapsulation.None,
})
export class MyComponent {}
This makes all of the CSS in that component global, not great if you want view encapsulation in other areas of your component.
2. Put your CSS in styles.css
Any CSS in this file is global by default.
3. Create a new global style file for this component
Something like my.component.global.css
After creating this file you need to add it to the styles array in angular.json. Any CSS files in this array are applied globally, styles.css is the only one by default.
angular.json
"styles": [
"src/styles.scss",
"src/app/my.component.global.css"
],
If you're using scss, you can import this file into styles.scss instead of adding it to the styles array.
Now for actually moving the icon, I'm just using the non-svg icon but it should work the same
<mat-form-field>
<input type="tel" matInput placeholder="Home" />
<mat-icon class="mdi-icon">home</mat-icon>
</mat-form-field>
I removed matSuffix
app-my .mdi-icon {
position: absolute;
right: 0;
top: 5px;
}
In some cases you will be overriding other css already present in the child, to do that, you may need to increase the specificity by repeating a class (not necessary in this case)
app-my .mdi-icon.mdi-icon.mdi-icon {
position: absolute;
right: 0;
top: 5px;
}

Target Angular binding with SCSS / CSS

I am migrating an application from AngularJS to Angular. I have just moved a loading-indicator component to Angular, and that has an optional modal binding to say whether its a modal loader or not.
In reality this doesnt bind to anything right now, it simply matches a CSS rule.
HTML
<loading-indicator [modal]="true"></loading-indicator>
SCSS
loading-indicator {
&[modal="true"] {
background: rgba(255,255,255,0.5);
}
}
The SCSS above targets an attribute of modal not [modal].
How do I target [modal]? I saw some answers suggesting I can escape the brackets using \\ e.g. &\\[[modal\\]] but this didn't seem to work.
You cannot. Because [modal]="true" for Angular it's an input and this will be converted to another HTML attribute.
You can use modal=true in your component and you can select this with
[modal=true] {
/*styles*/
}
But for encapsulation, you need to put this style on the root styles of the app.
It's a better solution to bind the input modal value to a [ngClass]="":
Inside the component ts loading-indicator:
#Input() modal;
On the template use:
<div [ngClass]="modal ? 'modal-background' : ''"></div>
On the styles of component:
.modal-background{
background: rgba(255,255,255,0.5);
}

How to load different .css files on different components of a react application?

I have two .jsx files that represent their respective components.
The first one is, Blog.jsx
import React from "react";
import '../assets/css/blog.css';
export const Blog = () => (
<div>
<h1>Hello Blog</h1>
</div>
)
With its respective CSS file, blog.css
div { background: #ff481f; }
and the second one is, Landing.jsx
import React from "react";
import '../assets/css/landing.css'
export const Landing = () => (
<div>
<h1>Hello Landing</h1>
</div>
)
With its respective CSS file, landing.css
div { background: #86ff2b; }
I have added routing and called instances of those two components on the App.js file which is the default file of a React application. After running the application, when navigated to components, I faced a problem that the background color is the same for both of the components (It loads landing.css only and never changes).
How can I fix that problem that each component only uses its respective .css file and loads it?
By default webpack and other build tools will compile all CSS files into one, even if css was imported in separate JSX files. So you can't use different CSS files and expect you don't affect on another part of page.
You have some options:
Use BEM for naming class names.
Use cssModules. In this case elements will have their own css class name and styles will not affect any other elements except if you use :global selector.
css-module
Using html tags as css selectors is a bad practice (because there is the behaviour you describe).
You should use only css classes or inline styles (using id's is another bad practise, id's have high priority).
div {
width: 20px;
height: 20px;
}
#id {
background: red;
}
.class {
background: green;
}
<div id="id" class="class"></div>
In case using css classes there is the same problem (when you have two similar classes). And this case is decided using css modules (set of rules of building) or you can use css-in-js (external library) which has its pros and cons. Also you can use BEM (methodology) and if your application is not big you can avoid this trouble.
css modules will add to your classes random hash and instead .my-awesome-class-name you will get .my-awesome-class-name-dew3sadf32s.
So, if you have two classes .class in the first file and .class in the second file in the end you will get two classes .class-dew23s2 and .class-dg22sf and you styles will resolve as expected.
css-in-js is a similar way except you should write your styles using javascript with some profits like including only those styles that are needed at the moment (what you are looking for right now) and several others.
You can code using pure css / scss / postcss / etc but many companies already choose between css modules and css-in-js.
BEM is just naming conventions for your class names.
And lastly - if you use inline-styles using react you should remember:
{} is constructor of object and {} returns new object on every call, it's mean if you write something like:
class MyAwesomeComponent extends Component {
render() {
return <div style={{color: "red"}}></div>;
}
}
or
class MyAwesomeComponent extends Component {
render() {
const divStyles = {color: "red"};
return <div style={divStyles}></div>;
}
}
div will re-render every time your render will call because div takes new prop.
Instead, you should define your styles (for example) in outside of your class:
const divStyles = {color: "red"};
class MyAwesomeComponent extends Component {
render() {
return <div style={divStyles}></div>;
}
}
Don't define your css using HTML tags because it will affect your entire application.
use className,id or inline styling.
like- App.css
.myApp{ color: red;}
#myApp2{ color: blue;}
App.js
import './App.css'
<div className="myApp">color changed by className</div>
<div id="myApp2">color changed by id</div>
<div style={{color:'red'}}>color changed by inline object styling</div> // inline styling
This is not the best solution if you are looking forward to improve yours css imports/loads.
However could be the best solution if you dont want to go in deep in css, resolve the problem fast and keep working with HTML tag.
You can add a div for each component, define an Id for the div and wrap the component. Afterwards in the component's css fies you are going to define all the styles starting with the #id so all the css classe or HTML tag will affect just the corresponding component.
//App render in root
ReactDOM.render(
<App />,
document.getElementById('root')
);
//App
function App(props){
return [
<Blog />, <OtherComponent />
]
}
//Blog component
function Blog(props){
return <div id="blog">
<h1>I am Blog</h1>
</div>
}
//Other component
function OtherComponent(props){
return <div id="otherComponent">
<h1>Im am other component</h1>
</div>
}
/* blog.css*/
#blog h1{
color:yellow;
}
/* otherComponent.css*/
#otherComponent h1{
color:green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

TailwindCSS focus + placeholder in CSS file

Is it possible to move the class focus:placeholder-gray-600 from the HTML into a CSS file?
From the following HTML
<input class="focus:placeholder-gray-600" type="text">
And I'd like to have
<input class="my-class" type="text">
#styles.css
.my-class {
...
}
Yes you can do that with tailwind css, but not with just css files.
You would need to process your css files with PostCSS and then follow the steps outlined in the documentation under Extracting CSS components with #apply
The basic idea is, to use the tailwind-provided #apply postcss directive:
<style>
.my-class:focus {
#apply placeholder-gray-600;
}
</style>
Note, that the focus aspect has to be used like in "regular" css with the pseudo selector in the class declaration instead of doing this:
/** INVALID **/
.my-class {
#apply focus:placeholder-gray-600;
}
See also this note from the docs:
Note that variants like hover:, focus:, and {screen}: can't be applied directly, so instead apply the plain version of the utility to the appropriate pseudo-selector or media query.

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);

Resources