react-contentful-image

Allows specifying of image dimensions for contentful images depending on media query and and pixel density.

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
react-contentful-image
1.3.24 years ago5 years agoMinified + gzip package size for react-contentful-image in KB

Readme

React Contentful Image
The Contentful Images API allows for the manipulation (resizing, cropping, compressing) of assets returned from the Contentful Delivery API.
This component allows you to specify, for a particular image, an image size per media query, and it will return a <picture> element or background-image CSS (depending on the function used). The <picture> element (React element or static markup) or background-image CSS are responsive and will display a manipulated image per media query based on the image sizes specified.
import { getStaticPictureElement } from 'react-contentful-image';

const attrs = {
  src: '//contentful.com/test.jpg',
};

const sizes = [
  {
    mediaQuery: 'default',
    params: { w: 500, h: 500 },
  },
];

const pictureElement = getStaticPictureMarkup(attrs, sizes);

console.log(pictureElement);
/*
<picture>
 <source type="image/webp" srcSet="https://contentful.com/test.jpg?fit=fill&fm=webp&h=500&q=85&w=500,
   https://contentful.com/test.jpg?fit=fill&fm=webp&h=1000&q=35&w=1000 2x,
   https://contentful.com/test.jpg?fit=fill&fm=webp&h=1500&q=25&w=1500 3x" />
 <source type="image/jpeg" srcSet="https://contentful.com/test.jpg?fit=fill&fl=progressive&fm=jpg&h=500&q=85&w=500,
   https://contentful.com/test.jpg?fit=fill&fl=progressive&fm=jpg&h=1000&q=35&w=1000 2x,
   https://contentful.com/test.jpg?fit=fill&fl=progressive&fm=jpg&h=1500&q=25&w=1500 3x" />
 <img src="https://contentful.com/test.jpg?fit=fill&fl=progressive&fm=jpg&h=500&q=85&w=500" class="react-contentful-image" />
</picture>
*/

Installation

npm install --save react-contentful-image
or
yarn add react-contentful-image

Setup

The module needs to be initialized using your own media queries and the quality levels you would like to use for each media query. To do this you can use the setup function. The best place to call this is somewhere close to where you bootstrap your application. E.g. in your base App component an a React app.
Params:
  • media - object of media queries. The 'default' media query does not need to be specified. It simply refers to 'no media query'. As a result it is the default match.
    variants - object of variations of media queries. Variants are media queries that are variations of a particular media query. E.g. media query 'sm' could be (min-width: 600px), but a dpr2 variant of media query 'sm' could be (min-width: 600px) and (min-resolution: 144dpi). Variants are useful for defining increased pixel resolutions.
  • options - an object of other internal options to override. Current options:
appendHTTPS - sets whether to append 'https:' to the url provided. This is because contentful returns image urls without a url scheme. E.g. //contentful.com/image.jpg. Defaults to true.

Media Queries Object

const screenXs = '360px';
const screenSm = '600px';
const screenMd = '960px';
const screenLg = '1280px';
const screenXl = '1920px';

const media = {
  xs: `(min-width: ${screenXs})`,
  sm: `(min-width: ${screenSm})`,
  md: `(min-width: ${screenMd})`,
  lg: `(min-width: ${screenLg})`,
  xl: `(min-width: ${screenXl})`,
  dpr2: '(min-resolution: 144dpi)', // 1.5x devices and up get 2x images
  dpr3: '(min-resolution: 240dpi)', // 2.5x devices and up get 3x images
  portrait: '(orientation: portrait)',
  landscape: '(orientation: landscape)',
};

// Object keys are media query names from above. 'default' means no media query (default match).
// E.g. for mobile first 'default' would be the mobile media query
const variants = {
  default: {
    quality: 85,
    density: 1,
  },
  dpr2: {
    quality: 35,
    density: 2,
  },
  dpr3: {
    quality: 25,
    density: 3,
  },
};
Note: It often helps to store these variables with your global styles and import them when settings up this module.

Call Setup

Once you have defined the media queries and variants above, you can supply them to the setup function.
import { setup as reactContentfulImageSetup } from 'react-contentful-image';

// Media query and variant setup or import from above
...

reactContentfulImageSetup(media, variants);

Defaults

There are some defaults that are set within the module that can be overridden when you call setup. The default media queries and variants are are:
// DPR: device pixel ratio
let mediaQueryConfig = {
  dpr2: '(min-resolution: 144dpi)', // 1.5x devices and up get 2x images
  dpr3: '(min-resolution: 240dpi)', // 2.5x devices and up get 3x images
  portrait: '(orientation: portrait)',
  landscape: '(orientation: landscape)',
};

let variantConfig = {
  default: {
    quality: 85,
    density: 1,
  },
  dpr2: {
    quality: 35,
    density: 2,
  },
  dpr3: {
    quality: 25,
    density: 3,
  },
};
These defaults will always be included as setup uses Object.assign to merge the defaults with your specified configuration. This is to cater for the default behaviours specified below. If you which to remove the defaults you must explicitly set them to null. E.g.:
const media = {
  sm: '(min-width: 600px)',
  dpr3: null,
};

const variantConfig = {
  default: {
    quality: 60,
    density: 1,
  },
  dpr3: null,
};

reactContentfulImageSetup(media, variants);
Will result in the internal variant config config looking like:
let mediaQueryConfig = {
  sm: '(min-width: 600px)',
  dpr2: '(min-resolution: 144dpi)', // 1.5x devices and up get 2x images
  portrait: '(orientation: portrait)',
  landscape: '(orientation: landscape)',
};

let variantConfig = {
  default: {
    quality: 60,
    density: 1,
  },
  dpr2: {
    quality: 35,
    density: 2,
  },
};
This behaviour can be removed in a future release if it is heavily disliked, but at present it makes logical sense based on the behaviours below.

Default Behaviours

This module is designed to be mobile first and therefore some default behaviours occur to help with that. These can be overridden when calling setup above.
  1. As the <picture> element is able to display images based on whether the browser that it is rendered within supports a particular image type, functions that return a <picture> element will automatically add 'webp' to the formats returned. This allows for increased image size savings for browsers that support WebP. This is especially true for images with a transparent background as WebP is lossy and supports an alpha channel unlike png which is lossless. As such it is often advantageous where possible to choose a <picture> element over a <div> with a background image.
  2. The 'default' media query (no media query match) will automatically use variants 'dpr2' and 'dpr3' if they have not been removed. This means that for mobile devices that don't match a media query, if using the background image CSS function with the config of:
const imageSizes = [
  {
    mediaQuery: 'default',
    params: { w: 500 },
  },
];
They will recive CSS something similar to the following:
.class {
  background-image: 'url(image.jpg?w=500)';
}

@media (min-resolution: 144dpi) {
  .class {
    background-image: 'url(image.jpg?w=1000)';
  }
}

@media (min-resolution: 240dpi) {
  .class {
    background-image: 'url(image.jpg?w=1500)';
  }
}

Sizes Configuration Array

To specify the image size you would like per media query, you supply the function you wish to use with a sizes configuration array. It looks like the following:
const imageSizes = [
  {
    mediaQuery: 'default',
    params: { w: 228 },
  },
  {
    mediaQuery: 'sm',
    params: { w: 600, h: 600 },
    variants: ['dpr2'],
  },
];
What this indicates, assuming the module has been set up using the media queries in the initial setup description above:
  1. For the 'default' no matching state, I would like the image to be 228 pixels in width and please shrink the height accordingly to maintain image's the aspect ratio.
  2. For the 'sm' media query, I would like the image to be 600 pixels in width and height. Please crop it to the aspect ratio of 600/600 using the best fit possible and then resize it to 600x600. I would also like a variant of this to be displayed on screens with a pixel resolution of 144dpi of 1200 pixels in width and height.

Options

  • mediaQuery: the media query to specify the size for. This can be either an alias to one of the media queries consumed during the module setup above, or an actual media query string e.g. (min-width: 600px). It also accepts an array of media query aliases or media query strings that will be concatenated with 'and'.
E.g. ['xs', '(max-width: 599px)'] would be concatenated to (min-width: 360px) and (max-width: 599px). E.g. ['xs', 'landscape'] would be concatenated to (min-width: 360px) and (orientation: landscape). The media query string syntax is purely to allow flexibility. It is recommended where possible to use the aliases supplied to the initial setup function.
* If only a width or height is specified, the image will be resized to the specified width or height, with its corresponding width/height resized to maintain the image's aspect ratio.
If both a width and a height are specified, the fit: 'fill' option is automatically set. This will crop the image to the aspect ratio of the width and height and then resize the image to the width and height specified.
  • variants: the variations of the media query to be rendered. This parameter rarely needs to be set due to the following default variants being set:
* The 'default' media query has variants 'dpr2' and 'dpr3' set by default to cater for mobile screen pixel densities.
* All other media query have variant 'dpr2' set automatically to cater for retina desktop displays.
  • url: override the main url supplied to the function that consumes this sizes array. Useful if you wish to use a different image for a particular media query.

React Component

To use the react component all you need is an image src url a sizes configuration array described above. All additional props (e.g. alt text, onload) are passed onto the image element within the picture element returned.
Props:
  • src - image source url
  • sizes - sizes configuration array

Assuming the module was initialized using the media queries near the start of the setup section:
import ReactContentfulImage from 'react-contentful-image';

const imageSizes = [
  {
    mediaQuery: 'default',
    params: { w: 228 },
  },
  {
    mediaQuery: 'sm',
    params: { w: 600 },
  },
];

<ReactContentfulImage src={imgSrc} sizes={imageSizes}/>

Static Markup String

A static markup string can also be generated. This was briefly shown in the very first example. It takes an array of attributes used for the element and a sizes configuration array.
Parameters
  • attrs - an array of html <img> attributes
  • sizes - sizes configuration array

Once again assuming the module was initialized using the media queries near the start of the setup section:
import { getStaticPictureElement } from 'react-contentful-image';

const attrs = {
  src: '//contentful.com/test.jpg',
};

const imageSizes = [
  {
    mediaQuery: 'default',
    params: { w: 228 },
  },
  {
    mediaQuery: 'sm',
    params: { w: 600 },
  },
];

const pictureElementString = getStaticPictureMarkup(attrs, imageSizes);

Background Image CSS

The module can also generate background image css with media queries. This CSS can then be added to an HTML element to give it a responsive background image. The function will return a CSS class that can be applied to an element to apply the styles. This uses the fantastic Emotion
library under the hood.
Parameters
  • imageUrl - contentful image asset url
  • sizes - sizes configuration array

import { getBackgroundImageCss } from 'react-contentful-image';

const imgUrl = '//contentful.com/test.jpg';

const imageSizes = [
  {
    mediaQuery: 'default',
    params: { w: 228 },
  },
  {
    mediaQuery: 'sm',
    params: { w: 600 },
  },
];

const bgImagesClass = getBackgroundImageCss(imgUrl, imageSizes);

// E.g. used within a React element
const Element = props => {
  return (
    <div className={bgImagesClass}></div>
  );
};