31

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] + ' )}}'">
Murhaf Sousli
  • 12,622
  • 20
  • 119
  • 185

4 Answers4

46

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 + ')')):

Léa Gris
  • 17,497
  • 4
  • 32
  • 41
sqwk
  • 2,649
  • 1
  • 28
  • 42
  • I get the image source from http response, so I can't set the background from my stylesheet – Murhaf Sousli Jun 19 '16 at 12:00
  • 12
    `[attr.style]="sanitizer.bypassSecurityTrustStyle('--custom:' + value)"` helped me – slowkot Jul 31 '17 at 14:38
  • there is a nice package called: https://github.com/lironbob/ngx-css-variables, which is very handy when attempting this trick – rivanov Dec 11 '18 at 04:27
  • @sqwk, you are a life saver! it works on Chrome browser! But this has to be followed: https://stackoverflow.com/questions/49903552/control-css-variable-from-angular-5
    in conjuction to you answer.
    – Artanis Zeratul May 28 '19 at 02:52
  • for multiple variables [style.--myFirstVar]="'25%'" [style.--mySecondVar]="'35px'" – WantToDo Aug 18 '22 at 18:26
30

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.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
dfsq
  • 191,768
  • 25
  • 236
  • 258
  • 1
    I need to set the `background-image` dynamically for a list of posts, so it won't work this way, instead I will set `div.blur`background and inherit it in `:before`, thank you for the answer. – Murhaf Sousli Feb 08 '16 at 23:45
  • You can't set style of pseudo-element with javascript. So in this case you can go with real element and set background of it instead. Just pretend it's pseudo. – dfsq Feb 09 '16 at 07:34
12

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

Josué Aparicio
  • 131
  • 1
  • 2
4

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>
RudyO
  • 41
  • 3