
Detect Responsive Screen Sizes in Angular
Usually, we rely on CSS media queries for responsive design. But there are situations when CSS alone isn’t sufficient, and we need to detect screen size changes programmatically. Here’s how to detect responsive breakpoints in Angular efficiently, using Bootstrap CSS classes instead of hardcoding breakpoints in TypeScript.
The Approach
We’ll use Bootstrap’s predefined responsive visibility classes to detect the current screen size:
- Extra small (
xs
):.d-block .d-sm-none
- Small (
sm
):.d-none .d-sm-block .d-md-none
- Medium (
md
):.d-none .d-md-block .d-lg-none
- Large (
lg
):.d-none .d-lg-block .d-xl-none
- Extra large (
xl
):.d-none .d-xl-block
Each class toggles the element’s display
property between none
and block
. When the screen size changes, we detect which element is displayed.
Creating the Size Detector Component
Create an Angular component named size-detector.component
.
HTML Template:
<!-- size-detector.component.html -->
<div *ngFor="let s of sizes" class="{{s.css + ' ' + (prefix + s.id)}}">{{s.name}}</div>
TypeScript Component:
// size-detector.component.ts
import { Component, AfterViewInit, HostListener, ElementRef } from '@angular/core';
import { ResizeService } from './resize.service';
export enum SCREEN_SIZE {
XS,
SM,
MD,
LG,
XL
}
@Component({
selector: 'app-size-detector',
templateUrl: './size-detector.component.html'
})
export class SizeDetectorComponent implements AfterViewInit {
prefix = 'is-';
sizes = [
{ id: SCREEN_SIZE.XS, name: 'xs', css: 'd-block d-sm-none' },
{ id: SCREEN_SIZE.SM, name: 'sm', css: 'd-none d-sm-block d-md-none' },
{ id: SCREEN_SIZE.MD, name: 'md', css: 'd-none d-md-block d-lg-none' },
{ id: SCREEN_SIZE.LG, name: 'lg', css: 'd-none d-lg-block d-xl-none' },
{ id: SCREEN_SIZE.XL, name: 'xl', css: 'd-none d-xl-block' },
];
constructor(private elementRef: ElementRef, private resizeSvc: ResizeService) {}
@HostListener('window:resize', [])
private onResize() {
this.detectScreenSize();
}
ngAfterViewInit() {
this.detectScreenSize();
}
private detectScreenSize() {
const currentSize = this.sizes.find(x => {
const el = this.elementRef.nativeElement.querySelector(`.${this.prefix}${x.id}`);
return window.getComputedStyle(el).display !== 'none';
});
this.resizeSvc.onResize(currentSize.id);
}
}
Resize Service
Create a ResizeService
to broadcast screen size changes:
// resize.service.ts
import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
import { SCREEN_SIZE } from './size-detector.component';
@Injectable()
export class ResizeService {
private resizeSubject: Subject<SCREEN_SIZE> = new Subject();
get onResize$(): Observable<SCREEN_SIZE> {
return this.resizeSubject.asObservable().pipe(distinctUntilChanged());
}
onResize(size: SCREEN_SIZE) {
this.resizeSubject.next(size);
}
}
Using the Service in Other Components
Inject the ResizeService
into any component to react to screen size changes:
// hello.component.ts
import { Component } from '@angular/core';
import { ResizeService } from './resize.service';
import { SCREEN_SIZE } from './size-detector.component';
@Component({
selector: 'hello',
template: `<h1>Hello {{size}}!</h1>`,
})
export class HelloComponent {
size: SCREEN_SIZE;
constructor(private resizeSvc: ResizeService) {
this.resizeSvc.onResize$.subscribe(x => this.size = x);
}
}
Include Bootstrap
Include Bootstrap in your project via CDN in index.html
:
<!-- index.html -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
Summary
With this approach, Angular components become aware of responsive breakpoints without duplicating CSS media query logic in TypeScript.