Responsive images

About responsive images

Responsive web design is a method of designing websites to provide an optimal viewing experience to users, irrespective of the device, window size, orientation, or resolution used to view it. A site designed responsively adapts its layout to the viewing environment, resizing and moving elements dynamically based on the properties of the browser or device the site is displayed on.

A responsive web design is developed with fluid grids, flexible images and media queries to produce a layout that dynamically adapts to the user’s viewing environment. For images to be flexible, they need to dynamically adjust their resolution (and sometimes format, quality, or even content) on-the-fly. For more information on responsive design and what it entails, see http://responsivewebdesign.com and http://alistapart.com/article/responsive-web-design.

An example of responsive web design:
(Resize this browser window to see how the layout and images below dynamically respond to the changes).

4 columns

4-3-2 grid

3-2-1 grid

When it comes to images, a responsively designed website should not just send a high-resolution image and then use browser resizing to display the image on various devices: that would be a huge waste of bandwidth for users on small, low-resolution displays. The image should be prepared in various resolutions, so that the requesting device can load only the image data that it needs. However, generating multiple, alternate resolutions of each image manually results in complex, time-consuming workflows.

Cloudinary can help reduce the complexity of delivering responsive images, as follows:

Dynamic image manipulation

Cloudinary can help reduce the complexity of maintaining and generating multiple image versions with the dynamic image manipulation feature. You can build Cloudinary dynamic image URLs that include any image width or height you want specified. This means you don't have to pre-create the images, and your images are dynamically resized on-the-fly as needed. This is especially useful when using the <picture> element and the srcset and sizes parameters of the <img> tag where the browser chooses which of the image versions to display. All of the Cloudinary image URLs that you build can also include any of Cloudinary's image transformation parameters, and the images will be created on-the-fly if they don't already exist.

For more information on building a responsive image solution with <img> and <picture> tags, see:

Responsive breakpoint generator

Having too many image versions reduces the number of CDN cache hits for requested images and increases the average delivery time for images to your users. On the other hand, having too few image versions means delivering images to users that are larger than needed for the available width, and end up being scaled down by the browser. Cloudinary's Responsive Breakpoints Generator is an open source tool that can be used to calculate the optimal number of versions needed for every image that balances the number of image versions generated vs. the file size reduction between each version. The set of breakpoints are thus calculated based on a difference in the actual image file size at different widths.

The Responsive Breakpoints Generator enables you to interactively generate responsive image breakpoints. However, for applications that involve user generated content of images dynamically uploaded to your site, you may want to streamline the breakpoints generation process. You can use Cloudinary's API to upload your images to the cloud and automatically generate breakpoints programmatically:

Ruby:
Cloudinary::Uploader.upload("sample.jpg", responsive_breakpoints: { 
  create_derived: true, bytes_step: 20000, min_width: 200, max_width: 1000, transformation: { 
  crop: :fill, aspect_ratio: "16:9", gravity: :auto } } )
PHP:
\Cloudinary\Uploader::upload("sample.jpg", array("responsive_breakpoints" => array( 
  "create_derived" => true, "bytes_step" => 20000, "min_width" => 200, "max_width" => 1000, 
  "transformation" => array( "crop" => "fill", "aspect_ratio" => "16:9", "gravity" => "auto" ))))
Python:
cloudinary.uploader.upload("sample.jpg", responsive_breakpoints = { 
  "create_derived": true, "bytes_step": 20000, "min_width": 200, "max_width": 1000, 
  "transformation": { "crop": "fill", "aspect_ratio": "16:9", "gravity": "auto" } } )
Node.js:
cloudinary.uploader.v2.upload("sample.jpg", { responsive_breakpoints: { 
  create_derived: true, bytes_step: 20000, min_width: 200, max_width: 1000, 
  transformation: { crop: 'fill', aspect_ratio: '16:9', gravity: 'auto' } } }, function(error, result) { console.log(result); });

For more information on requesting breakpoints and possible parameter values, see the responsive breakpoint request settings documentation.

Automating responsive images with JavaScript

Cloudinary provides an automatic JavaScript solution for handling dynamic generation of images that match the required dimensions according to the exact image width available and the DPR (Device Pixel Ratio) of every device. Cloudinary's JavaScript library includes a method that dynamically builds the dynamic image URLs and works as follows:

  • A Cloudinary dynamic manipulation URL is automatically built on-the-fly to deliver an image that is scaled to the exact available width and resolution.
  • If the browser window is consequently enlarged then new higher resolution images are automatically delivered, while using breakpoint steps (every 100px by default) to prevent loading too many images.
  • If the browser window is scaled down, browser-side scaling is used instead of delivering a new image.

This feature allows you to upload one high resolution image to Cloudinary, and have it automatically adapted to the resolution and size appropriate to each user’s device or browser on-the-fly.

Note: The JavaScript solution documented here dynamically replaces dpr_auto and w_auto with the actual values on the client side based on the actual browser settings and window width. The Client-Hints based solution described in the next section, allows you to simplify your code and perform the dynamic decisions on the server side (CDN level) based on Client-Hints, but only for supported browsers.

Step 1: include the Cloudinary JavaScript library

Include the Cloudinary JavaScript library in your HTML pages:

<script
    src="cloudinary-core-shrinkwrap.js" 
    type="text/javascript">
</script>

Note: The cloudinary-core-shrinkwrap.js library is a shrinkwrapped version of the Cloudinary JavaScript library (it is not dependant on lodash). See the JavaScript installation documentation for more information and details on the various JavaScript installation options (all the options include the responsive support as discussed here).

Step 2: set the img tag parameters

For each image to display responsively:

  1. Set the data-src attribute of the img tag to the URL of an image that was uploaded to Cloudinary. There is no need to set the src attribute of the img tag as it is updated dynamically. However, you can optionally set the src attribute to a placeholder image that is displayed until the image is loaded.
  2. Set the width parameter to auto and the crop parameter to scale (w_auto, c_scale in URLs). This allows the jQuery plugin to dynamically generate an image URL scaled to the correct width value, based on the detected width actually available for the image in the containing element.
  3. Add the cld-responsive class to the image tag. This is the default class name, but you can use custom class names and programmatically make HTML elements become responsive.

For example:

<img 
    data-src="https://res.cloudinary.com/demo/image/upload/w_auto,c_scale/smiling_man.jpg" 
    class="cld-responsive">

Step 3: call the Cloudinary responsive method

Add a call to Cloudinary's responsive JavaScript method at the end of the HTML page.

<script type="text/javascript">
    var cl = cloudinary.Cloudinary.new({cloud_name: "demo"}); 
    // replace 'demo' with your cloud name in the line above 
    cl.responsive();
</script>

The responsive method looks for all images in the page that have the "cld-responsive" class name, detects the available width for the image on the page, and then updates the HTML image tags accordingly. The image is also updated whenever the window size or screen resolution changes.

Note: the process presented above covers the simplest and most general solution. The behavior can be further customized to control whether to update images on resize, when to update the image using stop-points, preserving the CSS image height, and more. For details, see Cloudinary JavaScript library.

SDK support

To make things even easier, the JavaScript responsive design can be implemented with the Cloudinary SDK's helper methods (e.g. cl_image_tag in Ruby on Rails). Setting the width parameter to auto and the crop parameter to scale creates an HTML image tag with a blank src attribute while the data-src attribute points to a dynamic image manipulation URL. When you load Cloudinary's JavaScript library and call the responsive method, the image tags are automatically updated and the image URLs are replaced with new URLs that include the updated width values. You can also set a placeholder image using the responsive_placeholder parameter, or set it to an inline blank image by setting the parameter to blank.

For example, creating an HTML image tag for the "smiling_man.jpg" image with the width automatically determined on-the-fly as needed, and using a blank image placeholder:

Ruby:
cl_image_tag("smiling_man.jpg", :width => :auto, :crop => :scale, :responsive => :true,
  :responsive_placeholder => "blank")
PHP:
cl_image_tag("smiling_man.jpg",  array("width" => "auto", "crop" => "scale", 
  "responsive" => "true",  "responsive_placeholder" => "blank"));
Python:
cloudinary.CloudinaryImage("smiling_man.jpg").image(width = "auto", responsive = "true",
  crop = "scale", responsive_placeholder = "blank")
Node.js:
cloudinary.image("smiling_man.jpg",  { width: "auto", responsive: "true",
  crop: "scale", responsive_placeholder: "blank" })
Java:
cloudinary.url().transformation(new Transformation().width("auto").responsive("true").
  crop("scale").responsive_placeholder("blank")).imageTag("smiling_man.jpg");

The code above generates the following HTML image tag:

<img 
    class="cld-responsive" 
    data-src="https://res.cloudinary.com/demo/image/upload/w_auto,c_scale/smiling_man.jpg"
    src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"  />

Responsive design with support for retina and HiDPI devices

In addition to automating the width, you can also create the correct DPR image for devices that support higher resolutions by setting the dpr parameter to auto in the URL or SDK method. The JavaScript code will check the DPR of the device as well as the space available for the image. Delivery and manipulation URLs are then built automatically (and lazily) for all image tags to match the specific settings, with all image generation happening in the cloud. Users of devices with high pixel density will get a great visual result, while low-DPR users don't have to wait needlessly for larger images to load (see this blog post for more details).

For example, creating an HTML image tag for the "woman.jpg" image with the width and DPR automatically determined on-the-fly as needed, and using a blank image placeholder:

Ruby:
cl_image_tag("woman.jpg", :width => :auto,  :dpr => :auto, :responsive => :true,
  :crop => "scale", :responsive_placeholder => "blank")
PHP:
cl_image_tag("woman.jpg",  array("width" => "auto",  "dpr" => "auto", "responsive" => "true",
  "crop" => "scale", "responsive_placeholder" => "blank"));
Python:
cloudinary.CloudinaryImage("woman.jpg").image(width = "auto", dpr = "auto", 
  crop = "scale", responsive = "true", responsive_placeholder = "blank")
Node.js:
cloudinary.image("woman.jpg",  { width: "auto", dpr: "auto", responsive: "true",
  crop: "scale", responsive_placeholder: "blank" })
Java:
cloudinary.url().transformation(new Transformation().width("auto").dpr("auto").responsive("true"). 
  crop("scale").responsive_placeholder("blank")).imageTag("woman.jpg");

The code above generates the following HTML image tag:

<img class="cld-responsive" 
    data-src="https://res.cloudinary.com/demo/image/upload/w_auto,dpr_auto,c_scale/woman.jpg"
    src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"  />

Overriding default values

By default, the responsive method uses a breakpoint steps value of 100 pixels, and always uses the breakpoints to determine the width. These values can be overridden by using the config method to pass new values for the breakpoints and responsive_use_breakpoints parameters as follows:

breakpoints: A function or set of values to be used when resizing the browser window and a larger image needs to be delivered. For example:

  • a function to set the breakpoints steps to every 50 pixels:

    defaultBreakpoints = function(width) {  // width - the current width of the containing element
      return 50 * Math.ceil(width / 50);
    };
  • an array of values:

    defaultBreakpoints = [50, 90, 130, 170, 200, 300, 450, 550, 700, 850, 1000];

responsive_use_breakpoints: A string value determining when to use the breakpoint steps:

  • true - (default) always use breakpoints for width.
  • resize - use the exact width of the containing element on initial render, then proceed with breakpoints.
  • false - always use the containing element's width.

Both of the above parameters need to be passed with the config method. For example, calling to Cloudinary's responsive JavaScript method at the end of the HTML page, and also configuring the breakpoints step to every 50 pixels and to use the exact width of the containing element on initial render:

<script type="text/javascript">
    my_breakpoints = function (width){  // width - the current width of the containing element
      return 50 * Math.ceil(width / 50);
    }
    var cl = cloudinary.Cloudinary.new({cloud_name: "demo"}); 
    // replace 'demo' with your cloud name in the line above 
    cl.config({breakpoints:my_breakpoints, responsive_use_breakpoints:"resize"})
    cl.responsive();
</script>

Automating responsive images with Client Hints

Client-Hints is a technology that allows web browsers to inform servers (or CDN layers) of the required dimensions and pixel densities of each specific image download request. Taking advantage of this feature can allow a single dynamic Cloudinary URL to actually return different image sizes according to the specific needs of the responsive website in every user's device and browser. Browsers that support Client-Hints (already supported by Chrome, Android Browser and Opera) will send hints as HTTP request headers if this behavior is enabled for their websites. The relevant hints for automating responsive images are the DPR (Device Pixel Ratio) value, the Width available for the specific image in the responsive layout, and the Viewport-Width of the browser's window.

Note: The JavaScript based solution described above, dynamically replaces dpr_auto and w_auto with the actual values on the client side based on the actual browser settings and window width. The automatic features documented here allow you to simplify your code and perform the dynamic decisions on the server side (CDN level) based on Client-Hints, but only for supported browsers.

The HTML page must also have Client-Hints enabled, which can be easily accomplished by using Cloudinary's SDKs and adding the client_hints_meta_tag to the page or by manually adding the following line to your HTML page:

<meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width">

Using Client Hints, Cloudinary is informed about the layout width of an image on a user’s device and the pixel density of their screen. Cloudinary can then decide on the size of the image the browser needs for displaying to the user, and select and deliver an optimal resource – all at the CDN level.

For example, to deliver the sample image automatically scaled to the width available for the image in the responsive layout:

Ruby:
cl_image_tag("sample.jpg", :width => :auto, :client_hints => :true, :crop => "scale",
  :sizes => "100vw")
PHP:
cl_image_tag("sample.jpg",  array("width" => "auto", "client_hints" => "true",
  "crop" => "scale", "sizes" => "100vw"));
Python:
cloudinary.CloudinaryImage("sample.jpg").image(width = "auto", crop = "scale",
  client_hints = "true", sizes = "100vw")
Node.js:
cloudinary.image("sample.jpg",  { width: "auto", client_hints: "true", crop: "scale",
  sizes: "100vw" })
Java:
cloudinary.url().transformation(new Transformation().width("auto").client_hints("true").crop("scale").sizes("100vw")).imageTag("sample.jpg");

The code above generates the following HTML image tag:

<img 
    src="https://res.cloudinary.com/demo/image/upload/w_auto,c_scale/sample.jpg"
    sizes="100vw"  />

Cloudinary automatically adapts the image to fit the viewport, layout and resolution on any device, ensuring a visually-seamless user experience while improving performance, using one of the following options:

Automatic pixel density detection

To deliver an image in a resolution that automatically matches the DPR (Device Pixel Ratio) setting of the user's device, set the client_hints parameter to true and the dpr transformation parameter to auto (dpr_auto in URLs). The device's DPR value is received at the CDN level and rounded up to the nearest integer in order to avoid creating extra derived images and consuming extra transformations (e.g., a DPR value of 1.5 will be rounded up to 2.0).

For example, to deliver the sample image filled to a width of 300 pixels, a height of 200 pixels, and with a DPR value suitable for the user's device:

Ruby:
cl_image_tag("sample.jpg", :width=>300, :height=>200, :dpr=>"auto", :crop=>"fill", :client_hints=>true)
PHP:
cl_image_tag("sample.jpg", array("width"=>300, "height"=>200, "dpr"=>"auto", "crop"=>"fill", "client_hints"=>true))
Python:
CloudinaryImage("sample.jpg").image(width=300, height=200, dpr="auto", crop="fill", client_hints=True)
Node.js:
cloudinary.image("sample.jpg", {width: 300, height: 200, dpr: "auto", crop: "fill", client_hints: true})
Java:
cloudinary.url().transformation(new Transformation().width(300).height(200).dpr("auto").crop("fill")).clientHints(true).imageTag("sample.jpg")
JS:
cl.imageTag('sample.jpg', {width: 300, height: 200, dpr: "auto", crop: "fill", client_hints: true}).toHtml();
jQuery:
$.cloudinary.image("sample.jpg", {width: 300, height: 200, dpr: "auto", crop: "fill", client_hints: true})
React:
<Image publicId="sample.jpg" client_hints="true">
  <Transformation width="300" height="200" dpr="auto" crop="fill" />
</Image>
Angular:
<cl-image public-id="sample.jpg" client_hints="true">
  <cl-transformation width="300" height="200" dpr="auto" crop="fill">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Width(300).Height(200).Dpr("auto").Crop("fill")).ClientHints(true).BuildImageTag("sample.jpg")
Android:
MediaManager.get().url().transformation(new Transformation().width(300).height(200).dpr("auto").crop("fill")).clientHints(true).generate("sample.jpg")

Notes:

  • The CDN returns a Vary response header set to DPR in order to allow the same URL to be cached differently for each DPR value.
  • If Client-Hints are not supported by the user's browser or if they are not available, a URL with dpr_auto will be treated as dpr_1.0.

Automatic image width

(Note: For customers with a custom domain name or private CDN distribution, contact us to setup this feature).

To deliver an image automatically scaled to a width that matches the width available for the image in the responsive layout, set the:

  • width parameter to auto,
  • crop parameter to scale,
  • client_hints parameter to true,
  • sizes parameter to 100vw (this is the most common value to set, i.e., 100% of the available width, but you can give any value that the HTML sizes attribute accepts).

The width of the image is received at the CDN level and then rounded up in order to avoid creating extra derived images and consuming too many extra transformations. By default, the rounding up is made in steps of 100 pixels (e.g., 347 will be rounded up to 400 and w_auto in this case will be treated as w_400). To round up in steps of a different number of pixels, a numeric value can be appended to the auto value, separated with a colon. For example, w_auto:50 means rounding up in steps of 50 pixels: 347 will be rounded up to 350 and w_auto:50 in this case will be treated as w_350.

For example, to deliver the sample image automatically scaled to the width available for the image in the responsive layout:

Ruby:
cl_image_tag("sample.jpg", :width => :auto, :client_hints => :true, :crop => "scale",
  :sizes => "100vw")
PHP:
cl_image_tag("sample.jpg",  array("width" => "auto", "client_hints" => "true",
  "crop" => "scale", "sizes" => "100vw"));
Python:
cloudinary.CloudinaryImage("sample.jpg").image(width = "auto", crop = "scale",
  client_hints = "true", sizes = "100vw")
Node.js:
cloudinary.image("sample.jpg",  { width: "auto", client_hints: "true", crop: "scale",
  sizes: "100vw" })
Java:
cloudinary.url().transformation(new Transformation().width("auto").client_hints("true").crop("scale").sizes("100vw")).imageTag("sample.jpg");

The code above generates the following HTML image tag:

<img 
    src="https://res.cloudinary.com/demo/image/upload/w_auto,c_scale/sample.jpg"
    sizes="100vw"  />

To avoid delivering large images, no matter what the width available for the image, a limit transformation can be chained with the w_auto transformation. For example, to deliver the sample image filled to an aspect ratio of 16:9 and then automatically scaled to the width available for the image in the responsive layout (up to a maximum width of 1000 pixels):

Ruby:
cl_image_tag("sample.jpg", :client_hints=>true, :sizes=>"100vw", :transformation=>[
  {:aspect_ratio=>"16:9", :crop=>"fill"},
  {:width=>"auto", :crop=>"scale"},
  {:width=>1000, :crop=>"limit"}])
PHP:
cl_image_tag("sample.jpg", 
  array("client_hints"=>true, "sizes"=>"100vw", "transformation"=>array(
    array("aspect_ratio"=>"16:9", "crop"=>"fill"),
    array("width"=>"auto", "crop"=>"scale"),
    array("width"=>1000, "crop"=>"limit"))))
Python:
CloudinaryImage("sample.jpg").image(client_hints=True, sizes="100vw", transformation=[
  {"aspect_ratio": "16:9", "crop": "fill"},
  {"width": "auto", "crop": "scale"},
  {"width": 1000, "crop": "limit"}
])
Node.js:
cloudinary.image("sample.jpg", {client_hints: true, sizes: "100vw", transformation: [
  {aspect_ratio: "16:9", crop: "fill"},
  {width: "auto", crop: "scale"},
  {width: 1000, crop: "limit"}
]})
Java:
cloudinary.url().transformation(new Transformation()
  .aspectRatio("16:9").crop("fill").chain()
  .width("auto").crop("scale").chain()
  .width(1000).crop("limit")).clientHints(true).sizes("100vw").imageTag("sample.jpg"))

The code above generates the following HTML image tag:

<img 
    src="https://res.cloudinary.com/demo/image/upload/ar_16:9,c_fill/c_scale,w_auto/c_limit,w_1000/sample.jpg"
    sizes="100vw"  />

Notes:

  • The CDN returns a Vary response header set to Width, DPR in order to allow the same URL to be cached differently for each Width and DPR value.
  • If Client-Hints are not supported by the user's browser or if they are not available, by default w_auto will be treated as if no scaling is requested. This might mean delivering the original hi-res image dimensions, which is equivalent to omitting the width parameter altogether. You can bypass this default behavior by specifying a default (fallback) value for the width that is only used if the information cannot be retrieved from a Client-Hints header. This default width value can be concatenated to the transformation value: e.g., w_auto:40:360 means that Cloudinary will use a rounding step of 40 pixels, and in the absence of a Width hint from the browser, it will substitute a default value of 360.

Strict transformations and signed URLs

To support strict transformations and signed URLs, the explicit pixels step value has to be specified and included in the signed value of the width parameter. e.g., w_auto:100 (i.e., there is no default value in this case and the pixels step value must be explicitly included in the parameter value). The CDN layer will send the original requested path (e.g., /w_auto:100/sample.jpg) together with the actual required rounded up width (e.g., w_400). Cloudinary's service will validate the signature according to original requested width rather than according to the actual required image width (e.g., w_auto:100 instead of w_400).

Automatic image width using optimal responsive breakpoints

Important: This feature requires a private CDN distribution or CNAME, which is available for Cloudinary's Advanced plan and above. Contact us to setup this feature.

The automatic width feature can be further enhanced using Cloudinary's intelligent responsive breakpoints generation feature. Arbitrarily rounding up the width value in constant steps (e.g., 100 pixels) does not optimize the process of reducing the file size vs. the number of images generated. Having too many image versions reduces the number of CDN cache hits for requested images and increases the average delivery time for images to your users. On the other hand, having too few image versions means delivering images to users that are larger than needed for the available width, and end up being scaled down by the browser.

Cloudinary can calculate the set of optimal rounding up steps, or breakpoints, by determining the optimal number of versions for every image that balances the number of image versions generated vs. the file size reduction between each version. The set of breakpoints are thus calculated based on a difference in the actual image file size at different widths.

To automatically determine the optimal width values of each image, individually set the:

  • width parameter to auto:breakpoints,
  • crop parameter to scale,
  • client_hints parameter to true,
  • sizes parameter to 100vw (this is the most common value to set, i.e., 100% of the available width, but you can give any value that the HTML sizes attribute accepts).

Cloudinary performs the breakpoints calculation and then rounds up the generated image width to the closest optimal breakpoint.

For example, to deliver the bike image filled to an aspect ratio of 16:9 (ar_16:9,c_fill) and then automatically scaled to the closest optimal breakpoint that is larger than the width available for the image in the responsive layout, where the optimal breakpoints are calculated using the default breakpoint request values (c_scale,w_auto:breakpoints):

Ruby:
cl_image_tag("bike.jpg", :client_hints=>true, :sizes=>"100vw", :transformation=>[
  {:aspect_ratio=>"16:9", :crop=>"fill"},
  {:width=>"auto:breakpoints", :crop=>"scale"}])
PHP:
cl_image_tag("bike.jpg", 
  array("client_hints"=>true, "sizes"=>"100vw", "transformation"=>array(
    array("aspect_ratio"=>"16:9", "crop"=>"fill"),
    array("width"=>"auto:breakpoints", "crop"=>"scale"))))
Python:
CloudinaryImage("bike.jpg").image(client_hints=True, sizes="100vw", transformation=[
  {"aspect_ratio": "16:9", "crop": "fill"},
  {"width": "auto:breakpoints", "crop": "scale"}])
Node.js:
cloudinary.image("bike.jpg", {client_hints: true, sizes: "100vw", transformation: [
  {aspect_ratio: "16:9", crop: "fill"},
  {width: "auto:breakpoints", crop: "scale"}]})
Java:
cloudinary.url().transformation(new Transformation()
  .aspectRatio("16:9").crop("fill").chain()
  .width("auto:breakpoints").crop("scale")
  .clientHints(true).sizes("100vw").imageTag("bike.jpg"))

The code above generates the following HTML image tag:

<img 
    src="https://res.cloudinary.com/demo/image/upload/ar_16:9,c_fill/c_scale,w_auto:breakpoints/bike.jpg"
    sizes="100vw"  />

Assuming (for the example above) that the Client-Hints request header returns a width of 347, and Cloudinary has calculated that the set of optimal breakpoints for this image are as follows: 50, 238, 356, 450, 542, 621, 692, 764, 834, 901, 955, 1000. Then the selected breakpoint from the set will be 356 pixels (the first breakpoint greater than 347), and the delivery URL will be treated as ar_16:9,c_fill/c_scale,w_356.

Breakpoints generation settings:

  • Global breakpoints settings are applied with their default values as follows: min_width=50, max_width=1000, bytes_step=20KB, max_images=20. For more information on these settings and possible values, see the responsive breakpoint request settings documentation.
  • The default settings can be overridden using a dynamic URL that includes the new values: auto:breakpoints_[min_width]_[max_width]_[bytes_step_in_KBs]_[max_images] e.g., w_auto:breakpoints_200_1920_30_15.
  • All 4 of the breakpoint request settings parameters must be included if you need to override any of them.

For example, to deliver the bike image filled to an aspect ratio of 16:9 and then automatically scaled to the closest optimal breakpoint, where the optimal breakpoints are calculated using the following breakpoint request values - min_width=200, max_width=1920, bytes_step=30, max_images=15:

Ruby:
cl_image_tag("bike.jpg", :client_hints=>true, :sizes=>"100vw", :transformation=>[
  {:aspect_ratio=>"16:9", :crop=>"fill"},
  {:width=>"auto:breakpoints_200_1920_30_15", :crop=>"scale"}])
PHP:
cl_image_tag("bike.jpg", 
  array("client_hints"=>true, "sizes"=>"100vw", "transformation"=>array(
    array("aspect_ratio"=>"16:9", "crop"=>"fill"),
    array("width"=>"auto:breakpoints_200_1920_30_15", "crop"=>"scale"))))
Python:
CloudinaryImage("bike.jpg").image(client_hints=True, sizes="100vw", transformation=[
  {"aspect_ratio": "16:9", "crop": "fill"},
  {"width": "auto:breakpoints_200_1920_30_15", "crop": "scale"}])
Node.js:
cloudinary.image("bike.jpg", {client_hints: true, sizes: "100vw", transformation: [
  {aspect_ratio: "16:9", crop: "fill"},
  {width: "auto:breakpoints_200_1920_30_15", crop: "scale"}]})
Java:
cloudinary.url().transformation(new Transformation()
  .aspectRatio("16:9").crop("fill").chain()
  .width("auto:breakpoints_200_1920_30_15").crop("scale")
  .clientHints(true).sizes("100vw").imageTag("bike.jpg"))

The code above generates the following HTML image tag:

<img 
    src="https://res.cloudinary.com/demo/image/upload/ar_16:9,c_fill/c_scale,w_auto:breakpoints_200_1920_30_15/bike.jpg"
    sizes="100vw"  />

Default value for browsers that don't support Client-Hints

If Client-Hints are not supported by the user's browser or if they are not available, by default w_auto:breakpoints will be treated as if no scaling is requested. This might mean delivering the original hi-res image dimensions which is equivalent to omitting the width parameter altogether. You can bypass this behavior by specifying a default value for the width that is only used if the information cannot be retrieved from a Client-Hints header. This default width value can be concatenated to the transformation value, separated with a colon.

For example:

w_auto:breakpoints:500 tells Cloudinary to:

  • Scale the image to the closest calculated breakpoint based on the width retrieved from the Client-Hints header, or
  • Scale the image to the closest calculated breakpoint based on a default value of 500 pixels for the width, if the actual available width cannot be retrieved from a Client-Hints header (i.e., as if the Client-Hints header had returned a value of 500 for the width).

Calculated breakpoints delivery URL

Dynamic applications (e.g., JavaScript-based applications) can request that Cloudinary deliver the set of calculated breakpoints for an image instead of the transformed image itself. To request a JSON response containing the set of calculated breakpoints, set the width transformation parameter to auto:breakpoints:json. The breakpoints' JSON URLs are treated in a similar way to all other derived resources and are cached at the CDN layer like any derived image or file.

For example, to return the set of calculated breakpoints for the bike image filled to an aspect ratio of 16:9:

Ruby:
cl_image_tag("bike.jpg", :use_root_path=>true, :client_hints=>true, :transformation=>[
  {:aspect_ratio=>"16:9", :crop=>"fill"},
  {:width=>"auto:breakpoints:json", :crop=>"scale"}
  ])
PHP:
cl_image_tag("bike.jpg", array("use_root_path"=>true, "client_hints"=>true, "transformation"=>array(
  array("aspect_ratio"=>"16:9", "crop"=>"fill"),
  array("width"=>"auto:breakpoints:json", "crop"=>"scale")
  )))
Python:
CloudinaryImage("bike.jpg").image(use_root_path=True, client_hints=True, transformation=[
  {"aspect_ratio": "16:9", "crop": "fill"},
  {"width": "auto:breakpoints:json", "crop": "scale"}
  ])
Node.js:
cloudinary.image("bike.jpg", {use_root_path: true, client_hints: true, transformation: [
  {aspect_ratio: "16:9", crop: "fill"},
  {width: "auto:breakpoints:json", crop: "scale"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .aspectRatio("16:9").crop("fill").chain()
  .width("auto:breakpoints:json").crop("scale")).clientHints(true).useRootPath(true).imageTag("bike.jpg")
JS:
cl.imageTag('bike.jpg', {use_root_path: true, client_hints: true, transformation: [
  {aspect_ratio: "16:9", crop: "fill"},
  {width: "auto:breakpoints:json", crop: "scale"}
  ]}).toHtml();
jQuery:
$.cloudinary.image("bike.jpg", {use_root_path: true, client_hints: true, transformation: [
  {aspect_ratio: "16:9", crop: "fill"},
  {width: "auto:breakpoints:json", crop: "scale"}
  ]})
React:
<Image publicId="bike.jpg" use_root_path="true" client_hints="true">
  <Transformation aspect_ratio="16:9" crop="fill" />
  <Transformation width="auto:breakpoints:json" crop="scale" />
</Image>
Angular:
<cl-image public-id="bike.jpg" use_root_path="true" client_hints="true">
  <cl-transformation aspect_ratio="16:9" crop="fill">
  </cl-transformation>
  <cl-transformation width="auto:breakpoints:json" crop="scale">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .AspectRatio("16:9").Crop("fill").Chain()
  .Width("auto:breakpoints:json").Crop("scale")).UseRootPath(true).ClientHints(true).BuildImageTag("bike.jpg")
Android:
MediaManager.get().url().transformation(new Transformation()
  .aspectRatio("16:9").crop("fill").chain()
  .width("auto:breakpoints:json").crop("scale")).clientHints(true).useRootPath(true).generate("bike.jpg")

Returned JSON example:

{"breakpoints":[50,238,356,450,542,621,692,764,834,901,955,1000]}

Combining responsive automation with other Cloudinary features

Cloudinary offers a number of automation features that can be combined with your responsive image solution and allow you to implement advanced responsive design and art directed responsive images:

Responsive images with automatic format selection

You can use the fetch_format feature in conjunction with automatic width and/or dpr to save bandwidth and optimize delivery time by automatically delivering images as WebP to Chrome browsers or JPEG-XR to Internet Explorer browsers. Set the fetch_format value to auto and the best format will be delivered to the supported browser. If a browser does not support either of these formats then the image is delivered in the format specified by the file extension.

For example, the uploaded image named sample scaled to the available width and delivered as WebP to Chrome browsers, JPEG-XR to Internet Explorer browsers, or as a regular JPEG to browsers that support neither format:

Ruby:
cl_image_tag("sample.jpg", :width => :auto, :client_hints => :true, :crop => "scale",
  :fetch_format => :auto, :sizes => "100vw")
PHP:
cl_image_tag("sample.jpg",  array("width" => "auto", "client_hints" => "true",
  "crop" => "scale", "fetch_format" => "auto", "sizes" => "100vw"));
Python:
cloudinary.CloudinaryImage("sample.jpg").image(width = "auto", crop = "scale",
  client_hints = "true", fetch_format = "auto", sizes = "100vw")
Node.js:
cloudinary.image("sample.jpg",  { width: "auto", client_hints: "true", crop: "scale",
  fetch_format: "auto", sizes: "100vw" })
Java:
cloudinary.url().transformation(new Transformation().width("auto").client_hints("true").crop("scale")
  .fetchFormat("auto").sizes("100vw")).imageTag("sample.jpg");

The code above generates the following HTML image tag:

<img 
    src="https://res.cloudinary.com/demo/image/upload/w_auto,f_auto,c_scale/sample.jpg"
    sizes="100vw"  />

For more information and details on the automatic format feature see the Automatic format selection documentation.

Responsive images with automatic quality selection

Cloudinary's intelligent quality and encoding algorithm analyzes an image to find the best quality compression level and optimal encoding settings based on both the image content and the image format, in order to produce an image with good visual quality while minimizing the file size. Cloudinary automates the file size versus quality trade-off decision, on-the-fly using perceptual metrics and heuristics that tune the quality settings based on the specific image content and format. Analyzing every image individually to find the optimal compression level and image encoding settings allows for precise adjustment of the compression level complemented by fine tuning of the encoding settings, and can significantly reduce the file size without any degradation noticeable to the human eye.

The quality transformation parameter can be set to auto (q_auto in URLs) to perform automatic quality selection and image encoding adjustments.

For example, the uploaded image named sample scaled to the available width and with automatic quality selection:

Ruby:
cl_image_tag("sample.jpg", :width => :auto, :client_hints => :true, :crop => "scale",
  :quality => :auto, :sizes => "100vw")
PHP:
cl_image_tag("sample.jpg",  array("width" => "auto", "client_hints" => "true",
  "crop" => "scale", "quality" => "auto", "sizes" => "100vw"));
Python:
cloudinary.CloudinaryImage("sample.jpg").image(width = "auto", crop = "scale",
  client_hints = "true", quality = "auto", sizes = "100vw")
Node.js:
cloudinary.image("sample.jpg",  { width: "auto", client_hints: "true", crop: "scale",
  quality: "auto", sizes: "100vw" })
Java:
cloudinary.url().transformation(new Transformation().width("auto").client_hints("true").crop("scale")
  .quality("auto").sizes("100vw")).imageTag("sample.jpg");

The code above generates the following HTML image tag:

<img 
    src="https://res.cloudinary.com/demo/image/upload/w_auto,q_auto,c_scale/sample.jpg"
    sizes="100vw"  />

For more information and details on the automatic quality feature, see Automatic quality and encoding settings.

Responsive images with automatic gravity selection

Cloudinary's intelligent cropping capabilities ensure that the most interesting areas of each image are included in the resulting derived image, not only for photos with faces, but for any content type. Each image is analyzed individually to find the optimal region to focus on while cropping, with priority given to automatically detected faces (by default) while analyzing the image content.

This feature is especially useful for art directing responsive images, where the image is not merely scaled up or down. Art directed images’ content is cropped or otherwise visually altered in different viewing contexts. For example, merely scaling down an image to fit on a small screen might mean that it becomes difficult to make out an important detail in the image (like recognizing a face), and it would be better to display an image that is "zoomed in" on that region of interest.

The Cloudinary content-aware cropping algorithm uses a combination of heuristics to automatically detect the region of interest in every image and then crop them on-the-fly. Automatic cropping is supported by setting the gravity transformation parameter to auto (g_auto in URLs).

For example, the uploaded image named sample automatically filled to the available width and with automatic gravity selection:

Ruby:
cl_image_tag("sample.jpg", :width => :auto, :client_hints => :true, :crop => "fill",
  :gravity => :auto, :sizes => "100vw")
PHP:
cl_image_tag("sample.jpg",  array("width" => "auto", "client_hints" => "true",
  "crop" => "fill", "gravity" => "auto", "sizes" => "100vw"));
Python:
cloudinary.CloudinaryImage("sample.jpg").image(width = "auto", crop = "fill",
  client_hints = "true", gravity = "auto", sizes = "100vw")
Node.js:
cloudinary.image("sample.jpg",  { width: "auto", client_hints: "true", crop: "fill",
  gravity: "auto", sizes: "100vw" })
Java:
cloudinary.url().transformation(new Transformation().width("auto").client_hints("true").crop("fill")
  .gravity("auto").sizes("100vw")).imageTag("sample.jpg");

The code above generates the following HTML image tag:

<img 
    src="https://res.cloudinary.com/demo/image/upload/w_auto,g_auto,c_fill/sample.jpg"
    sizes="100vw"  />

For more information and details on the automatic gravity feature see the Automatic gravity selection documentation.

Responsive images - additional resources

Blog posts:

Tools:

Webinars:

External resources: