Angular Component styling – Using shadow piercing descendant selector

In this post, I am going to share how the shadow piercing descendant selector helped me with style scoping problem.

Well, I tried to create Angular wrapper for one of a JQuery plugin. All worked as planned and later I noticed that I was not able to apply custom styles to the plugin in ViewEncapsulation.Emulated mode. I can set the custom style when the ViewEncapsulation is set to None.

So I started to search for a solution to apply the custom style in ViewEncapsulation.Emulated mode.

What does ViewEncapsulation emulated mode actually do?

In ViewEncapsulation.Emulated mode, angular will try to emulate the style scoping feature of Shadow DOM. This is achieved by adding attribute to the element and style.

@Component({
    selector: 'my-app',
    template: `
<div>
<h2>Hello {{name}}</h2>
</div>
`,
    styles: [`h2 {
       color: red
    }`]
})
export class App {
   name:string;
   constructor() {
     this.name = `Angular! v${VERSION.full}`
   }
}

Extra attribute will be added to the template elements as follows.

b1

b2

Why component style is not applied to the JQuery plugin?

Inside the plugin the element creation is done by JQuery instead of Angular. So the attributes used to emulate style scoping is not added to the elements.

To illustrate this, check the below code example in which the dynamic h2 element is appended in the ngAfterViewInit lifecycle.


@Component({
    selector: 'my-app',
    template: `
<div>
<h2>Hello {{name}}</h2>
</div>
`,
    styles: [`::ng-deep h2 {
      color: red
    }`]
})
export class App {
     name:string; ele;
     constructor(eleRef: ElementRef) {
       this.name = `Angular! v${VERSION.full}`
       this.ele = eleRef;
     }
     ngAfterViewInit() {
       let dynam = document.createElement('h2');
       dynam.innerHTML = 'Dynamic content ' + this.name;
       this.ele.nativeElement.appendChild(dynam);
     }
}

The result will be as follow, you can see that the style from the component is not applied to the dynamically inserted h2 element.

out
Dynamic element insertion – style is not applied

Shadow piercing descendant selector to the rescue

To resolve the above depicted problem, you can use the shadow piercing descendant selector. It is a technique introduced in shadow DOM concept which is deprecated in major browsers.

But you can use this in Angular using the ::ng-deep special selector. This selector will apply the parent component styles to the descendant child components.

The encapsulation mode should be Emulated to use this feature in Angular

Now the component style should be modified as follows


::ng-deep h2 {
   color: red
}

The result will be as follows

oute
Dynamic element insertion – with ::ng-deep selector

Samplehttps://plnkr.co/edit/qb9m0qglyDNzmizQkC9d?p=preview

Reference

  1. https://angular.io/guide/component-styles#deprecated-deep–and-ng-deep
  2. https://angular.io/guide/component-styles#view-encapsulation
Advertisements

Height responsiveness using calc() CSS

I like to share a small use case of calc() CSS which helped me to achieve height responsiveness.

My use case is as follows

  1. A parent element with some static height.
  2. Three child elements (for reference let’s name them as c1, c2 and c3)which should fill the parent.
  3. Out of the three child elements, two of them(c1 & c3) will have static height and the c2 has to occupy the remaining space.
  4. And the c2 has to adjust its height on window resize without disturbing it’s siblings.

To achieve this, I need to calculate the height required by the c2, initially I tried the below solution to find the height.

  1. Calculate the sum of height of two child elements(c1 & c3).
  2. Calculate the height of parent element.
  3. Now height of the last child element calculated from the equation – height of parent – sum of height of c1 & c3 elements.
  4. Set the resultant height to the c2 child element.
  5. To auto adjust the height on window resize, register a resize callback and repeat the step 1 to 4.

Well, this method will work well but it could be done better.

How can it be done better?

Here comes the calc CSS. There are many usages available for calc CSS one of the them is unit mixing which is going to help me with this.

So my requirement will be achieved with the following steps.

  1. Calculate the sum of height of two child elements(c1 & c3).
  2. Now set the height to the c2 child element as height: calc(100% - height from step1).

That’s it. Now all the child elements will fit within its container whereas the c2 child will use the remaining space leave by c1 and c3.

Also it’s worth to note that this will allow the c2 element to adjust its height on window resize without using a resize event handler.

References

  1. MDN: calc CSS
  2. CSS Tricks: A couple of use cases for calc