Skip to content

WordPress Images

Custom image sizes

Add custom image sizes to functions.php. Replace 'xxxx' with the name of your theme (this is to ensure a unique function name).

WordPress documentation: add_image_size()

 * Custom image sizes
add_action('after_setup_theme', 'xxxx_theme_setup');
function xxxx_theme_setup() {
  add_image_size('full_640', 640);
  add_image_size('full_750', 750);
  add_image_size('full_828', 828);
  add_image_size('full_1080', 1080);
  add_image_size('full_1200', 1200);
  add_image_size('full_1440', 1440);
  add_image_size('full_1920', 1920);
  add_image_size('full_2048', 2048);
  add_image_size('full_2560', 2560);

The new images created will be scaled, not cropped, to create each new size. The image sizes above are based on the Next.js default device sizes, with the addition of the 1440 and 2560 sizes.

To add an image size that gets cropped:

add_action( 'after_setup_theme', 'xxxx_theme_setup' );
function xxxx_theme_setup() {
  add_image_size( 'logo', 120, 80, true ); // true = crop
  add_image_size( 'logo-retina', 240, 160, true );

Available sizes

Show all sizes available for the current theme.

var_dump( get_intermediate_image_sizes() );

The above will output default sizes plus additional sizes. Snippet from the above function:

$default_sizes    = array( 'thumbnail', 'medium', 'medium_large', 'large' );
$additional_sizes = wp_get_additional_image_sizes();


Returns a list of all currently registered image sub-sizes. Which essentially calls the following:

  global $_wp_additional_image_sizes;
  print '<pre>';
  print_r( $_wp_additional_image_sizes );
  print '</pre>';

Regenerate image sizes

If changes to image sizes is made after some images have already been loaded, use the Regenerate Thumbnails plugin or the WP-CLI command: wp media regenerate.


An example using an image from an ACF image field. This example assumes the width is full screen, i.e. 100vw.

  $img = get_field('hero_image');
  $width = $img['sizes'][ 'full_2560-width' ];
  $height = $img['sizes'][ 'full_2560-height' ];

  src="<?php echo $img['sizes']['full_2560']; ?>"
    <?php echo $img['sizes']['full_640']; ?> 640w,
    <?php echo $img['sizes']['full_750']; ?> 750w,
    <?php echo $img['sizes']['full_828']; ?> 828w,
    <?php echo $img['sizes']['full_1080']; ?> 1080w,
    <?php echo $img['sizes']['full_1200']; ?> 1200w,
    <?php echo $img['sizes']['full_1440']; ?> 1440w,
    <?php echo $img['sizes']['full_1920']; ?> 1920w,
    <?php echo $img['sizes']['full_2048']; ?> 2048w,
    <?php echo $img['sizes']['full_2560']; ?> 2560w
  alt="<?php echo $img['alt']; ?>"
  width="<?php echo $width; ?>"
  height="<?php echo $height; ?>"

Only include loading="lazy" if it is not in the viewport when the page loads.

Using the 'full' image size

When using ACF images with the return format as an image array the output does not include the full image in the sizes key. But the original url is available as $img['url'].

The image width and height can be accessed as follows:

  $image = get_field('the_image_field');
  $url = $image['url'];
  $alt = $image['alt'];

  // Get the attachment ID of the image
  $attachment_id = attachment_url_to_postid( $url );

  // Retrieve the image dimensions using wp_get_attachment_image_src()
  $image_dimensions = wp_get_attachment_image_src( $attachment_id, 'full' );

  // Extract the width and height from the returned array
  $image_width = $image_dimensions[1];
  $image_height = $image_dimensions[2];

  if ($image) {
    echo '<img src="' . esc_url($url) . '" alt="' . esc_attr($alt) . '" width="' . $image_width . '" height="' . $image_height . '" loading="lazy">';


The browser does not know the size at which the image will be rendered on the page until it has downloaded and parsed all the relevant CSS and JavaScript files.

If we give sizes based on screen width then the browser will know which image to use and can start downloading it.

Therefore, the sizes attribute is a list to let the browser know what size the image will be at different browser sizes / breakpoints.

It is often easiest to use the 'vw' unit for sizes relative to the viewport width. e.g. 100vw would be full width.

However, the width doesn’t have to be expressed as a viewport width unit. It can be any length including absolute and relative length. You can even use CSS calc() to do things like auto-calculate margins dynamically.

The sizes attribute should always be used when srcset width descriptors are used. If the sizes attribute is not provided the browser will assume the image is full width i.e. 100vw.

<img sizes="
  [media-condition] [length],
  [media-condition] [length],
  [media-condition] [length],

The browser users the first [media-condition] that is matched. If no conditions are matched it will use the last value [default-length].

Using max-width conditions the screen size will get bigger and bigger. In this case the image would be full width on mobile, two column on tablet and three column on desktop.

  (max-width: 840px) 100vw,
  (max-width: 1200px) 50vw,

Tailwind sizes

If using Tailwind, where the breakpoints use min-width, we need to start with the largest breakpoints and get smaller. The default size will be for when the browser is less than 640px.

  (min-width: 1536px) 5vw,  <!-- 2xl -->
  (min-width: 1280px) 10vw, <!-- xl -->
  (min-width: 1024px) 20vw, <!-- lg -->
  (min-width: 768px) 25vw,  <!-- md -->
  (min-width: 640px) 50vw,  <!-- sm -->

The Cloud Four tutorial further explains responsive images.

Or view the official WHATWG specification.



Gets the directory of the current theme.

This example uses x descriptors, useful for fixed size images such as logos.

  src="<?php echo get_stylesheet_directory_uri(); ?>/assets/logo-1x.png"
    <?php echo get_stylesheet_directory_uri(); ?>/assets/logo-1x.png,
    <?php echo get_stylesheet_directory_uri(); ?>/assets/logo-2x.png 2x