UNPKG

12 kBMarkdownView Raw
1# ViewportJS #
2
3[![NPM version](https://img.shields.io/npm/v/viewportjs.svg)](https://www.npmjs.com/package/viewportjs) [![Build Status](https://img.shields.io/travis/ryanfitzer/ViewportJS.svg)](https://travis-ci.org/ryanfitzer/ViewportJS?branch=master) ![Total downloads](https://img.shields.io/npm/dt/viewportjs.svg) [![Maintainability](https://img.shields.io/codeclimate/maintainability/ryanfitzer/ViewportJS.svg)](https://codeclimate.com/github/ryanfitzer/ViewportJS/maintainability)
4
5ViewportJS is built on top of `window.matchMedia` and provides valuable features that enable more structure when querying and subscribing to media queries.
6
7 - 1.16 kB minified & gzipped.
8
9 - Supports all browsers that [support `window.matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia#Browser_compatibility).
10
11 - Compatible with CommonJS, AMD, and browser globals (via [UMD](https://github.com/umdjs/umd)).
12
13 - Supports SSR (server-side rendering) by providing a shallow API when `window.matchMedia` is unavailable.
14
15Give the [demo](http://ryanfitzer.github.io/ViewportJS/demo) a try by changing the size of your browser window and watch the UI update.
16
17If you are upgrading from [v3](../../tree/v3.0.2), please see the [v4 migration guide](docs/migrating-to-4.0.0.md).
18
19
20------
21<!-- START doctoc generated TOC please keep comment here to allow auto update -->
22<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
23
24- [Installation](#installation)
25 - [CommonJS](#commonjs)
26 - [AMD](#amd)
27 - [Browser Global](#browser-global)
28- [Usage](#usage)
29- [Configuration](#configuration)
30- [Subscribing to Viewport Changes](#subscribing-to-viewport-changes)
31 - [Subscribing Directly to a `mediaQueryString`](#subscribing-directly-to-a-mediaquerystring)
32- [Instance Methods](#instance-methods)
33 - [`current( [name] )`](#current-name-)
34 - [`matches( [name] )`](#matches-name-)
35 - [`previous( [name] )`](#previous-name-)
36 - [`remove()`](#remove)
37 - [`state( [name] )`](#state-name-)
38- [Server-Side Rendering](#server-side-rendering)
39- [Examples](#examples)
40
41<!-- END doctoc generated TOC please keep comment here to allow auto update -->
42
43
44## Installation ##
45
46
47### CommonJS ###
48
49
50Install the latest version from [npm](https://www.npmjs.com/package/viewportjs):
51
52```bash
53npm install viewportjs
54```
55
56Add the `viewportjs` package to your app:
57
58```js
59const viewport = require( 'viewportjs' );
60
61const myViewports = viewport( /* configuration */ );
62```
63
64### AMD ###
65
66The API is exported as an anonymous module. If you're not familiar with AMD, [RequireJS](https://requirejs.org/docs/start.html) is a great place to start.
67
68
69### Browser Global ###
70
71Download the latest [development](https://unpkg.com/viewportjs/dist/viewport.js) and [production](https://unpkg.com/viewportjs/dist/viewport.min.js) versions from [UNPKG](https://unpkg.com/viewportjs/dist/). Once the script is loaded, the `viewport` function can be accessed globally.
72
73```html
74<!-- When deploying, replace "viewport.js" with "viewport.min.js". -->
75<script src="viewport.js"></script>
76<script>
77 const myViewports = viewport( /* configuration */ );
78</script>
79```
80
81
82
83## Usage ##
84
85Configure viewports by name:
86
87```js
88const myViewports = viewport( [
89 {
90 name: 'small',
91 query: '( min-width:0px ) and ( max-width:480px )'
92 },
93 {
94 name: 'medium',
95 query: '( min-width:480px ) and ( max-width:767px )'
96 },
97 {
98 name: 'large',
99 query: '( min-width:769px )'
100 }
101] );
102```
103
104Once configured, you can query their state:
105
106```js
107// Check if `small` is the current viewport
108myViewports.current( 'small' ); // boolean
109
110// Get the current viewport object
111myViewports.current(); // { name: 'small', matches: boolean, current: boolean }
112
113// Check if the `small` viewport's media query matches
114myViewports.matches( 'small' ); // boolean
115
116// Retrieve all matches
117myViewports.matches(); // [ /* matches viewport state objects */ ]
118```
119
120You can also subscribe to state changes:
121
122```js
123// Subscribe to changes in 'small' viewport
124myViewports( 'small', state => {
125
126 // Do something based on `state`
127 // {
128 // name: 'small',
129 // matches: boolean,
130 // current: boolean
131 // }
132
133} );
134```
135
136
137
138## Configuration ##
139
140The initialization method takes an array of viewport configuration objects that are composed of two properties:
141
142- `name` *(string)* The viewport's nickname. Must be unique.
143
144- `query` *(string)* A valid [`mediaQueryString`](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#Syntax).
145
146The order of these objects in the array is important, as it determines how to calculate the `current` viewport, which is defined as the last matching viewport based on the order of the configuration array. So if you prefer a "mobile-first" approach, your viewport configuration objects should be ordered from smallest to largest.
147
148The initialization method returns a configured instance that can act as:
149
150 - A function used to subscribe to viewport changes.
151 - An object that contains methods for querying viewport state.
152
153
154
155## Subscribing to Viewport Changes ##
156
157The initialization method returns an instance that can be used to subscribe to state changes on the configured viewports.
158
159Arguments:
160
161 - `name`: *(string)* (optional) The name of a configured viewport.
162 - `handler`: *(Function)* The function to execute whenever state changes occur.
163
164Returns:
165
166 - *(Function)*: A function that unsubscribes `handler`.
167
168To subscribe to the state of an individual viewport, both `name` and `handler` are required. Providing only a `handler` will set up a subscription to the states of all configured viewports.
169
170A subscriber's `handler` is executed whenever there's a change in either the viewport's `matched` or `current` state. When a subscriber is added, its `handler` will be immediately executed.
171
172The `handler` receives the following arguments when executed:
173
174 - `state`: *(Object)* The changed viewport's state object.
175 - `instance`: *(Object)* The configured instance.
176
177A viewport state object has three properties:
178
179 - `name`: *(string)* The name of a configured viewport.
180 - `matches`: *(boolean)* If the viewport's media query matches.
181 - `current`: *(boolean)* If the viewport is current.
182
183Example:
184
185```js
186const myViewports = viewport( /* configuration */ );
187
188// Subscribe to an individual configured viewport
189myViewports( 'name', state => {} );
190
191// Subscribe to all configured viewport
192myViewports( state => {} )
193```
194
195### Subscribing Directly to a `mediaQueryString` ###
196
197For scenarios where you're only interested in matching a single media query, you can provide the initialization method with a valid [`mediaQueryString`](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#Syntax) and an optional `handler`, instead of a configuration array. This will return an instance with a limited API.
198
199Arguments:
200
201 - `query`: *(string)* A valid `mediaQueryString`.
202 - `handler`: *(Function)* (optional) The function to execute whenever state changes occur.
203
204Returns:
205
206 - *(Object)*: A limited API composed of the `matches()` and `remove()` method.
207
208If provided, `handler` is executed whenever there's a change in the media query's `matched` state, including on initial subscription.
209
210The `handler` receives the following arguments when executed:
211
212 - `matches`: *(boolean)* If the media query matches.
213 - `instance`: *(Object)* The configured instance.
214
215Example:
216
217```js
218const smallvp = viewport( '( max-width: 500px )', ( matches, instance ) => {} );
219
220smallvp.matches(); // true/false
221smallvp.remove(); // remove the handler, if provided.
222```
223
224
225
226## Instance Methods ##
227
228
229### `current( [name] )` ###
230
231When called with the `name` argument, checks if `name` is the current viewport and returns a boolean. Otherwise, it returns the current viewport's state object.
232
233The current viewport is defined as the last matching viewport based on the order of the configuration array. If there is no current viewport, the state object for the `undefined` viewport is returned: `{ name: undefined, matches: false, current: false }`.
234
235
236Arguments:
237
238 - `name`: *(string)* (optional) The name of the configured viewport to check.
239
240Returns:
241
242 - *(boolean)*: If `name` is the current viewport.
243 - *(Object)*: The state object of the current viewport.
244
245
246```js
247myViewports.current(); // { name: string, matches: boolean, current: boolean }
248
249myViewports.current( 'name' ); // true/false
250```
251
252### `matches( [name] )` ###
253
254When called with the `name` argument, checks if the `name` viewport's media query matches. Otherwise, it returns an array of all matching viewports.
255
256If there are no matching viewports, an empty array is returned.
257
258
259Arguments:
260
261 - `name`: *(string)* (optional) The name of the configured viewport to check.
262
263Returns:
264
265 - *(boolean)*: If the `name` viewport matches.
266 - *(Array)*: An array of state objects for all matching viewports.
267
268
269```js
270myViewports.matches(); // [ { name: string, matches: boolean, current: boolean }, ... ]
271
272myViewports.matches( 'name' ); // true/false
273```
274
275### `previous( [name] )` ###
276
277When called with the `name` argument, checks if the `name` viewport was the previously current viewport. Otherwise, it returns the previously current viewport's state object.
278
279If there was no previously current viewport, the state object for the `undefined` viewport is returned: `{ name: undefined, matches: false, current: false }`.
280
281
282Arguments:
283
284 - `name`: *(string)* (optional) The name of the configured viewport to check.
285
286Returns:
287
288 - *(boolean)*: If `name` was the previously current viewport.
289 - *(Object)*: The state object of the previously current viewport.
290
291
292```js
293myViewports.previous(); // { name: string, matches: boolean, current: boolean }
294
295myViewports.previous( 'name' ); // true/false
296```
297
298
299### `remove()` ###
300
301Removes all the instance's configured viewports and subscribers at once.
302
303Returns:
304
305 - *(null)*: Subscribers are removed and values set to `null`.
306
307```js
308const myViewports = viewport( /* viewport config array */ );
309
310myvps( 'small', state => {} );
311myvps( 'medium', state => {} );
312
313myvps.remove();
314```
315
316### `state( [name] )` ###
317
318When called with the `name` argument, returns the named viewport's state object. Otherwise, it returns an array of state objects for all viewports.
319
320Arguments:
321
322 - `name`: *(string)* (optional) The name of the configured viewport to check.
323
324Returns:
325
326 - *(Object)*: The state object of the named viewport.
327 - *(Array)*: An array of state objects for all viewports.
328
329
330```js
331myViewports.state(); // [ { name: string, matches: boolean, current: boolean }, ... ]
332
333myViewports.previous( 'name' ); // { name: string, matches: boolean, current: boolean }
334```
335
336
337
338## Server-Side Rendering ##
339
340ViewportJS supports SSR (or "Universal JavaScript") through a shallow API that enables the use of all methods in an environment where `window.matchMedia` is unavailable.
341
342Due to potential memory leaks, calls that subscribe to viewports should only be made when their respective unsubscribe functions (or the instance's `remove()` method) can be called in the same environment. Initialization and query methods can be used in any environment, but it's best if subscriptions are made in code that only executes in the browser. The `development` build of ViewportJS will log a warning whenever a subscription is made in an environment where `window.matchMedia` is unavailable. All logging is removed in the `production` build.
343
344See the relevant framework examples below for SSR-compatible demonstrations.
345
346
347
348## Examples ##
349
350- [Vanilla](https://codesandbox.io/s/q3no20volw?module=%2Fsrc%2Findex.js)
351- [React](https://codesandbox.io/s/00l82nl6pv?module=%2Fsrc%2Fvpjs-component.js)
352- [Vue](https://codesandbox.io/s/zw8283vyol?module=%2Fsrc%2Fcomponents%2Fvpjs-component.vue)
353- Angular (todo)
354- Riot (todo)
355- [Next.js](https://codesandbox.io/s/q3r0xympjq?module=%2Fcomponents%2Fvpjs-component.js)
356- Nuxt.js (todo)
357- Ember (todo)