Change global css in react-router based on routes? - css

There's a global css class I want to override (.ant-content), but I want to do it per route, I've tried importing css files which override .ant-content per react-component that gets loaded up in various routes but they only end up loading their css even when not rendering (probably because the imports happen regardless if a component is loaded).

Assuming you have a class like this somewhere which you want to override:
.ant-content{
color: red
}
you could try using the specifity ordering rules of CSS to override this. So, for example if in one of your routes you have a component you want to overwrite which looks like this
<div className='override'>
<Component className='ant-content/>
</div>
Then in the CSS you import into that component you could use:
.override .ant-content{
color: blue
}
This should override the original .ant-content class as it is more 'specific' than the original class declaration.
You can read more about specifity here: https://www.w3schools.com/css/css_specificity.asp

Related

TailwindCSS 3 classes doesn't override previous classes

I am facing an issue which is mind-numbing in the world of CSS.
TailwindCSS 3 classes just doesn't override previous classes.
For example, there is this component, I created:
import * as React from "react";
const TextBox = ({ addClassName, children }) => {
const className = `text-xl leading-7.5 font-lato font-normal ${addClassName}`;
return <div className={className}>{children}</div>;
};
export default TextBox;
Then I go ahead and use this component above at another place, like this:
<TextBox addClassName="text-4xl">My New Text</TextBox>
Now when I inspect it in the browser, it shows both of the font-size:
Screenshot from the browser inspect
class="text-xl leading-7.5 font-lato font-normal text-4xl"
As you can see both of the classes are there, both referring to font-size, and the larger one is after the smaller one.
And still ONLY the small ( the original ) font-size will be the dominant.
( as a side note, I did try to put the addClassName variable in the front as well, no help )
Why is this?
I appreciate any help getting with this.
Thank you
I found the answer from dev.to.
The reasons your code didn't work are:
It turns out that the space-separated CSS class list that the class HTML attribute accepts is not treated as a list when calculating CSS rules precedence by the browser. The class attribute actually contains the set of classes the element has, so the order doesn't matter.
As the order that the classes appear in the class attribute doesn't matter, the rule that comes later in the CSS stylesheets wins.
Moreover, it wasn't warranted that the 'text-4xl' was defined after the 'text-xl' in the CSS stylesheet.
So to solve this problem, I recommended using tailwind-merge to override previous classes.
Tailwind-merge is a utility function to efficiently merge Tailwind CSS classes in JS without style conflicts.
One of its features was: Last conflicting class wins
twMerge('p-5 p-2 p-4') // → 'p-4'
Quoting from redit
In CSS if you have two selectors with equal specificity the one that comes last in the CSS structure takes precedence. The order in the class attribute has no effect.
Suggested solution would be to write your own class after tailwindcss import statement, or edit it using inline style.
My personal tip: Don't use two classes that target the same css property, text-lg and text-4xg both target font-size, you need a way (suggest clsx lib) to put only one class name and not the other
import clsx from 'clsx';
let condition = false;
function Component(){
return (
<div>
<p className={clsx({
"text-lg": condition,
"text-4xl": !condition,
})}>
...
</p>
</div>
);
}
I have had the same problem, and didn't want to add yet another dependency and increase my app's bundle size to solve something that doesn't have to be this hard. So I looked into the tailwind docs and found this:
Use the components layer for any more complicated classes you want to
add to your project that you’d still like to be able to override with
utility classes.
#tailwind base;
#tailwind components;
#tailwind utilities;
#layer components {
.card {
background-color: theme('colors.white');
border-radius: theme('borderRadius.lg');
padding: theme('spacing.6');
box-shadow: theme('boxShadow.xl');
}
/* ... */
}
By defining component classes in the components layer, you can still
use utility classes to override them when necessary:
<!-- Will look like a card, but with square corners -->
<div class="card rounded-none">
<!-- ... -->
</div>
Though this means you will have to write a component class every time you want to override an element with predefined classes.
https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes
I would suggest you to try clsx or clsssnames for better usage with tailwind classes instead of string interpolation
I found a Solution guys.
Setup props with default CSS values at the original component, and then at the time of the usage of this aforementioned component, if we need different style, we just gave that in the props.

Make Angular component stylesheet work with sub-components

I'm relatively new to Angular, and I have a doubt about component stylesheets.
I have an Angular 12 app and created a component named my-component. The template of the component in question is something like this:
my-component.html
<div>
...some html...
<some-other-angular-component></some-other-angular-component>
...some other html...
</div>
some-other-angular-component is another component, either from the app itself or a third party library.
Now, what I want to do in my-component is apply some CSS rules to the contents of some-other-angular-component. I know that the HTML it generates contains classes that I can target, so I tried to add this to my component CSS:
my-component.scss
.some-other-angular-component-inner-class {
background-color: red;
}
However, this doesn't work, it appears that the component's CSS file only applies rules to the HTML defined directly in the component's template, not the HTML generated by sub-components.
Is there a way to make this work? I find myself having to add my CSS to the webapp's main style.scss file, even when I want to apply the rule only to the particular some-other-angular-component instance inside of my-component. It makes styling confusing and needlessly fragmented. Is this intended, or what am I missing?
I think you may want to look into View Encapsulation.
#Component({
selector: 'app-no-encapsulation',
template: `
<h2>None</h2>
<div class="none-message">No encapsulation</div>
`,
styles: ['h2, .none-message { color: red; }'],
encapsulation: ViewEncapsulation.None,
})
export class NoEncapsulationComponent { }
These styles will be added to head and will be applicable to other components as well if style rule matches.
Please note, with this you are only enabling this behaviour for just this component. Chances of overlapping CSS rules is still there but is lot less in comparison to directly putting styles in style.css.
I will also suggest that you add .class or #id attribute in mark up to ensure that your rules don't overlap by default.
For example:
.my-component .rule-one {
}
It will ensure that my rules are only applied are on component that has this class applied on it.

React js css stylesheet applied to more than one component

I have a Parent.js component with a child component Child.js inside of it.
Parent.js imports parents.css
Child.js imports child.css
If I define this in child.css:
.example {
font-family: 'Roboto', sans-serif;
}
How come I'm able to use this className in the Parent.js component as well despite not specifying it in the parent.css?
Unless you use unique class names, CSS Modules or some other alternatives available for scoping CSS styles to any component in React, styles specified in any CSS file will be applied globally.
If you want to limit styles to any component, use CSS Modules or make sure every class name is unique in your project.
For details on how to use CSS Modules, see Adding a CSS Modules Stylesheet. You can also look at 9 Ways To Implement CSS in React JS for other available alternatives.
I recommend using unique class names. For example, lets say you have multiple ListView components: MemberUsersListView, AdminUsersListView, TestUsersListView; and each of them needs to be styled differently. I would create the following CSS classes:
.MUListView{
...
}
.AUListView{
...
}
.TUListView{
...
}
I know this seem's annoying, but it's cleaner than applying inline styles and easier to implement on smaller projects.

How to use environment variables in ReactJS imported CSS?

I created a simple React app using https://github.com/facebookincubator/create-react-app.
I am trying to specify a configurable URL to a component's CSS like this:
.Cell {
background-image: url({process.env.REACT_APP_STATIC_URL}./someImage.png);
}
And here's the component:
import React from 'react';
import './Cell.css'
class Cell extends React.Component {
render() {
return (
<div className="Cell">
{this.props.name}
</div>
);
}
}
But it doesn't look like the process variable trickles down to the imported CSS. How would I go about doing this?
If you want to use js variables in CSS, try React inline-style instead of plain css file.
https://facebook.github.io/react/tips/inline-styles.html
If you want to separate CSS and JS, you might need a CSS preprocessor to manage your global variables.
I came across one such scenario, The method I used is instead of adding it as background in CSS, make an img element and assign the path as src in component itself. I don't think there is any other way of doing that.
Commenting on this as I've recently had a similar issue. This should work to send an image file as a CSS variable in a build.
use the style prop to invoke a CSS style
Use template literal around the url() value
use the Javascript require() to refer to the file in the final build pack. Using a relative url requires that you call the image relative to where the the page will be called instead of being relative to the component JS file.
In the React component, use the inline style prop to set the CSS variable:
<div
style={{"--img":`url( ${require("../../images/coding.jpg")})`}}>
</div>
in the CSS file:
background-image: var(--img);

Overriding the encapsulated CSS of external component

I was wondering how to override the encapsulated CSS of an external component.
So I am using material2 in my project and the tabs component has a the attribute overflow set on tab-body. Is it possible to override the overflow value?
You can use the special css /deep/ instruction. See the documentation
So, if you have
app
sub-component
target-component
<div class="target-class">...</div>
You can put in your apps css (or less):
/deep/ .target-class {
width: 20px;
background: #ff0000;
}
Obviously, you can put this css fragment in sub-component as well.
From this article
Although the style of a component is well isolated, it can still be easily overridden if necessary. For that, we just need to add an attribute to the body of the page:
<body override>
<app></app>
</body>
The name of the attribute can be anything. No value is needed and the name override makes it apparent what its being used for. To override component styles, we can then do the following:
[override] hello-world h1 {
color:red;
}
Where override is the attribute, hello-world is the target component, and h1 is whatever you are trying to restyle. (get this right or it wont work).
Your component hello-world would be
selector: 'hello-world',
styles: [`
h1 {
color: blue;
}
`],
template: ` <h1>Hello world</h1> `
I think this is the most elegant way.
Alternatively if you are building a library of some sort, you can reset the styling altogether by doing something fancy in your css like:
:host-context(.custom-styles) {
//.. css here will only apply when there is a css class custom-styles in any parent elem
}
So then to use your component you'd use
<hello-world class="custom-styles">
But this is way less convenient than the first option.
::ng-deep .tag-or-css-class-you-want-to-override {
/* Add your custom css property value. */
}
The syntax ::ng-deep is used to override outside css class or tags without using ViewEncapsulation.None.
I see variations of this question a lot and since this is the top question on the subject I want to give the simplest answer. ng-deep and similar functionality is deprecated, so it's best to just rely on vanilla CSS.
Simply create a CSS selector with a higher specificity.
Most people (including myself) get hung up trying to do that because they don't understand two things:
Angular View Encapsulation
CSS Specificity
Angular View Encapsulation
View Encapsulation ensures CSS within a component only affects that component. To affect other components, you need some global CSS. You can do this by using a global style file like styles.css or by disabling View Encapsulation on a component.
#Component({
...
encapsulation: ViewEncapsulation.None
})
CSS Specificity
When two selectors select the same element, the CSS that actually gets applied is based on specificity: https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
You can increase specificity by simply adding more elements to your CSS selector. For example p.className is more specific than just .className. If you're lazy, you can just repeat a class name to increase specificity. .className.className is more specific than .className.
So to override any CSS in an Angular project, go into styles.css and repeat the class selector until your CSS has a higher specificity than the original.
.className.className.className {
color: red;
}
Didn't work? Add another .className.
Just check the class that is being applied to the tabs by the external component (use Inspector or any other tool). In your style css file, add the same name of the class for the tabs and set the overflow property along with adding !important to it to make sure it overwrites the previous one. Also make sure your css link to the page is added after the external component css link if any.
Hope this helps.
::ng-deep .css-class-you-want-to-override{
/*your custom css property value. like below */
background: white !important;
}

Resources