1

I'm using the following code to create a fullscreen background slideshow using the Swiper JS library:

<?php
function background_slideshow() {
    $args = array(
        'post_type'      => 'attachment',
        'numberposts'    => -1,
        'post_parent'    => get_the_ID(),
        'post_mime_type' => 'image',
        'orderby'        => 'menu_order',
        'order'          => 'ASC',
    );

    ?>
    <div class="swiper">
    <div class="swiper-wrapper">

    <?php
    $attachments = get_posts( $args );
    if ( $attachments ) {
        foreach ( $attachments as $attachment ) {
            echo '<div class="swiper-slide">' . wp_get_attachment_image( $attachment->ID, 'full' ) . '</div>';
        }
    }
    ?>

    </div>
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>
    </div>

    <?php

}
?>

This code returns image tags like this:

<img width="2664" height="1440" 
src="https://www.example.com/wp-content/uploads/2018/10/image.jpg"
class="attachment-full size-full" alt="" decoding="async" loading="lazy"
srcset="https://www.example.com/wp-content/uploads/2018/10/image.jpg 2664w,
        https://www.example.com/wp-content/uploads/2018/10/image-300x162.jpg 300w,
        https://www.example.com/wp-content/uploads/2018/10/image-600x324.jpg 600w,
        https://www.example.com/wp-content/uploads/2018/10/image-768x415.jpg 768w,
        https://www.example.com/wp-content/uploads/2018/10/image-1894x1024.jpg 1894w"
sizes="(max-width: 2664px) 100vw, 2664px" />

I'm using the following CSS code to make the images cover the whole screen:

.swiper {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}

.swiper-slide img {
  object-fit: cover;
  height: 100vh;
}

The problem is that those who access the site using a smartphone are getting really blurry images because their browser is choosing the smallest image for smartphones (https://www.example.com/wp-content/uploads/2018/10/image-300x162.jpg). This size is OK for thumbnails in a grid, but not for a fullscreen background slideshow.

My question is, is it possible to remove the https://www.example.com/wp-content/uploads/2018/10/image-300x162.jpg 300w srcset entry JUST for this specific wp_get_attachment_image() call without using preg_replace() or similar regexp functions?

1

1 Answer 1

1

This is the wrong approach. Mobile devices are being served the small image because the default sizes attribute is incorrect for your uses case, not because of the srcset.

If you provide a correct sizes attribute then browsers will choose a more appropriate source. If you remove the 300w version without changing the sizes attribute the browser will probably just pick the 600w version, which will probably still be blurry. In fact, given modern mobile display resolutions I'd wager that it is choosing the 600w version or higher already, but that's still too blurry.

The reason the image is blurry is because your sizes attribute (which is actually just the WordPress default) is telling the browser that on displays smaller than 2664px the image is displayed at 100vw, i.e. the viewport width, but the image is actually displayed at 100vh because of your CSS, meaning that the image is actually being displayed much much wider if the display is vertical.

You need to tell the browser what width the image will actually be displayed at. If your images are 16:9 the the image is going to be displayed at 1.77 times the height of the display (16/9 is 1.77). You can tell the browser this by setting the sizes attribute to calc(100vh * 1.77):

wp_get_attachment_image(
    $attachment->ID,
    'full',
    null,
    array(
        'sizes' => 'calc(100vh * 1.77)',
    )
);

Unfortunately. because the image is sized vertically, it's not possible to provide a 100% accurate sizes attribute unless you know the aspect ratio of the original image. If you or your users are going to use a variety of different images in this slider, then you may want to dynamically calculate the ratio:

$image = wp_get_attachment_image_src( $attachment->ID, 'full' );
$ratio = $src[1] / $src[2];

wp_get_attachment_image(
    $attachment->ID,
    'full',
    null,
    array(
        'sizes' => "max(100vw, calc(100vh * $ratio))",
    )
);

I added max() here to indicate that the image will display at 100vw or calc(100vh * $ratio), whichever is wider. This is to account for the behaviour of object-fit if the original image is tall and narrow.

3
  • Thanks for the thorough explanation! Now I understand the logic behind the srcset and sizes attributes a bit more. Just an observation, 16/9 is not 1.66 but 1.77.
    – leemon
    Commented Jan 16, 2023 at 6:37
  • 1
    @leemon Ah, good catch, thanks. Commented Jan 16, 2023 at 6:48
  • There are still two mentions of "1.66" left in your answer
    – leemon
    Commented Jan 16, 2023 at 6:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.