UNPKG

ngx-picture

Version:

An Angular library to properly size, lazy load images, and use next generation formats

295 lines (244 loc) 7.2 kB
# ngx-picture An Angular library to help properly size, lazy load images, and use next generation formats. Help improve app performance and fix common [Lighthouse](https://developers.google.com/web/tools/lighthouse) opportunities: - **Serve images in next-gen formats** - **Properly size images** - **Defer offscreen images** Ready made configurations available for: - [Cloudinary](https://cloudinary.com/) - [imagekit.io](https://imagekit.io/) - [GraphCMS](https://graphcms.com/) For live demos: - [Storybook](https://jaychase.github.io/ngx-picture) - [StackBlitz](https://stackblitz.com/edit/ngx-picture-blitz) - [npm](https://www.npmjs.com/package/ngx-picture) ## Install Angular 9+ ```bash npm i --save ngx-picture@latest ``` Angular < 9 ```bash npm i --save ngx-picture@2.0.4 ``` ## Configure Import **NgxPictureModule** into **app.module.ts** and call **forRoot** suppyling the config. ```typescript import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { DEFAULT_BREAKPOINTS, ImageFormat, NgxPictureModule } from 'ngx-picture'; import { AppComponent } from './app.component'; // 1: supply a function to create the srcset urls for each breakpoint export function srcInterpolator( url: string | undefined, imageFormat: ImageFormat, breakpoint: string, breakpointValue: number ) { return `${url?.split('.')[0]}-${breakpointValue}.${ imageFormat === 'jpeg' ? 'jpg' : 'webp' }`; } @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, , NgxPictureModule.forRoot({ breakpoints: DEFAULT_BREAKPOINTS, //2. the break points to create sources for imageFormats: ['webp', 'jpeg'], //3. the image formats to create sources for. * srcInterpolator }) ], providers: [], bootstrap: [AppComponent] }) export class AppModule {} ``` \* Image formats must be in order of precedence. In this example if **webp** s supported it will be used. ### Using the bundled configurations (Cloudinary, ImageKit and GraphCMS) ```typescript import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { NgxPictureModule, CLOUDINARY_CONFIG } from 'ngx-picture'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, NgxPictureModule.forRoot(CLOUDINARY_CONFIG)], providers: [], bootstrap: [AppComponent] }) export class AppModule {} ``` ## Using the ngx-picture component ```html <ngx-picture src="assets/images/banner.jpg" alt="test" [lazyLoad]="true" ></ngx-picture> ``` If **lazyLoad** is true the component will use an [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) (if it is supported by the browser) to only render the picture element if the component is in view. \*Remember to import the **NgxPictureModule** into the relevant module. ## Advanced configuration ### Changing the breakpoint value type and srcInterpolator **NgxPictureConfig** is generic so you can change the brreakpoint values to anything required in the **srcInterPolator** function. This example is using the [Angular CDK](https://material.angular.io/cdk/layout/overview) breakpoints for the breakpoint keys. ```typescript import { Breakpoints } from '@angular/cdk/layout'; export interface Dimensions { h: number; w: number; } const ngxPictureConfig: NgxPictureConfig<Dimensions> = { breakpoints: { [Breakpoints.XSmall]: { h: 10, w: 10 }, [Breakpoints.Medium]: { h: 100, w: 100 }, [Breakpoints.Large]: { h: 200, w: 200 } }, imageFormats: ['webp', 'jpg'], srcInterpolator: ( url: string, imageFormat: ImageFormat, breakpoint: string, breakpointValue: Dimensions ) => `${url}/w:${breakpointValue.w}/h:${breakpointValue.h}` }; export function srcInterpolator( url: string, imageFormat: ImageFormat, breakpoint: string, breakpointValue: number ) { return `${url.split('.')[0]}-${breakpointValue}.${ imageFormat === 'jpeg' ? 'jpg' : 'webp' }`; } @NgModule({ declarations: [AppComponent], imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), BrowserAnimationsModule, MatButtonModule, MatCardModule, MatListModule, NgxPictureModule.forRoot(ngxPictureConfig) ], providers: [], bootstrap: [AppComponent] }) export class AppModule {} ``` ### Changing the image template To use a custom img element provide an **ngTemplate** called **#imgTemplate**. ```html <ngx-picture src="assets/images/banner.jpg" alt="test" [lazyLoad]="true" #picture > <ng-template #imgTemplate let-imageData> <img class="custom-template" [src]="imageData.src" [alt]="imageData.alt" /> </ng-template> </ngx-picture> ``` The data context for the template is: ```typescript { src: string, alt: string } ``` ## Example of rendered element ```html <picture class="ngx-picture__picture"> <source srcset="assets/images/banner-300.webp" media="(max-width: 599.99px)" type="image/webp" /> <source srcset="assets/images/banner-600.webp" media="(min-width: 600px) and (max-width: 959.99px)" type="image/webp" /> <source srcset="assets/images/banner-960.webp" media="(min-width: 960px) and (max-width: 1279.99px)" type="image/webp" /> <source srcset="assets/images/banner-1280.webp" media="(min-width: 1280px) and (max-width: 1919.99px)" type="image/webp" /> <source srcset="assets/images/banner-1920.webp" media="(min-width: 1920px)" type="image/webp" /> <source srcset="assets/images/banner-300.jpg" media="(max-width: 599.99px)" type="image/jpeg" /> <source srcset="assets/images/banner-600.jpg" media="(min-width: 600px) and (max-width: 959.99px)" type="image/jpeg" /> <source srcset="assets/images/banner-960.jpg" media="(min-width: 960px) and (max-width: 1279.99px)" type="image/jpeg" /> <source srcset="assets/images/banner-1280.jpg" media="(min-width: 1280px) and (max-width: 1919.99px)" type="image/jpeg" /> <source srcset="assets/images/banner-1920.jpg" media="(min-width: 1920px)" type="image/jpeg" /> <img class="ngx-picture__picture__img" src="assets/images/banner.jpg" alt="test" loading="lazy" /> </picture> ``` ## Styling The **picture** element in the component has the class **ngx-picture\_\_picture** and the img element has the class **ngx-picture**picture**img**. ```scss .your-picture-class { .ngx-picture__picture { width: 100%; .ngx-picture__picture__img { width: 100%; } } } ``` ## More To clone this repo and run it locally. ```bash git clone https://github.com/JayChase/ngx-picture.git cd ngx-picture npm i npm run build ``` ### Demo ```bash ng s ``` ### Storybook ```bash npm run storybook ```