Generate responsive HTML picture elements powered by on-the-fly Filestack image conversions.
You will need a Filestack developer account to use this library. Get a free one here.
If you're looking for a self-initializing Javascript solution please see the powerful lazysizes library.
It can integrate easily with Filestack conversions by using the RIAS plugin.
Install
npm install filestack-adaptive
The package.json
specifies three separate modules:
main
for the CommonJS modulemodule
for the ES Module (suitable for bundlers like Webpack and Rollup)browser
for the UMD module (usable in HTML script tags)
You can find a minified UMD module on the Filestack CDN here.
API Documentation
https://filestack.github.io/adaptive/
What can this do?
Adaptive at its core is a generator for objects representing the structure of HTML picture tags. These in turn can be consumed by different interpreters.
This library ships with a built-in virtual DOM adapter powered by hyperx, which allows you to simply call picture(handle, options, renderer)
, where renderer
can be any DOM builder supported by hyperx. If renderer
is not provided then picture
will default to returning plain DOM. For example it can support React components:
Browser (using umd):
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://static.filestackapi.com/adaptive/adaptive.min.js"></script>
<script>
const options = { alt: 'windsurfer', sizes: { fallback: '100vw' } };
const tree = fsAdaptive.picture('5aYkEQJSQCmYShsoCnZN', options, React.createElement);
ReactDOM.render(tree, document.body);
</script>
Browser (using bundler):
import react from 'react';
import reactDOM from 'react-dom';
import { picture } from 'filestack-adaptive';
const createElement = (Component, props, children) => {
return React.createElement(Component, props, ...children);
};
const options = { alt: 'windsurfer', sizes: { fallback: '100vw' } };
const tree = picture('5aYkEQJSQCmYShsoCnZN', options, createElement);
ReactDOM.render(tree, document.body);
Server:
import react from 'react';
import reactDOM from 'react-dom/server';
import { picture } from 'filestack-adaptive';
const toString = reactDOM.renderToString;
const createElement = (Component, props, children) => {
return React.createElement(Component, props, ...children);
};
const options = { alt: 'windsurfer', sizes: { fallback: '100vw' } };
const tree = picture('5aYkEQJSQCmYShsoCnZN', options, createElement);
console.log(toString(tree));
The attribute structure returned from makePictureTree
can be used in JSX directly, if for example you would prefer writing your own adapter (not using the picture
helper).
JSX:
import React, { Component } from 'react';
import { makePictureTree } from 'filestack-adaptive';
class Picture extends Component {
renderSources(sources) {
return sources.map((sourceObj) => {
return <source {...sourceObj} />;
});
}
renderImage(imageObj) {
return <img {...imageObj} />;
}
render() {
const tree = makePictureTree(this.props.handle, this.props);
return (
<picture>
{tree.sources && this.renderSources(tree.sources)}
{this.renderImage(tree.img)}
</picture>
);
}
}
export default Picture;
Usage
Most cases can be covered with the picture
function for generating plain DOM elements. Support for art direction (distinct/cropped images per media query) is not yet implemented.
import { picture } from 'filestack-adaptive';
const options = {
alt: 'windsurfer',
sizes: {
fallback: '60vw',
},
};
const el = picture('5aYkEQJSQCmYShsoCnZN', options);
document.body.appendChild(el);
This will generate a DOM node with the following structure:
<picture>
<img alt="windsurfer"
sizes="60vw"
src="https://cdn.filestackcontent.com/5aYkEQJSQCmYShsoCnZN"
srcset="https://cdn.filestackcontent.com/resize=width:180/5aYkEQJSQCmYShsoCnZN 180w,
https://cdn.filestackcontent.com/resize=width:360/5aYkEQJSQCmYShsoCnZN 360w,
https://cdn.filestackcontent.com/resize=width:540/5aYkEQJSQCmYShsoCnZN 540w,
https://cdn.filestackcontent.com/resize=width:720/5aYkEQJSQCmYShsoCnZN 720w,
https://cdn.filestackcontent.com/resize=width:900/5aYkEQJSQCmYShsoCnZN 900w,
https://cdn.filestackcontent.com/resize=width:1080/5aYkEQJSQCmYShsoCnZN 1080w,
https://cdn.filestackcontent.com/resize=width:1296/5aYkEQJSQCmYShsoCnZN 1296w,
https://cdn.filestackcontent.com/resize=width:1512/5aYkEQJSQCmYShsoCnZN 1512w,
https://cdn.filestackcontent.com/resize=width:1728/5aYkEQJSQCmYShsoCnZN 1728w,
https://cdn.filestackcontent.com/resize=width:1944/5aYkEQJSQCmYShsoCnZN 1944w,
https://cdn.filestackcontent.com/resize=width:2160/5aYkEQJSQCmYShsoCnZN 2160w,
https://cdn.filestackcontent.com/resize=width:2376/5aYkEQJSQCmYShsoCnZN 2376w,
https://cdn.filestackcontent.com/resize=width:2592/5aYkEQJSQCmYShsoCnZN 2592w,
https://cdn.filestackcontent.com/resize=width:2808/5aYkEQJSQCmYShsoCnZN 2808w,
https://cdn.filestackcontent.com/resize=width:3024/5aYkEQJSQCmYShsoCnZN 3024w">
</picture>
The srcset here is using a list of default resolutions that apply whenever sizes
is specified, but these can be overridden. The alt is not required but it is strongly recommended to comply
with the HTML5 + ARIA specification.
Browser support
Current state of picture support.
For unsupported browsers we recommend the picturefill polyfill.
Examples
Image width and pixel density
When the image width is known it will generate a srcset for HiDPI screens at 2x. More densities can be specified
by passing an array to the resolutions
option, e.g. resolutions: ['1x', '2x', '3x']
.
const options = {
alt: 'windsurfer',
width: '768px',
};
picture('5aYkEQJSQCmYShsoCnZN', options);
Output:
<picture>
<img src="https://cdn.filestackcontent.com/resize=width:768/5aYkEQJSQCmYShsoCnZN"
srcset="https://cdn.filestackcontent.com/resize=width:768/5aYkEQJSQCmYShsoCnZN 1x,
https://cdn.filestackcontent.com/resize=width:1536/5aYkEQJSQCmYShsoCnZN 2x"
alt="windsurfer"
width="768">
</picture>
Using width descriptors
You can specify generated widths by using resolutions
, which takes an array
of numbers or strings (e.g. 540
or '540w'
).
const options = {
alt: 'windsurfer',
sizes: {
'(min-width: 1080px)': '100vw',
fallback: '90vw',
},
resolutions: [540, 1080],
};
picture('5aYkEQJSQCmYShsoCnZN', options);
Output:
<picture>
<source media="(min-width: 1080px)"
sizes="100vw"
srcset="https://cdn.filestackcontent.com/resize=width:540/5aYkEQJSQCmYShsoCnZN 540w,
https://cdn.filestackcontent.com/resize=width:1080/5aYkEQJSQCmYShsoCnZN 1080w">
<img src="https://cdn.filestackcontent.com/5aYkEQJSQCmYShsoCnZN"
srcset="https://cdn.filestackcontent.com/resize=width:540/5aYkEQJSQCmYShsoCnZN 540w,
https://cdn.filestackcontent.com/resize=width:1080/5aYkEQJSQCmYShsoCnZN 1080w"
alt="windsurfer"
sizes="90vw">
</picture>
WebP support
WebP can be used when it's supported by the browser. Filestack will take care of the image conversion
and cache it on the delivery network for future requests.
const options = {
alt: 'windsurfer',
formats: ['webp', 'jpg'],
};
picture('5aYkEQJSQCmYShsoCnZN', options);
Output:
<picture>
<source srcset="https://cdn.filestackcontent.com/output=format:webp/5aYkEQJSQCmYShsoCnZN"
type="image/webp">
<source srcset="https://cdn.filestackcontent.com/output=format:jpg/5aYkEQJSQCmYShsoCnZN"
type="image/jpg">
<img src="https://cdn.filestackcontent.com/5aYkEQJSQCmYShsoCnZN" alt="windsurfer">
</picture>
Transformations support
Adaptive also supports Filestack transformations.
Available options are listed in doc:
https://www.filestack.com/docs/image-transformations
const options = {
alt: 'windsurfer',
width: 400,
transforms: {
blur: {
amount: 5
},
border: true,
}
};
picture('5aYkEQJSQCmYShsoCnZN', options);
Output:
<picture>
<img src="https://cdn.filestackcontent.com/blur=amount:5/border/resize=width:400/5aYkEQJSQCmYShsoCnZN" srcset="https://cdn.filestackcontent.com/blur=amount:5/border/resize=width:400/5aYkEQJSQCmYShsoCnZN 1x, https://cdn.filestackcontent.com/blur=amount:5/border/resize=width:800/5aYkEQJSQCmYShsoCnZN 2x" alt="windsurfer" width="400">
</picture>
Future
Adaptive is joining an ecosystem already populated with many utilities for responsive images.
We want to remain flexible while still having some opinions on how to implement picture elements using Filestack conversions, and we know it is hard to
cover every use case. Contributions and ideas are welcome that would help improve the usefulness of this library.
Current ideas:
- LQIP using the Filestack blur transformation
- Compress HiDPI images using Filestack compress task
- Implement art direction with Filestack crop
- Develop a PostHTML transform for post-processing HTML using
makePictureTree