Documentation

Overview

Response is a jQuery plugin that provides tools for building performance-optimized, mobile-first responsive websites. Its breakpoint sets use HTML5 data attributes to dynamically swap markup based on breakpoints so that rich content can be served progressively. Its API includes cross-browser event hooks, HTML5 dataset, and ways to get or test responsive properties.

Setup

Load with normal <script> tags:

<-- before your closing </body> tag -->
<script src="jquery.min.js"></script>
<script src="response.min.js"></script>

Or load via yepnope:

yepnope([{
    test: 320 < screen.width // devices 320 and up
  , yep: [ "jquery.min.js", "response.min.js" ]
}]);

Or load in WordPress:

wp_enqueue_script('response', 'response.min.js', array('jquery'), false, true); #wp

Breakpoint Sets

Response's most powerful feature is breakpoint sets. Using the sets, content for more-capable devices and/or larger viewports can be stored in HTML5 data attributes. Designers can create custom sets to make exactly the functionality that they want. (None are setup by default.)

Write markup like:

<div 
   data-min-width-320='<img src=lo-fi.png alt="image @ 320+ viewports">' 
   data-min-width-961='<img src=hi-fi.png alt="image @ 961+ viewports">'
> 
   text-only @ <320px and no-js
</div>

Or load a different src:

<-- Load lo-fi.png  for devices 0–640px wide or no-js. 
    Load hi-fi.png  for devices 641px+ wide. -->


<img src="lo-fi.png" data-min-device-width-641="hi-fi.png" alt="example" />

Breakpoints can be based on width | device-width | height | device-height | device-pixel-ratio or on custom props. Designers can use the default breakpoints (ideal for 960 grids) or specify custom breakpoints.

Using JSON as shown below is the simplest way to create sets. Sets can also be created in JavaScript using Response.create. In either case, the options are the same.

JSON setup example

<body data-responsejs='{ 
    "create": [{ 
        "prop": "width"
      , "prefix": "min-width- r src"
      , "breakpoints": [0, 320, 481, 641, 961, 1025, 1281] 
  }]
}'>

Use custom breakpoints or use the default breakpoints:

Modes

Elements behave in one of two modes—markup or src. Since version 0.3.0 modes are autodetected and it is only necessary to create one breakpoint set to accomodate both. (0.2.x devs should note that it is more efficient to create a set with prefix aliases such as "prefix": "r src" rather than creating a separate set for each mode. Either techniques works. The 0.3.0 and 0.3.1 change notes expand on this, and, if needed, the old docs are still online.)

The difference between the modes lies in the content that is swapped. In src mode, the src attribute is swapped. In markup mode, the innerHTML is swapped. Markup mode has more extensive capabilities because entire code blocks can be swapped.

img | input | source | embed | track elements always behave in src mode.

iframe | audio | video behave in src mode only if a src attribute is present.

Otherwise elements behave in markup mode.

Examples

src mode

src mode applies to elements that use the src attribute.

<-- Load lo-fi.png  when viewport is 0–480px wide or no-js. 
    Load medium.png when viewport is 481–1024px wide.
    Load hi-fi.png  when viewport is 1025px+ wide. -->


<img src="lo-fi.png" data-src481="medium.png" data-src1025="hi-fi.png" alt="example" />

Consider wrapping <img> tags in an <a> tag that links to the larger version. This allows two versions of the image to be accessible in more situations without compromising performance.

src mode consider wrapping images in links.

<a href="hi-fi.png"><img src="lo-fi.png" data-src1025="hi-fi.png" alt="example" /></a>

An important src mode caveat is that screens fitting the hi-fi band(s) will briefly start to load the lo-fi image and then switch to the higher one. This occurs during the time that jQuery and Response are loaded and parsed. To circumvent this switchover you can use markup mode instead and include the entire <img> tag inside the data attribute.

markup mode

markup mode applies to elements that support inner markup.

<-- Keep default when viewport is <320px wide or no-js. 
    Load data-r320 when viewport is 320–960px wide.
    Load data-r961 when viewport is 961px+ wide. -->


<div data-r320="markup @ 320+" data-r961="markup @ 961+">default</div>

Best practices in markup mode:

  • Default markup should be lightweight, and the data attribute(s) should be used to serve richer (heavier) content to capable screens. Think mobile first.
  • Default markup can be empty. But for accessibility, semantics, and SEO, consider using a text-only-ish default, which if needed you could hide/unhide via CSS media queries.
  • Escape quotes in attribute values as needed to prevent quote mismatches.

markup mode in markup mode, HTML can be swapped.

<a 
   href=hi-fi.png
   data-min-width-320='<img src=lo-fi.png alt="image @ 320+">' 
   data-min-width-961='<img src=hi-fi.png alt="image @ 961+">'
> 
   text-only link @ <320px and no-js
</a>

Ideal uses for markup mode:

  • Load sidebars only for screens wide enough to fit them.
  • Load images only for screens above a certain breakpoint—with a non-image fallback. (On a blog, you could load article headlines on small screens and add thumbnails to screens above a breakpoint.)

Escape Quotes in Data Attributes

GOOD: data-r0="<a id='myid'>here is text</a>"
GOOD: data-r0="<a id=&quot;myid&quot;>here's text</a>"
GOOD: data-r0='<a id="myid">here&#039;s text</a>'
FAIL: data-r0='<a id="myid">here's text</a>'

CMS Integration

In CMS implementations or other situations where markup mode inputs are dynamic, you'll surely need some sort of escaping function, such as PHP's htmlspecialchars() or WordPress' esc_attr().

API (0.6)

Response provides cross-browser compatible ways to get and test properties that matter when building responsive websites, an HTML5 dataset implentation, event hooks for responsive actions, and related utilities. An API overview is below. Additional documention is on Github and in the test suite.

Getters

Response.deviceW() // Get the device width.
@example jsfiddle.net/eKHWF/5/
@return number
Response.deviceH() // Get the device height.
@example jsfiddle.net/eKHWF/5/
@return number
Response.deviceMax() // Get the calculated Math.max(deviceW, deviceH)
@example jsfiddle.net/eKHWF/5/
@return number
Response.deviceMin() // Get the calculated Math.min(deviceW, deviceH)
@example jsfiddle.net/eKHWF/5/
@return number
Response.viewportW() // Get the current viewport width.
@example jsfiddle.net/eKHWF/5/
@return number
Response.viewportH() // Get the current viewport height.
@example jsfiddle.net/eKHWF/5/
@return number
Response.scrollX() // cross-broswer equivalent to native window.scrollX
@return number
Response.scrollY() // cross-broswer equivalent to native window.scrollY
@return number

Booleans

Response.band(min [, max]) // Test if a viewport min/max-width range is active.
@param integer min
is a min-width in pixels.
@param integer max
is a max-width in pixels.
@return boolean
Response.band(481) // true in viewports 481px wide and up.
Response.band(0, 480) // true in viewports 0-480px wide.
Response.wave(min [, max]) // Test if a viewport min/max-height range is active.
@param integer min
is a min-height in pixels.
@param integer max
is a max-height in pixels.
@return boolean
Response.wave(481) // true in viewports 481px high and up.
Response.wave(0, 480) // true in viewports 0-480px high.
Response.device.band(min [, max]) // Test if a min/max-device-width range is active.
@param integer min
is a min-width in pixels.
@param integer max
is a max-width in pixels.
@return boolean
Response.device.band(481) // true for devices 481px wide and up.
Response.device.band(0, 480) // true for devices  0-480px wide.
Response.device.wave(min [, max]) // Test if a min/max-device-height range is active.
@param integer min
is a min-height in pixels.
@param integer max
is a max-height in pixels.
@return boolean
Response.device.wave(481) // true for devices 481px high and up.
Response.device.wave(0, 480) // true for devices  0-480px high.
Response.dpr(ratio) // Get the device-pixel-ratio, or test if a given device-pixel-ratio is active.
@param number ratio
is a device-pixel-ratio to test (integer or float)
@return number|boolean
Response.dpr() // get device-pixel-ratio (returns 0 if undetectable)
Response.dpr(1.5) // true when device-pixel-ratio is 1.5+
Response.dpr(2) // true when device-pixel-ratio is 2+
Response.media(query) // Get window.matchMedia || window.msMatchMedia || {}

This is a browser-normalized generic method designed for when none of the above booleans apply. It uses the same syntax as window.matchMedia and falls back gracefully when not supported. The booleans above (band, wave, etc.) are faster and better supported than this method (although you can polyfill matchMedia before Response is loaded to improve support).

@param string query
is a media query to test.
@return object
The .matches prop is boolean (or undefined if neither form is supported).
Response.media("(min-width: 20em)").matches // true in viewports 20em+ wide.
Response.inViewport(elem [, verge]) // Test if any part of an element is in the viewport.
@param object elem
is a native DOM element or jQuery object to test.
@param number verge
is the # extra pixels around elem to also test. (Defaults to 0)
@return boolean
@example responsejs.com/test/
Response.inViewport(this) // true if any part of this is in the viewport (exact).
Response.inViewport(this, 100) // true if any part of this is in (or 100px near) the viewport.
Response.inViewport(this) === Response.inX(this) && Response.inY(this) // always true
Response.inX(elem [, verge]) // Test if any part of elem is in the same x-axis as the viewport.
@param object elem
is a native DOM element or jQuery object to test.
@param number verge
is the # extra pixels around elem to also test. (Defaults to 0)
@return boolean
@example responsejs.com/test/
Response.inX(this) // true if any part of this is in same x-axis as the viewport (exact).
Response.inX(this, 100) // true if any part of this is in (or 100px near) the same x-axis.
Response.inViewport(this) === Response.inX(this) // true if there is no vertical overflow
Response.inY(elem [, verge]) // Test if any part of elem is in the same y-axis as the viewport.
@param object elem
is a native DOM element or jQuery object to test.
@param number verge
is the # extra pixels around elem to also test. (Defaults to 0)
@return boolean
@example responsejs.com/test/
Response.inY(this) // true if any part of this is in same y-axis as the viewport (exact).
Response.inY(this, 100) // true if any part of this is in (or 100px near) the same y-axis.
Response.inViewport(this) === Response.inY(this) // true if there is no horizontal overflow

Events

Response.ready(fn) // Call function when the DOM is ready.
@param callback fn
is a function to call on ready.
Response.ready(function(){ /*  stuff to do on ready */ });
Response.resize(fn) // Call function whenever the window (viewport) resizes.
@param callback fn
is a function to call on the resize event.
Response.resize(function(){ /* stuff to do on resize */ });
Response.action(fn) // Call function when the DOM is ready and whenever the window resizes.
@param callback fn
is a function to call on ready and resize.
Response.action(function(){ /*  stuff to do on ready and resize */ });
Response.crossover(fn [, prop]) // Call function when breakpoint sets' breakpoints are crossed.
@param callback fn
is a function to call on the crossover custom event.
@param string prop
is a specific prop's breakpoints to target. Defaults to all.
Response.crossover(function(){ /*  stuff to do on all breakpoint set crossovers */ });
Response.crossover(function(){ /*  stuff to do on "width" crossovers */ }, "width");

Dataset

Note: The dataset methods in Response 0.7+ come from dope.

Response.dataset(elem [, key, value]) // Get or set custom data- attributes.
@param object elem
is a native DOM element or jQuery element.
@param string|mixed key
is the camelCase (or lowercase) identifier for the data.
@param string|mixed value
is the data value to store.
@return mixed
Response.dataset(el, "showName", "Lost") // Set data-show-name on el to "Lost"
Response.dataset(el, "seasonNumber", 1) // Set data-season-number on el to "1"
Response.dataset(el, {seasonNumber: 1, episode: 5}) // Set multiple data attrs at once.
Response.dataset(el, "showName", "Lost") // Set data-show-name on el to "Lost"
Response.dataset(el, "showName") // Get data-show-name // "Lost"
Response.dataset(el, "seasonNumber") // Get data-season-number // "1"
Response.dataset(el, ["seasonNumber"]) // Get and render data-season-number // 1
Response.dataset(el) // Get object containing all data attrs on el element.
Response.dataset(el).showName // "Lost"
Response.dataset($(".shows"), "genre", "drama") // Set data-genre to "drama" on all shows
Response.deletes(elem, keys) // Remove custom data- attributes.
@param object elem
is a native DOM element or jQuery element.
@param string keys
is one or more space-separated keys to remove.
Response.deletes(el, "showName") // Remove data-show-name from el.
Response.deletes(el, "showName seasonNumber") // Remove both data attrs from el.
Response.deletes($(".shows"), "genre") // Remove data-genre from all shows.
$.fn.dataset([key, value]) // Get or set custom data- attributes.

This is a jQueryish form of the dataset method. To enable it, first call Response.bridge(jQuery).

$("#lost").dataset("showName", "Lost") // Set data-show-name on #lost to "Lost"
$("#lost").dataset("seasonNumber", 1) // Set data-season-number on #lost to "1"
$("#lost").dataset({seasonNumber: 1, episode: 5}) // Set multiple data attrs at once.
$("#lost").dataset("showName", "Lost") // Set data-show-name on this to "Lost"
$("#lost").dataset("showName") // Get data-show-name // "Lost"
$("#lost").dataset("seasonNumber") // Get data-season-number // "1"
$("#lost").dataset(["seasonNumber"]) // Get and render data-season-number // 1
$("#lost").dataset() // Get object containing all data attrs on #lost.
$("#lost").dataset().showName // "Lost"
$(".shows").dataset("genre", "drama") // Set data-genre to "drama" on all shows.
$(".shows").dataset("genre") // Get data-genre of the first element in the set. // "drama"
$.fn.deletes(keys) // Remove custom data- attributes.

This is a jQueryish form of the deletes method. To enable it, first call Response.bridge(jQuery).

$("#lost").dataset("showName") // Remove data-show-name from el.
$("#lost").dataset("showName seasonNumber") // Remove both data attrs from el.
$(".shows").dataset($("genre") // Remove data-genre from all shows.

Extending

Response.create(options) // Create breakpoint sets.
@param object|array options
is an object (or array of objects) specifying options for the set(s).
options.prop (string)
is the property to base breakpoints on. Supported props are width|height|device-width|device-height|device-pixel-ratio. Custom props can be added via Response.addTest(). Default: "width"
@param string options.prefix
is a prefix to use in the data- key. It can be alphanumerics, dashes, and/or underscores. A unique prefix must be used for each set. Prefixes create attribute names of the form data-myprefix320, data-myprefix481, etc. Since 0.3.1 it is possible to define multiple (aliased) prefixes in a space-separated string. Default: "min-[prop]-" (e.g. if the prop is "width" then the prefix would default to "min-width-")
@param array options.breakpoints
is an array of min- breakpoints. Defaults depend on the prop. See here.
@param void options.mode
OBSOLETE. Modes are autodetected since 0.3.0.
@example responsejs.com/wiki/how-to-create-breakpoint-sets
Response.bridge($) // Integrate .dataset/.deletes into $.fn

Optional methods added by Response.bridge($) are: dataset and deletes. To use these optional methods simply call Response.bridge($) before you need them. (It only needs to be called once.)

Response.addTest(prop, fn) // Add a custom test for use in breakpoint sets.
@param string prop
is a custom prop name (or an existing prop to override).
@param callback fn
is a boolean callback to test min breakpoints for prop.
Response.addTest("viewport-area", function(min) {
    return min >= Response.viewportW() * Response.viewportH();
}).create({
    prop: "viewport-area" // custom prop name
  , breakpoints: [100000, 1000000, 10000000] // custom breakpoints
  , dynamic: true // set this to true if prop needs to be tested on resize
});

Closures

It is recommended that you wrap custom code in a self-invoking anonymous function. This design pattern has several advantages. Watch this video to learn more. It looks like this:

(function(window, document, $, R) { // put the vars you need and match them at the bottom

    // All 4 vars are localized in here - makes them read faster b/c they are in local scope
    // $ works as alias for jQuery in here - ensures no conflict with other libs
    // R works as alias for Response in here - R.band(320) instead of Response.band(320)
    // window and document minify down to single letter vars
    
}(this, this.document, this.jQuery, this.Response)); // in global scope, this === window

Comments

The Disqus thread has been removed but is readable at responsejs.disqus.com. The best way to ask a question is to create an issue via Github or tweet to @ryanve