Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement responsiveness with srcSet and sizes #159

Merged
merged 29 commits into from
Jul 30, 2018
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
560385c
chore(readme): fix typo and update codesandbox examples (#158)
frederickfogerty Jul 5, 2018
c03401a
chore(jest): upgrade jest to support new expect functions
frederickfogerty Jul 22, 2018
0070943
test: use srcset and sizes
frederickfogerty Jul 23, 2018
1bb6808
chore: update build:watch to build es instead of commonjs
frederickfogerty Jul 23, 2018
9c504c9
feat: add constants file and targetWidths from imgix.js
frederickfogerty Jul 23, 2018
ccdbfcf
test: mock window.screen for unit tests
frederickfogerty Jul 23, 2018
d21c5ea
feat: use srcset and sizes
frederickfogerty Jul 23, 2018
0392518
Merge branch 'version-8' into fred/use-srcsets
frederickfogerty Jul 23, 2018
26b0035
test: refactor alt test
frederickfogerty Jul 23, 2018
88eb552
test: refactor ixlib tests to use expectSrcTo
frederickfogerty Jul 23, 2018
6438f15
chore: stop using ...other in props
frederickfogerty Jul 23, 2018
7116c15
chore: rename support.js -> constructUrl.js
frederickfogerty Jul 23, 2018
fac1757
feat: add fallback srcset when using sizes
frederickfogerty Jul 23, 2018
df2db05
feat: update targetWidths with up to date reses, and remove max restr…
frederickfogerty Jul 25, 2018
fa7860c
chore: remove fixed TODO
frederickfogerty Jul 25, 2018
9cf4365
docs: update README for new srcSet/sizes
frederickfogerty Jul 26, 2018
8322693
test: add srcSet test for <source>
frederickfogerty Jul 26, 2018
93a5dfb
feat: use 2x and 3x srcSets for pictures
frederickfogerty Jul 26, 2018
6719d24
docs: update markdown link
frederickfogerty Jul 26, 2018
a7cbe47
docs: add sizes doc
frederickfogerty Jul 26, 2018
7af8394
chore: cleanup unused code
frederickfogerty Jul 26, 2018
c4750f1
chore: update targetWidth
frederickfogerty Jul 26, 2018
ecc0e84
feat: remove type=bg and add reference to issue
frederickfogerty Jul 26, 2018
78c25f0
chore: remove availWidth and availHeight constants as they're not used
frederickfogerty Jul 26, 2018
8108460
chore: update fit logic
frederickfogerty Jul 26, 2018
4e53375
test: remove type=bg tests
frederickfogerty Jul 26, 2018
a6cc892
docs: remove reference to unimplemented aspect ratio behaviour
frederickfogerty Jul 26, 2018
28b074a
docs: add upgrade guide
frederickfogerty Jul 29, 2018
9167095
chore: refactor some code to be more readable
frederickfogerty Jul 29, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 73 additions & 79 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,28 @@

A [React](https://facebook.github.io/react/) component that renders images using the [imgix](https://www.imgix.com/) API. It uses the smallest images possible, and does cool stuff, like [cropping to faces](https://www.imgix.com/docs/reference/size#param-crop) by default.

- [Overview / Resources](#overview-resources)
- [Installation](#installation)
- [Usage](#usage)
- [Examples](#examples)
- [Basic Use Case](#basic-use-case)
- [Server-side rendering](#server-side-rendering)
- [Flexible image rendering](#fixed-image-rendering-ie-non-flexible)
- [Fixed image rendering](#fixed-image-rendering)
- [Picture support](#picture-support)
- [Background mode](#background-mode)
- [Props](#props)
- [Browser Support](#browser-support)
- [Meta](#meta)

## Overview / Resources

**Before you get started with react-imgix**, it's _highly recommended_ that you read Eric Portis' [seminal article on `srcset` and `sizes`](https://ericportis.com/posts/2014/srcset-sizes/). This article explains the history of responsive images in responsive design, why they're necessary, and how all these technologies work together to save bandwidth and provide a better experience for users. The primary goal of react-imgix is to make these tools easier for developers to implement, so having an understanding of how they work will significantly improve your react-imgix experience.

Below are some other articles that help explain responsive imagery, and how it can work alongside imgix:

- [Using imgix with `<picture>`](https://docs.imgix.com/tutorials/using-imgix-picture-element). Discusses the differences between art direction and resolution switching, and provides examples of how to accomplish art direction with imgix.
- [Responsive Images with `srcset` and imgix](https://docs.imgix.com/tutorials/responsive-images-srcset-imgix). A look into how imgix can work with `srcset` and `sizes` to serve the right image.

## Installation

- **NPM**: `npm install react-imgix`
Expand All @@ -38,53 +54,69 @@ import Imgix from 'react-imgix'

#### Basic use case

For simply using as you would use an <img>, react-imgix can be used as follows:
For simply using as you would use an `<img>`, react-imgix can be used as follows:

```js
import Imgix from "react-imgix";

<Imgix src="https://assets.imgix.net/examples/pione.jpg" />;
<Imgix src="https://assets.imgix.net/examples/pione.jpg" sizes="100vw" />;
```

<iframe src="https://codesandbox.io/embed/xp0348lv0z?hidenavigation=1" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
**Please note:** `100vw` is an appropriate `sizes` value for a full-bleed image. If your image is not full-bleed, you should use a different value for `sizes`. [Eric Portis' "Srcset and sizes"](https://ericportis.com/posts/2014/srcset-sizes/) article goes into depth on how to use the `sizes` attribute.

#### Server-side rendering
This will generate HTML similar to the following:

```html
<img
src="https://assets.imgix.net/examples/pione.jpg?auto=format&amp;crop=faces&amp;fit=crop&amp;ixlib=react-7.2.0"
sizes="100vw"
srcset="https://assets.imgix.net/examples/pione.jpg?auto=format&amp;crop=faces&amp;fit=crop&amp;ixlib=react-7.2.0&amp;w=100 100w, https://assets.imgix.net/examples/pione.jpg?auto=format&amp;crop=faces&amp;fit=crop&amp;ixlib=react-7.2.0&amp;w=200 200w,..."
>
```

For server rendering, `aggressiveLoad` should be used. This component renders nothing on the first render as it tries to work out what the size of the container it will be rendering in, and only loads an image at the resolution required. For server rendering this will mean no image will be rendered.
Since imgix can generate as many derivative resolutions as needed, react-imgix calculates them programmatically, using the dimensions you specify (note that the w and h params scale appropriately to maintain the correct aspect ratio). All of this information has been placed into the srcset and sizes attributes.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm missing something, but what's up with the bit about w and h scaling properly? This isn't exemplified in the above code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, I was planning to do this but didn't get around to it. I might pull this out and put it in a separate issue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed from PR and added to #161


To keep some of this dynamic behaviour, this configuration is recommended. This will render an image on the server at the default dimensions specified, but will then check what size the element is once on the client, and load a second image.
**Width and height known:** If the width and height are known beforehand, it is recommended that they are set explicitly:

```js
import Imgix from "react-imgix";

<Imgix
src="https://assets.imgix.net/examples/pione.jpg"
aggressiveLoad
defaultWidth={100} // This sets what resolution the component should load from the CDN
defaultHeight={200}
width={100} // This sets what resolution the component should load from the CDN and the size of the resulting image
height={200}
/>;
```

Alternatively, if this dynamic behaviour is not desired, of if the width and height are known beforehand, the following is recommended.
[![Edit xp0348lv0z](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/xp0348lv0z?view=preview)

#### Server-side rendering

React-imgix also works well on the server. Since react-imgix uses `srcset` and `sizes`, it allows the browser to render the correctly sized image immediately after the page has loaded.

```js
import Imgix from "react-imgix";

<Imgix src="https://assets.imgix.net/examples/pione.jpg" sizes="100vw" />;
```

If the width and height are known beforehand, it is recommended that they are set explicitly:

```js
import Imgix from "react-imgix";

<Imgix
src="https://assets.imgix.net/examples/pione.jpg"
aggressiveLoad
width={100} // This sets what resolution the component should load from the CDN and the size of the resulting image
height={200}
/>;
```

#### Flexible image rendering

This component acts dynamically by default. The component will try and work out what the size of the image element is before loading an image from the CDN. Once it knows the dimensions of the element, it will only load an image at an appropriate size for that element, rather than loading the full-size image.
This component acts dynamically by default. The component will leverage `srcset` and `sizes` to render the right size image for its container. This is an example of this responsive behaviour.

react-imgix implements this by rendering nothing on the first render pass, and then trying to work out what the size of the container it will be rendering in. Then, it will render a second time with a resized src.

Nothing has to be configured for this to work, but to work well some styling should be used to set the size of the component rendered. Without correct styling the image might render at full-size.
`sizes` should be set properly for this to work well, and some styling should be used to set the size of the component rendered. Without `sizes` and correct styling the image might render at full-size.

`./styles.css`

Expand All @@ -94,8 +126,8 @@ Nothing has to be configured for this to work, but to work well some styling sho
}

.App > img {
margin: 0 auto;
width: 200px;
margin: 10px auto;
width: 10vw;
height: 200px;
}
```
Expand All @@ -106,11 +138,14 @@ Nothing has to be configured for this to work, but to work well some styling sho
import "./styles.css";

<div className="App">
<Imgix src="https://assets.imgix.net/examples/pione.jpg" />
<Imgix
src="https://assets.imgix.net/examples/pione.jpg"
sizes="calc(10% - 10px)"
/>
</div>;
```

<iframe src="https://codesandbox.io/embed/xp0348lv0z?hidenavigation=1" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
[![Edit xp0348lv0z](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/xp0348lv0z?view=preview)

#### Fixed image rendering (i.e. non-flexible)

Expand All @@ -126,6 +161,8 @@ import Imgix from "react-imgix";
/>;
```

[![Edit 4z1rzq04q7](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/4z1rzq04q7?view=preview)

#### Picture support

Using the [<picture> element](https://docs.imgix.com/tutorials/using-imgix-picture-element) you can create responsive images:
Expand All @@ -150,54 +187,26 @@ Using the [<picture> element](https://docs.imgix.com/tutorials/using-imgix-pictu

#### Background mode

When it's desired for the image to render as the background for an element such as div, `type=bg` can be used. The image will be set using `background-image: url()`.

```js
<Imgix src="https://assets.imgix.net/examples/pione.jpg" type="bg">
<span>Blog Title</span>
</Imgix>
```

<iframe src="https://codesandbox.io/embed/zq80p61r4l?hidenavigation=1" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>

_Note_: if you use type='bg' the css property background-size is set to 'cover' by default. To override this behaviour you can change the background size by overriding it with a string such as `'contain'`, or to `null` for controlling the style with CSS.

```js
<Imgix
src={src}
type="bg"
imgProps={{ style: { backgroundSize: "contain" } }}
/>
```

A custom component can be used when in bg mode by setting the `component` prop.

```js
<Imgix src={src} type="bg" component="header" />
```
This feature has been removed from react-imgix when `sizes` and `srcset` was implemented. It was decided that it was too hard to implement this feature consistently. If you would still like to use this feature, please open an issue! If we get enough requests for this, we will re-implement it.

### Props

#### src :: string, required

Usually in the form: `https://[your_domain].imgix.net/[image]`. Don't include any parameters.

#### aggressiveLoad :: bool, default = false
#### sizes :: string

Whether to wait until the component has mounted to render the image, useful for auto-sizing and server-side rendering, defaults to false
Specified the developer's expected size of the image element when rendered on the page. Similar to width. E.g. `100vw`, `calc(50vw - 50px)`, `500px`. Highly recommended when not passing `width` or `height`. [Eric Portis' "Srcset and sizes"](https://ericportis.com/posts/2014/srcset-sizes/) article goes into depth on how to use the `sizes` attribute.

#### auto :: array, default = ['format']

Array of values to pass to imgix's auto param
Array of values to pass to imgix's auto param.

#### type :: string, default = 'img'

What kind of component to render, one of `img`, `bg`, `picture`, `source`.

#### component :: string, default = 'div'

Wrapper component to use when rendering a `bg`, defaults to `div`

#### className :: string

`className` applied to top level component. To set `className` on the image itself see `imgProps`.
Expand All @@ -208,55 +217,39 @@ Whether or not to crop using points of interest. See imgix API for more details.

#### faces :: bool, default = true

Whether to crop to faces
Whether to crop to faces.

#### crop :: string

Sets specific crop, overriding faces and entropy flags. Useful for specifying fallbacks for faces like `faces,top,right`
Sets specific crop, overriding faces and entropy flags. Useful for specifying fallbacks for faces like `faces,top,right`.

#### fit :: string

See imgix's API, defaults to `crop`

#### fluid :: bool, default = true

Whether to fit the image requested to the size of the component rendered.
See imgix's API, defaults to `crop`.

#### onMounted :: func

Called on `componentDidMount` with the mounted DOM node as an argument

#### precision :: number

Round to nearest x for image width and height, useful for caching, defaults to `100`
Called on `componentDidMount` with the mounted DOM node as an argument.

#### height :: number

Force images to be a certain height, overrides `precision`
Force images to be a certain height.

#### width :: number

Force images to be a certain width, overrides `precision`

#### defaultHeight :: number

Fallback height for images, useful for SSR or static site generation

#### defaultWidth :: number

Fallback width for images, useful for SSR or static site generation
Force images to be a certain width.

#### generateSrcSet :: bool
#### disableSrcSet :: bool, default = false

Generate `2x` and `3x` src sets when using an `<img>` tag. Defaults to `true`
Disable generation of variable width src sets to enable responsiveness.

#### disableLibraryParam :: bool

By default this component adds a parameter to the generated url to help imgix with analytics and support for this library. This can be disabled by setting this prop to `true`.

#### customParams :: object

Any other imgix params to add to the image `src`
Any other imgix params to add to the image `src`.

_For example_:

Expand All @@ -266,11 +259,12 @@ _For example_:

#### imgProps :: object

Any other attributes to add to the html node (example: `alt`, `data-*`, `className`)
Any other attributes to add to the html node (example: `alt`, `data-*`, `className`).

## Browser Support

We support the latest version of Google Chrome (which [automatically updates](https://support.google.com/chrome/answer/95414) whenever it detects that a new version of the browser is available). We also support the current and previous major releases of desktop Firefox, Internet Explorer, and Safari on a rolling basis. Mobile support is tested on the most recent minor version of the current and previous major release for the default browser on iOS and Android (e.g., iOS 9.2 and 8.4). Each time a new version is released, we begin supporting that version and stop supporting the third most recent version.
- By default, browsers that don't support [`srcset`](http://caniuse.com/#feat=srcset), [`sizes`](http://caniuse.com/#feat=srcset), or [`picture`](http://caniuse.com/#feat=picture) will gracefully fall back to the default `img` `src` when appropriate. If you want to provide a fully-responsive experience for these browsers, react-imgix works great alongside [Picturefill](https://github.com/scottjehl/picturefill)!
- We support the latest version of Google Chrome (which [automatically updates](https://support.google.com/chrome/answer/95414) whenever it detects that a new version of the browser is available). We also support the current and previous major releases of desktop Firefox, Internet Explorer, and Safari on a rolling basis. Mobile support is tested on the most recent minor version of the current and previous major release for the default browser on iOS and Android (e.g., iOS 9.2 and 8.4). Each time a new version is released, we begin supporting that version and stop supporting the third most recent version.

This browser support is made possible by the great support from [BrowserStack](https://www.browserstack.com/).

Expand Down
Loading