Skip to content

Print IMG auto-sizes contain CSS fix by enqueueing inline style #8954

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/wp-includes/default-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@
add_action( 'wp_default_styles', 'wp_default_styles' );
add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 );

add_action( 'wp_head', 'wp_print_auto_sizes_contain_css_fix', 1 );
add_action( 'wp_enqueue_scripts', 'wp_enqueue_img_auto_sizes_contain_css_fix' );
add_action( 'wp_head', 'wp_maybe_inline_styles', 1 ); // Run for styles enqueued in <head>.
add_action( 'wp_footer', 'wp_maybe_inline_styles', 1 ); // Run for late-loaded styles in the footer.

Expand Down
29 changes: 28 additions & 1 deletion src/wp-includes/deprecated.php
Original file line number Diff line number Diff line change
Expand Up @@ -6460,4 +6460,31 @@ function wp_add_editor_classic_theme_styles( $editor_settings ) {
array_unshift( $editor_settings['styles'], $classic_theme_styles_settings );

return $editor_settings;
}
}

/**
* Prints a CSS rule to fix potential visual issues with images using `sizes=auto`.
*
* This rule overrides the similar rule in the default user agent stylesheet, to avoid images that use e.g.
* `width: auto` or `width: fit-content` to appear smaller.
*
* @since 6.7.1
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per below, if we want to target the next minor release:

Suggested change
* @deprecated 6.9.0 Use wp_enqueue_img_auto_sizes_contain_css_fix() instead.
* @deprecated 6.8.2 Use wp_enqueue_img_auto_sizes_contain_css_fix() instead.

* @deprecated 6.9.0 Use wp_enqueue_img_auto_sizes_contain_css_fix() instead.
* @see wp_enqueue_img_auto_sizes_contain_css_fix()
*
* @see https://html.spec.whatwg.org/multipage/rendering.html#img-contain-size
* @see https://core.trac.wordpress.org/ticket/62413
*/
function wp_print_auto_sizes_contain_css_fix() {
_deprecated_function( __FUNCTION__, '6.9.0', 'wp_enqueue_img_auto_sizes_contain_css_fix' );

/** This filter is documented in wp-includes/media.php */
$add_auto_sizes = apply_filters( 'wp_img_tag_add_auto_sizes', true );
if ( ! $add_auto_sizes ) {
return;
}

?>
<style>img:is([sizes="auto" i], [sizes^="auto," i]) { contain-intrinsic-size: 3000px 1500px }</style>
<?php
}
16 changes: 10 additions & 6 deletions src/wp-includes/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -2061,25 +2061,29 @@ function wp_sizes_attribute_includes_valid_auto( string $sizes_attr ): bool {
}

/**
* Prints a CSS rule to fix potential visual issues with images using `sizes=auto`.
* Enqueues a CSS rule to fix potential visual issues with images using `sizes=auto`.
*
* This rule overrides the similar rule in the default user agent stylesheet, to avoid images that use e.g.
* `width: auto` or `width: fit-content` to appear smaller.
*
* @since 6.7.1
* @since 6.9.0
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be 6.8.2 if we want.

Suggested change
* @since 6.9.0
* @since 6.8.2

*
* @see https://html.spec.whatwg.org/multipage/rendering.html#img-contain-size
* @see https://core.trac.wordpress.org/ticket/62413
*/
function wp_print_auto_sizes_contain_css_fix() {
function wp_enqueue_img_auto_sizes_contain_css_fix(): void {
/** This filter is documented in wp-includes/media.php */
$add_auto_sizes = apply_filters( 'wp_img_tag_add_auto_sizes', true );
if ( ! $add_auto_sizes ) {
return;
}

?>
<style>img:is([sizes="auto" i], [sizes^="auto," i]) { contain-intrinsic-size: 3000px 1500px }</style>
<?php
$handle = 'wp-img-auto-sizes-contain';
wp_register_style( $handle, false );
wp_add_inline_style( $handle, 'img:is([sizes="auto" i], [sizes^="auto," i]) { contain-intrinsic-size: 3000px 1500px }' );

// Make sure inline style is printed first since it was previously printed at wp_head priority 1 and this preserves the CSS cascade.
array_unshift( wp_styles()->queue, $handle );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a bit hacky to me, but I understand the purpose. I assume there's not a better way to control the order of registered styles besides maybe making sure that the wp_register_style() call is made on an earlier hook, like init, correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly.

}

/**
Expand Down
89 changes: 88 additions & 1 deletion tests/phpunit/tests/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class Tests_Media extends WP_UnitTestCase {
protected static $large_filename = 'test-image-large.jpg';
protected static $post_ids;

/**
* @var WP_Styles|null
*/
protected static $original_wp_styles;

public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
self::$_sizes = wp_get_additional_image_sizes();
$GLOBALS['_wp_additional_image_sizes'] = array();
Expand Down Expand Up @@ -66,6 +71,13 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
wp_trash_post( self::$post_ids['trash'] );
}

public function set_up(): void {
global $wp_styles;
self::$original_wp_styles = $wp_styles;
$wp_styles = null;
parent::set_up();
}

public static function wpTearDownAfterClass() {
$GLOBALS['_wp_additional_image_sizes'] = self::$_sizes;
}
Expand All @@ -79,9 +91,11 @@ public static function tear_down_after_class() {
* Ensures that the static content media count, fetchpriority element flag and related filter are reset between tests.
*/
public function tear_down() {
global $_wp_current_template_id, $_wp_current_template_content;
global $_wp_current_template_id, $_wp_current_template_content, $wp_styles;
unset( $_wp_current_template_id, $_wp_current_template_content );

$wp_styles = self::$original_wp_styles;

parent::tear_down();

$this->reset_content_media_count();
Expand Down Expand Up @@ -6500,6 +6514,79 @@ public function data_image_with_existing_auto_sizes() {
);
}

/**
* Provides data to test wp_enqueue_img_auto_sizes_contain_css_fix().
*
* @return array<string, array>
*/
public function data_provider_data_provider_to_test_wp_enqueue_img_auto_sizes_contain_css_fix(): array {
return array(
'default' => array(
'set_up' => null,
'expected' => true,
),
'filtered_off' => array(
'set_up' => static function (): void {
add_filter( 'wp_img_tag_add_auto_sizes', '__return_false' );
},
'expected' => false,
),
'filtered_on' => array(
'set_up' => static function (): void {
add_filter( 'wp_img_tag_add_auto_sizes', '__return_false' );
add_filter( 'wp_img_tag_add_auto_sizes', '__return_true', 100 );
},
'expected' => true,
),
);
}

/**
* Tests that IMG auto-sizes CSS fix is enqueued (and printed) when expected.
*
* @covers ::wp_enqueue_img_auto_sizes_contain_css_fix
* @ticket 62731
*
* @dataProvider data_provider_data_provider_to_test_wp_enqueue_img_auto_sizes_contain_css_fix
*/
public function test_wp_enqueue_img_auto_sizes_contain_css_fix( ?Closure $set_up, bool $expected ): void {
if ( $set_up ) {
$set_up();
}
remove_action( 'wp_print_styles', 'print_emoji_styles' ); // To avoid deprecation warning.

$this->assertCount( 0, wp_styles()->queue );

wp_enqueue_style( 'wp-block-library' );
$this->assertSame( array( 'wp-block-library' ), wp_styles()->queue );

wp_enqueue_img_auto_sizes_contain_css_fix();
$printed_styles = get_echo( 'wp_print_styles' );
$p = new WP_HTML_Tag_Processor( $printed_styles );
$found_style_text_content = null;
while ( $p->next_tag( array( 'tag_name' => 'STYLE' ) ) ) {
if ( $p->get_attribute( 'id' ) === 'wp-img-auto-sizes-contain-inline-css' ) {
$found_style_text_content = $p->get_modifiable_text();
break;
}
}

if ( $expected ) {
$this->assertSame(
array( 'wp-img-auto-sizes-contain', 'wp-block-library' ),
wp_styles()->queue
);
$this->assertIsString( $found_style_text_content );
$this->assertStringContainsString( 'contain-intrinsic-size', $found_style_text_content );
} else {
$this->assertSame(
array( 'wp-block-library' ),
wp_styles()->queue
);
$this->assertNull( $found_style_text_content );
}
}

/**
* Data provider for test_wp_img_tag_add_auto_sizes().
*
Expand Down
Loading