Breakpoints and Responsive Images
|
This content was generated with the assistance of AI and should be verified against the official Drupal documentation before being relied on in production. This sub-section’s Drupal bibliography lists the reference material consulted while preparing these pages. |
A phone, a laptop and a gallery wall display need different pixels from the same photograph. Drupal solves this in two steps. A theme (or a module) declares breakpoints in a YAML file, and the core Responsive Image module maps those breakpoints to image styles and renders markup that lets the browser pick the right file. This page was checked against the official documentation on 2026-10-30 and is written for Drupal 11.4.x, PHP 8.3 or later and Drush 13 or 14. Drupal 10 ends on 2026-12-09 and Drupal 12.0.0 is planned for the week of 2026-12-07, so new sites should start on Drupal 11. Everything here applies to both lines unless a version is named.
The examples belong to the Meridian Museum scenario: the theme meridian shows a wide hero photograph on each
exhibition and a grid of square object photographs for the collection (meridian_collection). The image styles that the
responsive styles map to are created as described in
Display modes and image styles, which also covers lazy loading of
the plain Image formatter and format conversion; this page does not repeat that material.
The pieces and who uses them
| Piece | What it does | Who works with it |
|---|---|---|
|
Declares named media queries, their order and the pixel-density multipliers they support. There is no screen for it. |
Themer |
Breakpoint module (core) |
Reads those files from all enabled themes and modules and exposes them as breakpoint groups. |
Developer (API), invisible to editors |
Responsive Image module (core) |
Provides the responsive image style configuration entity, its administration screen and the Responsive image field formatter. |
Site builder |
Image styles (core Image module) |
Produce the actual resized files (the derivatives) that the mapping refers to. |
Site builder |
Field formatter or Twig/render array |
Chooses which responsive style renders an image in a view mode, a view or custom markup. |
Site builder, themer |
The Responsive Image module depends on the Breakpoint and Image modules, so enabling it enables them. Enable it with
drush pm:install responsive_image (or drush en responsive_image) and export the result with the rest of the
configuration, see Configuration management.
Declaring breakpoints: THEME.breakpoints.yml
A theme or module that wants its breakpoints known to Drupal places a file named after itself in its root directory:
meridian.breakpoints.yml in the theme meridian, or meridian_collection.breakpoints.yml in a module. The official
documentation states that Drupal offers no user interface for editing breakpoints; the file is the only place. A new
file is only discovered after a cache rebuild (drush cache:rebuild).
Each entry is keyed by a machine identifier and has these keys:
| Key | Meaning |
|---|---|
|
Human-readable name. It is shown in the responsive image style form. |
|
The media query text. An empty string means "no query" and is typical for the smallest, mobile-first breakpoint. |
|
The order. Breakpoints with smaller minimum widths get smaller weights. Modules usually sort from the smallest to the largest, though a consumer can reverse this, and the Responsive Image module orders its mappings with the breakpoint weight and then the multiplier. |
|
The device-pixel-ratio multipliers the breakpoint supports. The Breakpoint module itself defines |
|
Optional. When omitted the group is the name of the theme or module that declares the file. |
# web/themes/custom/meridian/meridian.breakpoints.yml
meridian.mobile:
label: Mobile
mediaQuery: ''
weight: 0
multipliers:
- 1x
- 2x
meridian.tablet:
label: Tablet
mediaQuery: 'all and (min-width: 48em)'
weight: 1
multipliers:
- 1x
- 2x
meridian.desktop:
label: Desktop
mediaQuery: 'all and (min-width: 75em)'
weight: 2
multipliers:
- 1x
- 2x
Identifiers and groups
A breakpoint identifier is the theme or module name, a dot and the breakpoint name (meridian.tablet). All breakpoints
declared by one file share one group named after the theme or module, and the group is what the responsive image style
form asks you to choose. To place a breakpoint in a group with a different name, give the entry a group key and use
the group name in the identifier, in the form provider.group.name. A module can add a breakpoint to a group that a theme
or another module defined by using that group’s full name in the identifier and in the group key. The documentation
says custom group labels are not supported, so the machine name of the group is what appears in the screens.
# web/modules/custom/meridian_collection/meridian_collection.breakpoints.yml
# Adds a wide breakpoint to the group defined by the meridian theme.
meridian.wall:
label: Gallery wall
mediaQuery: 'all and (min-width: 120em)'
weight: 3
group: meridian
multipliers:
- 1x
Treat this second form with care. It couples a module to a theme, and if the theme is not installed the group simply does not exist. Most sites need only the simple file in the theme.
Writing good media queries
-
Use a mobile-first scheme: an empty query for the smallest breakpoint and
min-widthqueries after it. The mapping screen then reads in the same order as the cascade of the stylesheet. -
Prefer
emoverpxin the query so that the breakpoint follows a user’s font size; the example uses48emand75em. -
Keep the file and the CSS in sync. A CSS custom property cannot be used inside a media query, so the same numbers live in two places: the YAML file and the stylesheet (or the Sass or PostCSS configuration that generates it, see Front-end tooling). A breakpoint that exists only in CSS is perfectly valid; put a breakpoint in the YAML file only when Drupal needs to know about it, for example for responsive images.
-
The
weightvalues must follow the order of the minimum widths. A wrong weight produces a mapping table whose rows are in the wrong order and apictureelement whosesourceelements the browser evaluates in the wrong order.
Multipliers
A multiplier describes a device pixel ratio. The 2x entry of the tablet breakpoint means "the file for a tablet
whose pixels are twice as dense". Each breakpoint and multiplier pair is a separate row on the responsive image style
form, so listing 1x and 2x for three breakpoints produces six rows. List only the multipliers you will map, as every
row is a decision and an image style to maintain. Unmapped multipliers cause no error; the browser falls back to
the files it has.
Responsive image styles
A responsive image style is a configuration entity that holds a breakpoint group, a fallback image style and a list of
mappings from breakpoint and multiplier pairs to image styles. It is managed at Configuration > Media > Responsive
image styles (/admin/config/media/responsive-image-style), which requires the permission Administer responsive image
styles. The User Guide describes it as a mapping between image styles and breakpoints that can use the breakpoints of
the theme.
The form has these parts:
-
Label and machine name, for example
meridian_hero. -
Breakpoint group: choose
meridian. Changing the group of an existing style clears every mapping, because the old rows would refer to breakpoints that are no longer in the group. -
Fallback image style: the style used for the
imgelement when the browser does not supportsrcsetorpicture. Pick a mid-sized one, such as the style for the tablet. It is also the file that crawlers and legacy clients receive. -
For each breakpoint and multiplier row, a choice of what to output (see below).
Mapping types
Each row is one of these:
-
Select multiple image styles and use the sizes attribute: you give a
sizesvalue and tick several image styles. The output is animg(or asource) with asrcsetof width descriptors (640w) and asizesattribute. The browser chooses the file. -
Select a single image style: one style for that breakpoint and multiplier. The output is a
pictureelement with asourcecarrying the breakpoint’s media query and, for the multipliers, asrcsetwith1xand2xdescriptors. -
The empty image option: the identifier
_empty image_. Below or at this breakpoint nothing loads. It is useful for decorative images that should disappear on small screens. -
The original image option (
_original image_): no derivative, the uploaded file is served. It skips every effect, so large uploads are served in full size; avoid it for editor-uploaded photographs.
The two constants EMPTY_IMAGE ('_empty image_') and ORIGINAL_IMAGE ('_original image_') are defined by
ResponsiveImageStyleInterface, and a mapping counts as empty unless it has an image style (single-style type), or both
a sizes value and at least one style (sizes type).
The stored configuration
The entity is stored as responsive_image.styles.<id>. Each mapping has a breakpoint_id, a multiplier, an
image_mapping_type (image_style or sizes) and an image_mapping: a style identifier for image_style, or an array
with sizes and sizes_image_styles for sizes. The fallback and the group are fallback_image_style and
breakpoint_group.
# config/sync/responsive_image.styles.meridian_hero.yml
langcode: en
status: true
dependencies:
config:
- image.style.meridian_hero_lg
- image.style.meridian_hero_md
- image.style.meridian_hero_sm
theme:
- meridian
id: meridian_hero
label: 'Meridian hero'
image_style_mappings:
-
breakpoint_id: meridian.mobile
multiplier: 1x
image_mapping_type: sizes
image_mapping:
sizes: '100vw'
sizes_image_styles:
- meridian_hero_sm
- meridian_hero_md
-
breakpoint_id: meridian.tablet
multiplier: 1x
image_mapping_type: sizes
image_mapping:
sizes: '100vw'
sizes_image_styles:
- meridian_hero_md
- meridian_hero_lg
-
breakpoint_id: meridian.desktop
multiplier: 1x
image_mapping_type: image_style
image_mapping: meridian_hero_lg
breakpoint_group: meridian
fallback_image_style: meridian_hero_md
Source: API: ResponsiveImageStyle
Because the entity computes its dependencies from the breakpoint group’s provider, the fallback style and every style named in a mapping, exporting it brings the theme and the image styles along. The consequence is the usual rule of configuration management: import the image styles and the responsive style together, and do not delete an image style that a responsive style uses. Drupal refuses to delete a style that is in use.
Check what is stored:
ddev drush config:get responsive_image.styles.meridian_hero
ddev drush config:export --yes
Source: Drush: config:get
srcset and sizes versus picture
The two outputs solve different problems and the choice is made per row, not per site.
Resolution switching with srcset and sizes
When the question is "the same crop at several sizes", use the sizes mapping type. The markup tells the browser the
widths of the available files (640w) and how wide the image will be in the layout (sizes), and the browser combines
that with the screen size and pixel density to pick one file. You do not need one row per device. A typical result for
the hero (the layout is full width up to the maximum of the page) looks like this:
<img loading="lazy"
srcset="/sites/default/files/styles/meridian_hero_sm/public/hero.jpg?itok=AAAA 640w,
/sites/default/files/styles/meridian_hero_md/public/hero.jpg?itok=BBBB 1024w"
sizes="100vw"
src="/sites/default/files/styles/meridian_hero_md/public/hero.jpg?itok=BBBB"
width="1024" height="576" alt="A dome seen at dusk">
Source: Responsive Image module
The sizes value is a string of the browser’s own syntax: a media condition and a length, repeated, ending with a default
length, for example (min-width: 75em) 1200px, 100vw. Drupal does not validate it. A wrong sizes is the most common
reason for oversized downloads: a sizes of 100vw for an image that fills only a third of the page makes the browser
fetch a file three times larger than needed. Measure the rendered width in the layout and write that.
Art direction with picture
When the question is "a different crop at different sizes" (the wide panoramic hero on desktop, a tight crop of the
dome on a phone), use the single image style type for each breakpoint. Each style then differs in its Scale and Crop,
Crop or Focal Point effects, not only in size. The output is a picture element with one source per breakpoint and
media query, and the browser uses the first matching source.
<picture>
<source srcset="/sites/default/files/styles/meridian_hero_lg/public/hero.jpg?itok=CCCC"
media="all and (min-width: 75em)" type="image/jpeg" width="1600" height="600">
<source srcset="/sites/default/files/styles/meridian_hero_md/public/hero.jpg?itok=BBBB 1x,
/sites/default/files/styles/meridian_hero_md2x/public/hero.jpg?itok=DDDD 2x"
media="all and (min-width: 48em)" type="image/jpeg" width="1024" height="400">
<img loading="lazy" src="/sites/default/files/styles/meridian_hero_sm/public/hero.jpg?itok=EEEE"
width="640" height="640" alt="A dome seen at dusk">
</picture>
Source: Responsive Image module
Three details come from the module’s own code. If every file in a srcset shares one MIME type, the source gets a
type attribute, which lets the browser skip a format it does not support; if one breakpoint lists several multipliers
they are expressed as 1x, 2x descriptors; and the width and height are passed through when known so the browser can
reserve space. Width descriptors and multipliers cannot be mixed in a single srcset (the HTML specification forbids it), so when a
breakpoint has several multipliers in the sizes type the module merges them into width descriptors and drops the
multipliers.
Choosing
| Need | Use | Why |
|---|---|---|
The same picture at different resolutions (collection thumbnails, news images) |
|
One row per breakpoint is enough, and the browser accounts for the pixel density. |
A different crop or aspect ratio per screen (exhibition hero) |
Single image style per breakpoint ( |
Only |
Different file formats with a fallback |
Single image style rows whose styles end in different Convert effects (WebP, AVIF, JPEG) |
The |
An image that is decoration on a phone |
|
Nothing is downloaded there. |
Both can be combined in one style: the sizes type for some rows and the single-style type for others.
Using a responsive style
In a view mode
Select the Responsive image formatter for an image field on the Manage display tab of the content type, pick the
responsive style and the link and loading settings. The formatter plugin has the identifier responsive_image, applies to
image fields only and its settings are responsive_image_style, image_link and image_loading.
# core.entity_view_display.node.exhibition.hero (excerpt)
content:
field_hero_image:
type: responsive_image
label: hidden
settings:
responsive_image_style: meridian_hero
image_link: ''
image_loading:
attribute: eager
weight: 0
region: content
third_party_settings: { }
The formatter adds the responsive style and every image style that it references to the cache tags of the rendered element. Editing an image style or the mapping therefore refreshes the pages that show it, and Performance and caching explains how those tags are invalidated. Media items, the Media Library and the image fields of Views use the same formatter (see Media and the Media Library and Views).
In a render array
A custom block or controller can render an image through the same theme hook that the formatter uses.
<?php
declare(strict_types=1);
namespace Drupal\meridian_collection\Plugin\Block;
use Drupal\Core\Block\Attribute\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Shows the featured object photograph with a responsive style.
*/
#[Block(
id: 'meridian_featured_object',
admin_label: new TranslatableMarkup('Featured object'),
)]
final class FeaturedObjectBlock extends BlockBase {
public function build(): array {
return [
'#theme' => 'responsive_image',
'#responsive_image_style_id' => 'meridian_hero',
'#uri' => 'public://collection/orrery.jpg',
'#width' => 1600,
'#height' => 900,
'#attributes' => [
'alt' => $this->t('A brass orrery from 1790'),
'loading' => 'lazy',
],
];
}
}
Source: API: responsive_image.module
The template responsive-image.html.twig renders this hook, and the formatter uses responsive-image-formatter.html.twig
around it, so both can be overridden in the theme with the suggestions described in
Template suggestions and preprocess. Pass the dimensions when you
know them; the module treats them as optional and passes them on to the markup.
Version note on preprocess functions
The procedural template_preprocess_responsive_image() and template_preprocess_responsive_image_formatter() were
deprecated in Drupal 11.3.0 and are removed in 12.0.0. The same applies to the helper functions
responsive_image_get_image_dimensions(), responsive_image_get_mime_type() and _responsive_image_build_source_attributes():
the code moved to the ResponsiveImageBuilder service and to ResponsiveImageThemeHooks. Custom code that called these
functions directly must use the service. Preprocess functions in a theme (meridian_preprocess_responsive_image()) are
unaffected.
Lazy loading
The image_loading setting offers lazy and eager; the default is lazy, and the chosen value is written to the
loading attribute of the rendered img. The rule is the same as for the plain Image formatter:
-
Set the one image that is the largest element in the first viewport (the Meridian hero) to
eager. A lazy hero delays the largest contentful paint. -
Leave all others on
lazy, particularly the grid of collection thumbnails, so offscreen files are not downloaded. -
Lazy loading is a hint and does not change the file size; correct
sizesvalues do. -
Keep
widthandheighton the element or reserve the space in CSS withaspect-ratio, otherwise lazy images shift the layout when they arrive. With thepicturetype, the aspect ratio can differ persource, so the dimensions that the module outputs on eachsourcematter.
A theme that overrides the template or the preprocess function to force loading per style is possible, and old tutorials
and issue discussions do it, but since the formatter exposes the setting, change the display configuration first. The
change records for the setting (node 3173719 and node 3272098) describe it as configurable in the image formatters.
Accessibility and performance together are discussed in
Accessibility and performance in themes.
Debugging a responsive image
-
Rebuild caches after adding or changing
meridian.breakpoints.yml, then open the responsive style form. If the group is missing, the file name or its YAML is wrong. -
Turn on Twig debugging (see Twig templates and debugging) and check that the
responsive-image.html.twigtemplate is used and thatpictureorsrcsetappears in the markup. -
Open the browser developer tools, resize the window and watch the network panel: the chosen file changes at the breakpoints, and the "current source" shown by the inspector tells which candidate the browser selected.
-
Check
ddev drush config:get responsive_image.styles.meridian_heroagainst the form. -
Look for the generated files under
sites/default/files/styles/; the first request for a derivative creates it, as described in File system and private files.
Security notes
-
Derivative URLs carry an
itoktoken tied to the image style, so a visitor cannot request arbitrary sizes. This is also why a responsive style with many styles and multipliers multiplies the number of derivatives created on a first request. A cache in front of the site, a warm-up after publication and a limit on the number of styles keep that cost down. -
Images of private files are served through Drupal, and a responsive style does not change access checks; see File system and private files.
-
Alt text is not a part of the responsive style. An empty
altmarks the image as decorative; set it on the field, as covered in Media and the Media Library. -
The
_original image_option serves the editor’s upload as is, including its size and embedded metadata. Do not use it for uploaded photographs.
Common errors and pitfalls
| Symptom | Cause and remedy |
|---|---|
The responsive style form shows no breakpoint group |
The theme is not enabled, the file name does not match the theme machine name, or the YAML is invalid. Caches need a rebuild. |
Mapping rows disappeared |
The group of the style was changed; Drupal clears all mappings when the group changes. |
The wrong image is chosen on a wide screen |
The |
The phone downloads the desktop file |
The |
Blurry images on high-density screens |
The |
A layout jump when images load |
No width and height, or a |
The hero loads late |
It is left on |
The style cannot be deleted |
It is used by a display. Change the displays first. |
An image in the body text ignores the responsive style |
Images typed into formatted text are plain |
Older books and tutorials
Modernizing Drupal 10 Theme Development (2023) devotes a chapter to responsive images and is the best structured treatment in the books: the breakpoint file, the Responsive Image module and the mapping screen are all described. The module and the YAML format have not changed, so the concepts remain valid. Check four things against current practice:
-
It was written for Drupal 10.1, before the PHP-attribute formatters (10.2) and the deprecation of the procedural responsive image preprocess functions in 11.3; code that implements or calls them must use the services shown above.
-
Tutorials of the Drupal 8 era keep
loadinghandling in preprocess functions or contributed modules (such as the Lazy module with its own responsive formatter). Core has offered lazy and eager loading in the formatters for years, so remove such workarounds. -
Format advice written then lists JPEG, PNG and WebP only. The Convert effect also supports AVIF in recent releases, as described in Display modes and image styles.
-
Olivero and Claro are removed in Drupal 12, so a book example that copies a core theme’s breakpoints is best replaced by the theme’s own file in a Starterkit-generated theme (see Starterkit and subthemes).
Drupal 10 Masterclass and Drupal 10 Development Cookbook (both 2023) were written for Drupal 10.0 and 10.1; where they describe the administration screens for images, check the details against the current release. See Where older books and tutorials are outdated for the general list.
Related pages
-
Theme info file and regions: the theme files next to the breakpoints file
-
Libraries and assets: the stylesheets whose media queries mirror the breakpoints
-
Display modes and image styles: creating the image styles and lazy loading of the Image formatter