Skip to content

Foresight.js gives webpages the ability to tell if the user's device is capable of viewing high-resolution images (such as the 3rd generation iPad) before the image is requested from the server. Additionally, it judges if the user's device currently has a fast enough network connection for high-resolution images. Depending on device display and …

License

winddweb/foresight.js

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Introduction

Foresight.js gives webpages the ability to tell if the user's device is capable of viewing high-resolution images (such as the 3rd generation iPad) before the image is requested from the server. Additionally, it judges if the user's device currently has a fast enough network connection for high-resolution images. Depending on device display and network connectivity, foresight.js will request the appropriate image for the webpage. It modifies context image requests, specifically the img src attribute, but the server does the image resizing. Media queries however should be used when dealing with CSS background-images, while foresight.js is used to handle inline img elements (or until current web standards are improved).

This project's overall goal is to tackle these current issues faced by web developers designing for hi-res: Challenges for High-Resolution Images. Foresight.js aims at providing a lightweight, cross-browser and framework independent tool for a high-resolution web. Please feel free to contact me (@adamdbradley) or contribute to this project to help improve it.

Features

  • Request hi-res images according to device pixel ratio
  • Estimates network connection speed prior to requesting an image
  • Does not use device detection through user-agents
  • Does not make multiple requests for the same image
  • Javascript library and framework independent (ie: jQuery not required)
  • Cross-browser and cross-platform
  • Image dimensions set by percents will scale to the parent element's available width and device pixel ratio
  • Fully customizable through global configuration options and individual img attributes
  • Default images will load without javascript enabled
  • Minifies down to roughly 5K

Demos

Before we get too far into the nitty-gritty, it's probably best to view foresight.js in action. Currently most desktop and laptops do not have high-resolution displays and are limited to a device pixel ratio of only 1, so you will not be able to see the effects on a standard monitor. Make sure you view the demos from multiple devices, such as your mobile phone, tablet and traditional computer.

Img Element

One of the largest problems faced with dynamically deciding image quality is that by the time javascript is capable of viewing an img in the DOM, the image file has already been requested from the server. And on the flip side, if img elements are built by javascript then search engines probably won't view them and browsers without javascript enabled will also not be able to view the images. To overcome both of these challenges foresight.js uses the img element, but without the src attribute set, and a noscript element with a child img element.

<img data-src="imagefile.jpg" data-width="320" data-height="240" class="fs-img">
<noscript>
    <img src="imagefile.jpg">
</noscript>

Notice how the first image is missing the src attribute, but instead has a data-src attribute. Because this img element does not have the src attribute the browser will not attempt to download the file. Once the DOM is ready, foresight.js does its magic to transform the data-src and set the src attribute tailored to the device's display and network connectivity. Using this structure allows us to still place img elements within the context of the webpage, while also allowing search engines and javascript disabled browsers to view the images.

One concept change is that both the data-width and data-height attributes should not be seen as the image's physical dimensions, but rather a way for the browser to know the image's aspect ratio as it is scaled up and down according to the desired dimensions and device pixel ratio. After gathering info about the device/browser and your given requirements, foresight.js decides the image's actual dimensions, while the data-width and data-height attributes help to maintain its correct aspect ratio.

Until the web community completes a new standard to hi-res context images, and it becomes widely adopted by all the major browsers, and the updated browsers are installed on the billions of devices in the world, the approach by foresight.js is one of the few that answers each of the Challenges for High-Resolution Images.

There is hope however as the web community works on a solution to high-resolution images. These two resources offer a glimpse about what's currently being worked on (and be sure to read the comments too) Adaptive Image Element and also Polyfilling picture without the overhead.

NoScript Element

Immediately you'll notice that the noscript element and its child img is redundant, but with today's standards this is one of the issues we'll have to dance with.

If javascript is not enabled then the browser shows the noscript img instead. In this case the webpage should also hide the first img so it's not seen as a broken image. The head element of the document should contain:

<style> .fs-img{ display:none }</style>

When foresight.js executes, it will change each image's CSS class from fs-img to fs-img-ready so that the .fs-img CSS display:none will no longer apply and the images can be seen.

If your website has no reason to care about SEO or support browsers without javascript than feel free to omit the noscript elements all together.

High-Speed Network Connection Test

Currently most devices capable of hi-res displays are mobile devices, such as new iPhones or iPads. However, since they are "mobile" in nature and their data may be relying on cell towers, even if the device has a hi-res display, users with slow connectivity probably do not want to wait a long time while images download. In these cases, foresight.js does a quick network speed test to make sure the user's device can handle hi-res images. Additionally, it stores the devices network connection speed information for 30 minutes (or is customizable to any expiration period you'd like) so it does not continually perform speed tests. You can host your own speed test file to be downloaded, or you can use the default URI available for public use found in the foresight.js configuration.

Src Modification

An img src attribute needs to be modified so the browser can request the correct image according to the device and network speed. How an image's src is templated is entirely up to the URI format of the server, but foresight.js allows the img src attribute to be customized to meet various templates. See Server Resizing Images for more information on a few options for requesting various images sizes from a server.

Src modification types can be assigned in the foresight.options.srcModification config, or individually for each image using the img data-src-modification attribute. The possible values are replaceDimensions or rebuildSrc and described below.

replaceDimensions: The current src may already have dimensions within the URI. Instead of rebuilding the src entirely, just find and replace the original dimensions with the new dimensions.

rebuildSrc: Rebuild the src by parsing apart the current URI and rebuilding it using the supplied src URI template. Review the Src URI Template section to see how to format the image URI's.

Also view the data-src-high-resolution attribute definition under the Img Attributes section to read more about manually setting which file to use when the hi-res image should be shown instead. Src Modification should be used when dynamically building the img src, while the data-src-high-resolution attribute is used if you want to manually tell foresight.js which image to use when hi-res is enabled.

Src URI Template

The src URI template is only required when using the rebuildSrc src modification. The src URI template provides foresight.js with how the request should be built for the image. Each server's image request is different and the srcUriTemplate value allows the URI to be customized. The template can either be in the foresight.options.srcUriTemplate config, or individually for each image using the img data-src-uri-template attribute. Below are the various keys that are used to rebuild the src to request the correct image from the server. Each one is not required, and you should only use the keys that help build the src request for the server. More info about Server Resizing Images.

{protocol}: The protocol of the request. ie: http or https

{host}: The host. ie: cdn.mysite.com or www.wikipedia.com

{port}: The port number, but production systems will rarely use this. ie: 80

{directory}: The directory (folder) within the path. ie: /images/

{file}: Includes both the file-name and file-extension of the image. ie: myimage.jpg

{filename}: Only the file-name of the image. ie: myimage

{ext}: Only the file-extension of the image. ie: jpg

{query}: The querystring. ie: page=1&size=10

{requestWidth}: The requested width of the image to load. This value will automatically be calculated, it's just that you need to tell foresight.js where to put the request width in the src. ie: 320

{requestHeight}: The requested height of the image to load. This value will automatically be calculated, it's just that you need to tell foresight.js where to put the request height in the src. ie: 480

{pixelRatio}: The requested pixel ratio of the image to load. This value will automatically be calculated, it's just that you need to tell foresight.js where to put this info in the src. ie: 2

Again, not all of these keys are required inside your src URI. Src URI template is entirely dependent on how the server handles image requests. See Server Resizing Images for more information on a few options for requesting various images sizes from a server.

Src Format Examples

Example A: Width and height in their own directory
Original Img Src: http://cdn.mysite.com/images/myimage.jpg
SrcUriTemplate:   {protocol}://{host}{directory}{requestWidth}x{requestHeight}/{file}
Request Src:      http://cdn.mysite.com/images/640x480/myimage.jpg

Example B: Width and height in the querystring
Original Img Src: http://cdn.mysite.com/images/myimage.jpg
SrcUriTemplate:   {protocol}://{host}{directory}{file}?w={requestWidth}&h={requestHeight}
Request Src:      http://cdn.mysite.com/images/myimage.jpg?w=640&h=480

Example C: Width in the filename, request to the same host
Original Img Src: /images/myimage.jpg
SrcUriTemplate:   {directory}{requestWidth}px-{file}
Request Src:      /images/320px-myimage.jpg

Example D: Pixel ratio in the filename
Original Img Src: http://images.example.com/home/images/hero.jpg
SrcUriTemplate:   {protocol}://{host}{directory}{file}_{pixelRatio}x.jpg
Request Src:      http://images.example.com/home/images/hero_2x.jpg

Foresight.js Options

Foresight.js comes with default settings, but using the foresight.options object allows you to customize them as needed. The easiest way to configure foresight.js is to include the foresight.options configuration before the foresight.js script, such as:

<script>
    foresight = {
        options: {
            srcModification: 'rebuildSrc',
            srcUriTemplate: '{directory}{requestWidth}px-{file}'
        }
    };
</script>
<script src="foresight.js"></script>

foresight.options.srcModification: Which type of src modification to use, either rebuildSrc or replaceDimensions. See the Src Modification section for more info.

foresight.options.srcUriTemplate: The URI template in which a src should be rebuilt from. See the Src URI Template section for more info.

foresight.options.testConn: Boolean value determining if foresight.js should test the network connection speed or not. Default is true

foresight.options.minKbpsForHighSpeedConn: Foresight.js considers a network connection to be either high-speed or not. When a device has a high-speed connection and hi-res display it will request hi-res images to be downloaded. However, everyone's interpretation of what is considered high-speed should be a variable. By default, any connection that can download an image at a minimum of 400Kbps is considered high-speed. The value should be a number representing Kbps. Default value is 400

foresight.options.speedTestUri: You can determine the URI for the speed test image. By default it will use a foresight.js hosted image, but you can always choose your own URI for the test image. Default value is http://foresightjs.appspot.com/speed-test/50K.jpg (also note that if the webpage is in SSL, foresight.js will replace 'http:' for 'https:' to avoid any ugly security warnings)

foresight.options.speedTestKB: Foresight.js needs to know the filesize of the speed test file is so it can calculate the approximate network connection speed. By default it downloads a 50KB file. The value should be a number representing KiloBytes. Default value is 50

foresight.options.speedTestExpireMinutes: Speed-tests do not need to be continually performed on every page. Instead you can set how often a speed test should be completed, and in between tests you can rely on past test information. The value should be a number representing how many minutes a speed test is valid until it expires. Default value is 30

foresight.options.maxBrowserWidth: A max pixel width can be set on images. This is in reference to browser, or CSS, pixels. Default value is 1024

foresight.options.maxBrowserHeight: A max pixel height can be set on images. This is in reference to browser, or CSS, pixels. Default value is 1024

foresight.options.maxRequestWidth: A max pixel request width can be set on how large of images can be requested from the server. Default value is 2048

foresight.options.maxRequestHeight: A max pixel request height can be set on how large of images can be requested from the server. Default value is 2048

foresight.options.forcedPixelRatio: You can override the device pixel ratio value. Default value is undefined

Additionally, the foresight.options configurations can be overridden by each individual img element if need be. See the Img Attributes section for more information on individual configuration.

Img Attributes

data-src: (Required) The src attribute of the image, which is the location image on the server. Note that the img element should not set the src attribute, but instead it sets a data-src attribute.

data-width: (Required) The pixel width according to the browser. Any adjustments to the device pixel ratio will take care of the request image width automatically. Both data-width and data-height are required so we can always proportionally scale the image.

data-height: (Required) The pixel height according to the browser. Any adjustments to the device pixel ratio will take care of the request image height automatically. Both data-width and data-height are required so we can always proportionally scale the image.

data-src-modification: (Optional) Which type of src modification to use, either rebuildSrc or replaceDimensions. See the Src Modification section for more info.

data-src-uri-template: (Optional) The URI template in which a src should be rebuilt. See the Src URI Template section for more info.

data-src-high-resolution: (Optional) Alternatively to dynamically building the img's src, you can manually set the data-src-high-resolution attribute which is used when the device is high-resolution enabled. Any device pixel ratio greater than 1 is considered high-resolution. For example, devices with a pixel ratio of 1.5 and 2 will both receive the same image.

data-width-percent: (Optional) The width percent is in reference to the image's parent element, and how much of the image's parent element's width should be taken by the image. The image's previous data-width attribute should not be given percents because its value is reserved so we can always know the image's aspect ratio. The data-width-percent attribute, on the other hand, is an optional attribute that determines how to scale the image within its parent element.

data-height-percent: (Optional) The height percent is in reference to the image's parent element, and how much of the image's parent element's width should be taken by the image. The image's previous data-height attribute should not be given percents because its value is reserved so we can always know the image's aspect ratio. The data-height-percent attribute, on the other hand, is an optional attribute that determines how to scale the image within its parent element.

data-max-width: (Optional) Maximum browser pixel width this image should take. If this value is greater than the width it will scale the image proportionally.

data-max-height: (Optional) Maximum browser pixel height this image should take. If this value is greater than the height it will scale the image proportionally.

data-max-request-width: (Optional) Maximum pixel width this image should request. If this value is greater than the width it will scale the image request dimensions proportionally.

data-max-request-height: (Optional) Maximum pixel height this image should request. If this value is greater than the height it will scale the image request dimensions proportionally.

data-pixel-ratio: (Optional) By default an image's pixel ratio is figured out using the devices pixel ratio. You can however manually assign an image's pixel ratio which will override the default.

Foresight.js Properties

After foresight.js executes there are a handful of properties viewable.

foresight.images: An array containing each of the foresight.js img elements.

foresight.devicePixelRatio: The device's pixel ratio used by foresight. If the browser does not know the pixel ratio, which older browsers will not, the devicePixelRatio defaults to 1.

foresight.connTestResult: The connection test result provides info on how the device received its speed-test information. Below are the possible values:

  • networkSuccess: The speed test information came directly from a network test.
  • networkSlow: A 50KB file should be downloaded within 1 second on a 400Kbps connection. If the speed test takes longer than 1 second than we already know its not a high-speed connection. Instead of waiting for the response, just continue and set that this network connection is not a high-speed connection.
  • networkError: When a speed-test network error occurs, such as a 404 response, the connTestMethod will equal networkError and will not be considered a high-speed connection.
  • localStorage: A speed-test does not need to be executed on every webpage. The browser's localStorage function is used to remember the last speed test information. When the last speed-test falls outside of the foresight.options.speedTestExpireMinutes option it execute a new speed-test again.
  • skip: If the device pixel ratio equals 1 then the display cannot view hi-res images. Since high-resolution doesn't apply to this device, foresight.js doesn't bother testing the network connection.

foresight.connKbps: Number representing the estimated Kbps following a network connection speed-test. This value can also come from localStorage if the last test was within the foresight.options.speedTestExpireMinutes option. Note that foresight.connKbps is not an extremely accurate assessment of the device's connection speed, but rather provides a fast look to see if it can download a file quickly (and then remembers that test info for a configurable number of minutes).

foresight.isHighSpeedConn: Boolean used to tell foresight.js if this device's connection is considered a high-speed connection or not. You can use the foresight.options.minKbpsForHighSpeedConn configuration option to help determine what is considered high-speed. See the minKbpsForHighSpeedConn config description for more info.

Foresight.js Methods

foresight.reload: Call this method when your code changes the DOM. However, foresight.reload is automatically executed on any window resize event. Take a look at the jQuery Mobile integration and the demos on an example of how it would be used.

jQuery Mobile Integration

Foresight.js does not require the jQuery library or jQuery Mobile framework, but it can still be easily integrated into jQuery Mobile. Below is a sample of what the head element would contain so foresight.js can be used:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
<script src="foresight.js"></script>
<script>
    $(document).bind("pagechange", foresight.reload);
</script>

Notice how it binds the foresight.reload method when a page change happens, this ensures all new images to the DOM are correctly loaded by foresight. Take a look at the jQuery Mobile demo pages to see it in action.

Foresight.js Events

foresight.updateComplete: Executed after foresight.js rebuilds each of the image src's.

Foresight.js Debugging

Instead of including debugging code directly in the foresight.js, an additional javascript file has been included to help developers debug. By using the foresight.updateComplete event and populated foresight properties, the foresight-debug.js file prints out relevant information to help debug. This is particularly useful for mobile devices since it is more difficult to view source code and javascript errors. Below is an example on how to include the foresight-debugger.js file and calling it when foresight.js completes:

<script src="foresight-debugger.js"></script>
<script>
    foresight = {
        options: {
            srcModification: 'rebuildSrc',
            srcUriTemplate: '{directory}{requestWidth}px-{file}'
        },
        updateComplete: foresight_debugger
    };
</script>
<script src="foresight.js"></script>

Testing

Foresight's goal has always been to work on the major browsers, both desktop and mobile, and not require any javascript libraries or frameworks. If you come across any problems please help us by submitting an issue and we'll work to improve it. Below are the primary browsers foresight.js has been tested against.

  • iOS 5.1 (iPad3 & iPhone4)
  • Android 2.3 (Samsung Charge)
  • Chrome 17 (Mac)
  • Chrome 19 (Win)
  • Safari 5.1 (Mac)
  • Firefox 11 (Mac)
  • Firefox 10 (Win)
  • IE8

Contribute

This project was originally created as a need for an ecommerce mobile homepage, which basically showed high-resolution images for high-resolution devices, and adjust image widths accordingly. This is by no means the end-all solution for high-resolution images; I'd label this more as an interim solution as the web standards evolve for handling device pixel ratios. Please feel free to improve this project in any way you can.

Contact Me

License

Copyright (c) 2012 Adam Bradley

Licensed under the MIT license.

About

Foresight.js gives webpages the ability to tell if the user's device is capable of viewing high-resolution images (such as the 3rd generation iPad) before the image is requested from the server. Additionally, it judges if the user's device currently has a fast enough network connection for high-resolution images. Depending on device display and …

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published