Make WordPress Core

Changeset 60910

Timestamp:
10/07/2025 06:22:02 AM (7 weeks ago)
Author:
westonruter
Message:

Media: Switch to enqueueing contain-intrinsic-size CSS fix for IMG tags having sizes=auto.

This deprecates the wp_print_auto_sizes_contain_css_fix() function running at wp_head priority 1, in favor of a wp_enqueue_img_auto_sizes_contain_css_fix() function which runs just before at wp_head priority 0. The latter function unhooks the former while also enqueueing an inline style to be printed with all other styles but up front to preserve the cascade. This eliminates directly printing the STYLE tag, which was a change done similarly before for the emoji styles. See #58775.

For backwards compatibility, the CSS can still be prevented from being enqueued/printed via:

remove_action( 'wp_head', 'wp_print_auto_sizes_contain_css_fix', 1 );

This change ensures that all styles are printed together using the correct API for emitting styles.

Developed in https://github.com/WordPress/wordpress-develop/pull/8954.

Follow-up to [59435].

Props westonruter, sabernhardt, SirLouen, flixos90, joemcgill, SergeyBiryukov, superpoincare.
See #62413.
Fixes #62731.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/default-filters.php

    r60076 r60910  
    629629add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 );
    630630
    631 add_action( 'wp_head', 'wp_print_auto_sizes_contain_css_fix', 1 );
     631add_action( 'wp_head', 'wp_enqueue_img_auto_sizes_contain_css_fix', 0 ); // Must run before wp_print_auto_sizes_contain_css_fix().
     632add_action( 'wp_head', 'wp_print_auto_sizes_contain_css_fix', 1 ); // Retained for backwards-compatibility. Unhooked by wp_enqueue_img_auto_sizes_contain_css_fix().
    632633add_action( 'wp_head', 'wp_maybe_inline_styles', 1 ); // Run for styles enqueued in <head>.
    633634add_action( 'wp_footer', 'wp_maybe_inline_styles', 1 ); // Run for late-loaded styles in the footer.
  • trunk/src/wp-includes/deprecated.php

    r60811 r60910  
    64626462    return $editor_settings;
    64636463}
     6464
     6465/**
     6466 * Prints a CSS rule to fix potential visual issues with images using `sizes=auto`.
     6467 *
     6468 * This rule overrides the similar rule in the default user agent stylesheet, to avoid images that use e.g.
     6469 * `width: auto` or `width: fit-content` to appear smaller.
     6470 *
     6471 * @since 6.7.1
     6472 * @deprecated 6.9.0 Use wp_enqueue_img_auto_sizes_contain_css_fix() instead.
     6473 * @see wp_enqueue_img_auto_sizes_contain_css_fix()
     6474 *
     6475 * @see https://html.spec.whatwg.org/multipage/rendering.html#img-contain-size
     6476 * @see https://core.trac.wordpress.org/ticket/62413
     6477 * @see https://core.trac.wordpress.org/ticket/62731
     6478 */
     6479function wp_print_auto_sizes_contain_css_fix() {
     6480    _deprecated_function( __FUNCTION__, '6.9.0', 'wp_enqueue_img_auto_sizes_contain_css_fix' );
     6481
     6482    /** This filter is documented in wp-includes/media.php */
     6483    $add_auto_sizes = apply_filters( 'wp_img_tag_add_auto_sizes', true );
     6484    if ( ! $add_auto_sizes ) {
     6485        return;
     6486    }
     6487
     6488    ?>
     6489    <style>img:is([sizes="auto" i], [sizes^="auto," i]) { contain-intrinsic-size: 3000px 1500px }</style>
     6490    <?php
     6491}
  • trunk/src/wp-includes/media.php

    r60780 r60910  
    20822082
    20832083/**
    2084  * Prints a CSS rule to fix potential visual issues with images using `sizes=auto`.
     2084 * Enqueues a CSS rule to fix potential visual issues with images using `sizes=auto`.
    20852085 *
    20862086 * This rule overrides the similar rule in the default user agent stylesheet, to avoid images that use e.g.
    20872087 * `width: auto` or `width: fit-content` to appear smaller.
    20882088 *
    2089  * @since 6.7.1
     2089 * @since 6.9.0
     2090 *
    20902091 * @see https://html.spec.whatwg.org/multipage/rendering.html#img-contain-size
    20912092 * @see https://core.trac.wordpress.org/ticket/62413
    2092  */
    2093 function wp_print_auto_sizes_contain_css_fix() {
     2093 * @see https://core.trac.wordpress.org/ticket/62731
     2094 */
     2095function wp_enqueue_img_auto_sizes_contain_css_fix(): void {
     2096    // Back-compat for plugins that disable functionality by unhooking this action.
     2097    $priority = has_action( 'wp_head', 'wp_print_auto_sizes_contain_css_fix' );
     2098    if ( false === $priority ) {
     2099        return;
     2100    }
     2101    remove_action( 'wp_head', 'wp_print_auto_sizes_contain_css_fix', $priority );
     2102
    20942103    /** This filter is documented in wp-includes/media.php */
    20952104    $add_auto_sizes = apply_filters( 'wp_img_tag_add_auto_sizes', true );
     
    20982107    }
    20992108
    2100     ?>
    2101     <style>img:is([sizes="auto" i], [sizes^="auto," i]) { contain-intrinsic-size: 3000px 1500px }</style>
    2102     <?php
     2109    $handle = 'wp-img-auto-sizes-contain';
     2110    wp_register_style( $handle, false );
     2111    wp_add_inline_style( $handle, 'img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px}' );
     2112
     2113    // Make sure inline style is printed first since it was previously printed at wp_head priority 1 and this preserves the CSS cascade.
     2114    array_unshift( wp_styles()->queue, $handle );
    21032115}
    21042116
  • trunk/tests/phpunit/tests/media.php

    r60736 r60910  
    2929    protected static $large_filename = 'test-image-large.jpg';
    3030    protected static $post_ids;
     31
     32    /**
     33     * @var WP_Styles|null
     34     */
     35    protected static $original_wp_styles;
    3136
    3237    public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
     
    6772    }
    6873
     74    public function set_up(): void {
     75        global $wp_styles;
     76        self::$original_wp_styles = $wp_styles;
     77        $wp_styles                = null;
     78        parent::set_up();
     79    }
     80
    6981    public static function wpTearDownAfterClass() {
    7082        $GLOBALS['_wp_additional_image_sizes'] = self::$_sizes;
     
    8092     */
    8193    public function tear_down() {
    82         global $_wp_current_template_id, $_wp_current_template_content;
     94        global $_wp_current_template_id, $_wp_current_template_content, $wp_styles;
    8395        unset( $_wp_current_template_id, $_wp_current_template_content );
     96
     97        $wp_styles = self::$original_wp_styles;
    8498
    8599        parent::tear_down();
     
    65786592
    65796593    /**
     6594     * Provides data to test wp_enqueue_img_auto_sizes_contain_css_fix().
     6595     *
     6596     * @return array<string, array>
     6597     */
     6598    public function data_provider_data_provider_to_test_wp_enqueue_img_auto_sizes_contain_css_fix(): array {
     6599        return array(
     6600            'default'                     => array(
     6601                'set_up'   => null,
     6602                'expected' => true,
     6603            ),
     6604            'filtered_off'                => array(
     6605                'set_up'   => static function (): void {
     6606                    add_filter( 'wp_img_tag_add_auto_sizes', '__return_false' );
     6607                },
     6608                'expected' => false,
     6609            ),
     6610            'filtered_on'                 => array(
     6611                'set_up'   => static function (): void {
     6612                    add_filter( 'wp_img_tag_add_auto_sizes', '__return_false' );
     6613                    add_filter( 'wp_img_tag_add_auto_sizes', '__return_true', 100 );
     6614                },
     6615                'expected' => true,
     6616            ),
     6617            'deprecated_function_removed' => array(
     6618                'set_up'   => static function (): void {
     6619                    remove_action( 'wp_head', 'wp_print_auto_sizes_contain_css_fix', 1 );
     6620                },
     6621                'expected' => false,
     6622            ),
     6623            'new_function_removed'        => array(
     6624                'set_up'              => static function (): void {
     6625                    remove_action( 'wp_head', 'wp_enqueue_img_auto_sizes_contain_css_fix', 0 );
     6626                },
     6627                'expected'            => false,
     6628                'expected_deprecated' => 'wp_print_auto_sizes_contain_css_fix',
     6629            ),
     6630            'both_functions_removed'      => array(
     6631                'set_up'   => static function (): void {
     6632                    remove_action( 'wp_head', 'wp_enqueue_img_auto_sizes_contain_css_fix', 0 );
     6633                    remove_action( 'wp_head', 'wp_print_auto_sizes_contain_css_fix', 1 );
     6634                },
     6635                'expected' => false,
     6636            ),
     6637        );
     6638    }
     6639
     6640    /**
     6641     * Tests that IMG auto-sizes CSS fix is enqueued (and printed) when expected.
     6642     *
     6643     * @covers ::wp_enqueue_img_auto_sizes_contain_css_fix
     6644     * @ticket 62731
     6645     *
     6646     * @dataProvider data_provider_data_provider_to_test_wp_enqueue_img_auto_sizes_contain_css_fix
     6647     */
     6648    public function test_wp_enqueue_img_auto_sizes_contain_css_fix( ?Closure $set_up, bool $expected, ?string $expected_deprecated = null ): void {
     6649        if ( $set_up ) {
     6650            $set_up();
     6651        }
     6652        if ( isset( $expected_deprecated ) ) {
     6653            $this->setExpectedDeprecated( $expected_deprecated );
     6654        }
     6655
     6656        $this->assertCount( 0, wp_styles()->queue );
     6657        wp_enqueue_style( 'very-early-enqueued', home_url( '/very-early-enqueued.css' ) );
     6658        add_action(
     6659            'wp_enqueue_scripts',
     6660            static function () {
     6661                wp_enqueue_style( 'wp-block-library' );
     6662            }
     6663        );
     6664
     6665        $wp_head_output           = get_echo( 'wp_head' );
     6666        $html_processor           = new WP_HTML_Tag_Processor( $wp_head_output );
     6667        $found_style_text_content = null;
     6668        while ( $html_processor->next_tag( array( 'tag_name' => 'STYLE' ) ) ) {
     6669            if ( $html_processor->get_attribute( 'id' ) === 'wp-img-auto-sizes-contain-inline-css' ) {
     6670                $found_style_text_content = $html_processor->get_modifiable_text();
     6671                break;
     6672            }
     6673        }
     6674
     6675        $enqueued = wp_styles()->queue;
     6676        if ( $expected ) {
     6677            $this->assertSame( 'wp-img-auto-sizes-contain', array_shift( $enqueued ) );
     6678            $this->assertIsString( $found_style_text_content );
     6679            $this->assertStringContainsString( 'contain-intrinsic-size', $found_style_text_content );
     6680        } else {
     6681            $this->assertNull( $found_style_text_content );
     6682        }
     6683        $this->assertSame( 'very-early-enqueued', array_shift( $enqueued ) );
     6684        $this->assertContains( 'wp-emoji-styles', $enqueued );
     6685        $this->assertContains( 'wp-block-library', $enqueued );
     6686    }
     6687
     6688    /**
    65806689     * Data provider for test_wp_img_tag_add_auto_sizes().
    65816690     *
Note: See TracChangeset for help on using the changeset viewer.