Change style of pseudo elements in angular2 - css

Is it possible to change style of pseudo elements using [style] or [ngStyle] in angular2?
in order to get a blur effect on a div acts like an overlay, and I should set up background-image on pseudo element.
I tried something like
<div class="blur" [style.before.backgroundImage]="'url('+ featuredImage[i] + ' )'">
it didn't work. I also tried this
<div class="blur" [ngStyle]="'{:before{ background-image:url('+ featuredImage[i] + ' )}}'">

You can achieve what you need with CSS variables.
In your style sheet you can set the background image like this:
.featured-image:after { content: '';
background-image: var(--featured-image);
}
After that you can programmatically set this variable on the same element or higher up in the DOM tree:
<div class="featured-image" [ngStyle]="{'--featured-image': featuredImage}">
More about CSS variables here: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables Note that the browser support is not complete yet.
Also note that you will need to sanitize the url/style using sanitizer.bypassSecurityTrustResourceUrl(path) or sanitizer.bypassSecurityTrustStyle('--featured-image:url(' + path + ')')):

No it's not possible. It is actually not an Angular issue: pseudo elements are not part of DOM tree, and because of that do not expose any DOM API that can be used to interact with them.
Usual approach if you want to deal with pseudo elements programmatically is indirect: you add/remove/change class and in CSS make this class affect corresponding pseudo-element. So in your case you could have one more class that changes necessary style:
.blur:before {/* some styles */}
.blur.background:before {/* set background */}
Now all you need to do is to toggle .background class on the element when you need before pseudo-element to get a background. You can use NgClass, for example.

if you want to add other properties I did it like this:
<div class="progress" [style]= "'--porcentaje-width:' + widthh " ></div>
and the css:
.progress::after {
content: '';
width: var(--porcentaje-width);
}
this worked for me :)

With current versions of Angular 2+ you can use CSS Variables to achieve this as well as sanitizing your input.
In your style sheet define the rule using CSS Variables. A fallback can also be defined as CSS Variables aren't supported by IE.
https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties
.featured-image:after {
content: '';
// Fallback for IE
background-image: url('fallback-img.png');
background-image: var(--featured-image);
}
Rather than bypassing security trust style, you can also sanitize your input with a reusable pipe:
https://angular.io/api/platform-browser/DomSanitizer#sanitize
import {Pipe, PipeTransform, SecurityContext} from '#angular/core';
import {DomSanitizer, SafeStyle} from '#angular/platform-browser';
#Pipe({
name: 'safeStyle',
})
export class SafeStylePipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) {}
transform(value: string): SafeStyle {
if (!value) return '';
return this.sanitizer.sanitize(SecurityContext.STYLE, value);
}
}
In your template:
<div class="featured-image" [style.--featured-image]="featuredImage[i] | safeStyle"></div>

Related

Prefix css selectors for make styles from API safe

Let's assume that the user can add styles for every component in admin panel and I get it as string in my Node server:
const stylesFromAPI = ".p { color: red } .bg { background: lime }";
How to prefix this styles before append to my document to avoid conflicts?
I need something like CSS modules but working with strings (not as module loader):
const stylesFromAPI = css(".p { color: red } .bg { background: lime }"); // returns hashedClassname685946898456
<SomeCompontent className={stylesFromAPI} />
produces:
<style>
.hashedClassname685946898456 .p { color: red }
.hashedClassname685946898456 .bg { background: lime }
</style>
<div class="hashedClassname685946898456"></div>
Shadow DOM seems like a reasonable option here. You can create your style tags with inside the shadow DOM without having to deal with any selector prefixes. For example, using the react-shadow package:
import root from 'react-shadow';
Then in JSX, something like:
<root.div>
<style type="text/css">
{/* CSS string here */}
</style>
<div>
{/* Stuff here */}
</div>
</root.div>
Check out a working example of this here: https://github.com/joshdavenport/stack-overflow-61566764-react-css-shadow-dom
The main downside here is your styles from outside the shadow DOM will not apply. Those using the shadow DOM for components see this as a good thing, those simply trying to scope CSS do not. Not sure what it is you're scoping, so I can't really tell if that would be an issue for you.
If it is, you could re-import your styles within the shadow DOM, though I can't really point out how to do that without knowing what bundler is in use and how it is in use.
Alternatively you could pull apart your imported CSS using the css package, iterate over the selectors prefixing all with a randomly generated class, and then re-stringify.

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 dynamically change css selector property value in react js code?

I need to dynamically change the color in the react component for specific selector.
In scss (use sass) i have the following rule:
foo.bar.var * {
color: blue;
}
I want to change it in react code, to be yellow, red or something else.
I cant use style property for element, cause i need the selector to
apply for all subchilds !=)
Is there any native ways? Or should i use Radium? Or is there any similar libs for this? Maybe css-next some hove can help with this?
I have color picker, i cant write class styles for every color =(
For some answerers NOTE:
So i have selector in some scss file, that imported in some root js file with .class * {color: $somecolor} and i need change the $somecolor in that selector, during picking colors in color picker
Maybe i can somehow set selector for all nested inside style property? or there is the way how to recursively apply css style for every nested items from the style prop?
What about
class MyComponent extends React.Component {
render() {
const yellow = true // Your condition
return(
<div className={`foo bar var ${yellow && 'yellow'}`}
My item
</div>
)
}
}
.foo.bar.var {
& * {
color: blue;
}
&.yellow * {
color: yellow;
}
}
You could define a custom CSS property (CSS variables) using the style attribute of the element and assign the value to a prop, state etc.
<div className='foo bar var' style={{ "--my-color": props.color }}></div>
The custom property would work for any selector that apply to that component or children. So you could use it like that:
foo.bar.var * {
color: var(--my-color);
}
See a snippet with similar code here
this may sound stupid . but does this work ?
import myCss from './mydesign.css';
myCss.foo.bar.var = "your color"

CSS Modules & ReactJS: Parent and child CSS classes in different components

So I am building a react application and have a quick question. If I have two separate components:
and
with CSS classes navigation.css and navigationLogo.css respectively. In navigation.css I have a class named .main and in navigationLogo.css I want to have a class like so:
.main .main_in_logo {
color: red;
}
But with CSS Modules I am unable to do this, any ideas on a work around?
I just feel that the explanations here are not complete enough. In css you do .parentSelector .childSelector in order to select the child. The same rule is for css modules, but in your html/jsx you should add to the parent and the child the relevant className -> styles.parentSelector , styles.childSelector.
<div className={styles.container}>text</div>
This way you can have in your css something like:
.banner .container{
background-color:reb;
}
.banner .container{
background-color:blue;
}
Sometimes you use libraries and you want to change something somewhere down the DOM inside the library and you can't change its source code. In this case you can use the :global like this:
.parentElement :global(div)
.parentElement :global(#some-lib-element-selector)
I was looking for the same problem and didn't find the solution here, maybe because the post is 3 years old. The accepted answer is, in my opinion but not mine only, not scalable.
I don't really know if this is something new, but I found out what I would do in vanilla CSS adapted to CSS modules.
Here is what I did and fully suits my needs:
/* parent.css */
.main {
...some CSS...
}
/* logo.css */
#value main from "./parent.css";
.logo {
...some CSS...
}
.main .logo {
color: red
}
Here, we are using #value, which is a CSS modules variable and allows us to bind with another file to build a selector including the final name of the parent "main".
As strange as it looks to me, it took some time to find out about this solution, I hope this will save some time and help other people!
Why you need to create .main .main_in_logo - the main idea of styles with parent elements its not to broke your css with other styles in the future. But its impossible with css modules, because your styles will be unique forever.
But even you really need it you can use global css for these 2 components - documentation about global css for react-css-modules.
The child component should not have a css rule that is dependent upon the parent css classname.
the child should just be:
.main_in_logo { color: red; }
If you need to define styles that involve both parent and child, then the easiest way is to define the styles completely in the parent:
/* navigation.css */
.main .main_in_logo {
color: red;
}
Then have the parent pass the css class to the child and tell the child to use it:
// Navigation.js
<NavigationLogo className={navigationCss.main_in_logo} />
// NavigationLogo.js
<div className={"foo " + this.props.className}>stuff</div>
You don't need to be specify which child class you are referring to when using CSS modules in ReactjS.
so doing:
.main_in_logo {
color: red;
}
will be enough in the stylesheet.
I ended up using CSS the normal way but with BEM convention.
I mean after all, what the CSS modules do is adding the [this_name].module.css to your css classes anyway. If you typed it correctly in the first place, there's no need of using this. It's just a new abstract that allow newbies so they can just do stuff without having to worry about class names clashing.
// Main.jsx
import './Main.css'
import Logo from './Logo.jsx'
const Main = () => {
return (
<div className="main">
<Logo className="main__logo" />
</div>
)
}
/* Main.css */
.main {/* do magic */}
.main__logo {/* do magic but for Logo component */}
So maybe you had Logo component like this..
// Logo.jsx
import './Logo.css'
const Logo = () => {
return (
<div className="logo">
<img className="logo__img" />
</div>
)
}
/* Logo.css */
.logo {/* do magic for logo */}
.logo__img {/* do magic for logo's image */}
This feels much more natural.

Apply stylesheet to half a page with shadow-dom?

Can I apply an external stylesheet to a specific div/element with shadow-dom or via any other means? I've heard about shadow-dom and I believe it lets you constrain your styles, but that's about all I know.
Specifically, I want half the page to use bootstrap, and the other half to use MUI or something else. This is just to show how my library works nicely with different themes.
I don't want to modify the CSS in anyway to constrain it to a specific element, nor do I want to use iframes.
Yes, you can apply an external stysheet in a Shadow DOM using the #import url CSS rule.
div.attachShadow( { mode: 'open' } )
.innerHTML = `
<style>
#import url( './external-style.css' )
</style>
<!-- other elements -->`
NB: The #import rule must placed at the top of the <style> element.
You can then manipulate the Shadow DOM like a normal DOM:
div.shadowRoot.appendChild( firstSection.cloneNode( true ) )
If your content is already existing in the normal DOM, you can move it with appendChild(), duplicate it with cloneNode() as in the above example), or reveal it with the help of <slot> element:
div1.attachShadow( { mode: 'open' } )
div1.shadowRoot.innerHTML = `
<style>
:host { display: inline ; background: #cfc ; }
::slotted( span ) { color: red ; }
</style>
<slot></slot>`
<div id=div1>
<span>Hello</span> world
</div>
In the last case you'll need to use the ::slotted pseudo-element to change the style of the original DOM, so maybe you'll have to modify already existing stylesheet. The best solution depends on your use case.

Resources