Skip to content

Commit e21a628

Browse files
authored
Merge pull request #5955 from ampproject/add/object-fit-position-inheritance
Inherit object-fit and object-position styles so more conversions work out of the box
2 parents 0c0d442 + ed1c930 commit e21a628

13 files changed

+113
-326
lines changed

assets/css/src/amp-default.css

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
21
/*
3-
* Prevent cases of amp-img converted from img to appear with stretching by using object-fit to scale.
2+
* Prevent cases of amp-img converted from img to appear with stretching by using object-fit to scale. Only do this for
3+
* amp-img/amp-anim elements that we converted from <img> via AMP_Img_Sanitizer. This is key for images that get 100%
4+
* width such as in the post content so that the contents do not get stretched or cropped.
45
* See <https://github.com/ampproject/amphtml/issues/21371#issuecomment-475443219>.
5-
* Also use object-fit:contain in worst case scenario when we can't figure out dimensions for an image.
6-
* Additionally, in side of \AMP_Img_Sanitizer::determine_dimensions() it could $amp_img->setAttribute( 'object-fit', 'contain' )
7-
* so that the following rules wouldn't be needed.
86
*/
9-
amp-img.amp-wp-enforced-sizes[layout="intrinsic"] > img,
10-
amp-anim.amp-wp-enforced-sizes[layout="intrinsic"] > img {
7+
.amp-wp-enforced-sizes {
118
object-fit: contain;
129
}
1310

@@ -89,3 +86,20 @@ amp-carousel .amp-wp-gallery-caption {
8986
button[overflow] {
9087
bottom: 0;
9188
}
89+
90+
/*
91+
* Ensure relevant properties for "replaced elements" which are set on sanitizer-converted custom elements will be
92+
* inherited to the actual replaced element which is the shadow element and also to the noscript fallback element.
93+
*/
94+
amp-anim img,
95+
amp-anim noscript,
96+
amp-iframe iframe,
97+
amp-iframe noscript,
98+
amp-img img,
99+
amp-img noscript,
100+
amp-video video,
101+
amp-video noscript {
102+
image-rendering: inherit;
103+
object-fit: inherit;
104+
object-position: inherit;
105+
}

includes/embeds/class-amp-core-block-handler.php

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ class AMP_Core_Block_Handler extends AMP_Base_Embed_Handler {
5050
'core/categories' => 'ampify_categories_block',
5151
'core/archives' => 'ampify_archives_block',
5252
'core/video' => 'ampify_video_block',
53-
'core/cover' => 'ampify_cover_block',
5453
];
5554

5655
/**
@@ -212,75 +211,6 @@ public function ampify_video_block( $block_content, $block ) {
212211
return $block_content;
213212
}
214213

215-
/**
216-
* Ampify cover block.
217-
*
218-
* This ensures that the background img/video in a cover block has object-fit=cover and the appropriate object-position
219-
* attribute so that they will be carried over to to the amp-img/amp-video and propagated to the img/video in the
220-
* light shadow DOM.
221-
*
222-
* @see \AMP_Video_Sanitizer::filter_video_dimensions()
223-
*
224-
* @param string $block_content The block content about to be appended.
225-
* @param array $block The full block, including name and attributes.
226-
* @return string Filtered block content.
227-
*/
228-
public function ampify_cover_block( $block_content, $block ) {
229-
$is_video_background = (
230-
isset( $block['attrs']['backgroundType'] )
231-
&&
232-
'video' === $block['attrs']['backgroundType']
233-
);
234-
$is_image_element = ! (
235-
! empty( $block['attrs']['hasParallax'] )
236-
||
237-
! empty( $block['attrs']['isRepeated'] )
238-
);
239-
240-
// Object fit/position is not relevant when background image has fixed positioning or is repeated.
241-
// In other words, it is not relevant when a <video> or a <img> is not going to be used.
242-
// See <https://github.com/WordPress/gutenberg/blob/54c9066d4/packages/block-library/src/cover/save.js#L54-L72>.
243-
if ( ! ( $is_video_background || $is_image_element ) ) {
244-
return $block_content;
245-
}
246-
247-
$pattern = sprintf(
248-
'#<%s(?= )[^>]*? class="(?:[^"]*? )?wp-block-cover__%s-background(?: [^"]*?)?"#',
249-
$is_video_background ? 'video' : 'img',
250-
$is_video_background ? 'video' : 'image'
251-
);
252-
return preg_replace_callback(
253-
$pattern,
254-
static function ( $matches ) use ( $block ) {
255-
$replacement = $matches[0];
256-
257-
// The background image/video for the cover block by definition needs object-fit="cover" on the resulting amp-ing/amp-video.
258-
$replacement .= ' object-fit="cover"';
259-
260-
// Add the fill layout to skip needlessly obtaining the dimensions.
261-
$replacement .= ' layout="fill"';
262-
263-
// Add object-position from the block's attributes to add to the img/video to be copied onto the amp-img/amp-video.
264-
// The AMP runtime copies object-position attribute onto the underlying img/video for a given amp-img/amp-video.
265-
// This is needed since the object-position property directly on an amp-img/amp-video will have no effect since
266-
// since it is merely a wrapper for the underlying img/video element which actually supports the CSS property.
267-
if ( isset( $block['attrs']['focalPoint']['x'], $block['attrs']['focalPoint']['y'] ) ) {
268-
// See logic in Gutenberg for writing focal point to object-position attr:
269-
// <https://github.com/WordPress/gutenberg/blob/54c9066/packages/block-library/src/cover/save.js#L71>.
270-
$replacement .= sprintf(
271-
' object-position="%d%% %d%%"',
272-
round( (float) $block['attrs']['focalPoint']['x'] * 100 ),
273-
round( (float) $block['attrs']['focalPoint']['y'] * 100 )
274-
);
275-
}
276-
277-
return $replacement;
278-
},
279-
$block_content,
280-
1
281-
);
282-
}
283-
284214
/**
285215
* Sanitize widgets that are not added via Gutenberg.
286216
*

includes/sanitizers/class-amp-core-theme-sanitizer.php

Lines changed: 6 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -158,18 +158,17 @@ protected static function get_theme_features_config( $theme_slug ) {
158158
// Twenty Nineteen.
159159
case 'twentynineteen':
160160
return [
161-
'dequeue_scripts' => [
161+
'dequeue_scripts' => [
162162
'twentynineteen-skip-link-focus-fix', // This is part of AMP. See <https://github.com/ampproject/amphtml/issues/18671>.
163163
'twentynineteen-priority-menu',
164164
'twentynineteen-touch-navigation', // @todo There could be an AMP implementation of this, similar to what is implemented on ampproject.org.
165165
],
166-
'remove_actions' => [
166+
'remove_actions' => [
167167
'wp_print_footer_scripts' => [
168168
'twentynineteen_skip_link_focus_fix', // See <https://github.com/WordPress/twentynineteen/pull/47>.
169169
],
170170
],
171-
'add_twentynineteen_masthead_styles' => [],
172-
'adjust_twentynineteen_images' => [],
171+
'adjust_twentynineteen_images' => [],
173172
'enable_determine_hero_images_transformer' => [],
174173
];
175174

@@ -938,121 +937,20 @@ static function() use ( $method ) {
938937
}
939938

940939
/**
941-
* Add required styles for featured image header in Twenty Nineteen.
942-
*
943-
* The following is necessary because the styles in the theme apply to the featured img,
944-
* and the CSS parser will then convert the selectors to amp-img. Nevertheless, object-fit
945-
* does not apply on amp-img and it needs to apply on an actual img.
946-
*
947-
* @link https://github.com/WordPress/wordpress-develop/blob/5.0/src/wp-content/themes/twentynineteen/style.css#L2276-L2299
948-
* @since 1.0
949-
*/
950-
public static function add_twentynineteen_masthead_styles() {
951-
add_action(
952-
'wp_enqueue_scripts',
953-
static function() {
954-
ob_start();
955-
?>
956-
<style>
957-
.site-header.featured-image .site-featured-image .post-thumbnail amp-img > img {
958-
height: auto;
959-
left: 50%;
960-
max-width: 1000%;
961-
min-height: 100%;
962-
min-width: 100vw;
963-
position: absolute;
964-
top: 50%;
965-
transform: translateX(-50%) translateY(-50%);
966-
width: auto;
967-
z-index: 1;
968-
/* When image filters are active, make it grayscale to colorize it blue. */
969-
}
970-
971-
@supports (object-fit: cover) {
972-
.site-header.featured-image .site-featured-image .post-thumbnail amp-img > img {
973-
height: 100%;
974-
left: 0;
975-
object-fit: cover;
976-
top: 0;
977-
transform: none;
978-
width: 100%;
979-
}
980-
}
981-
</style>
982-
<?php
983-
$styles = str_replace( [ '<style>', '</style>' ], '', ob_get_clean() );
984-
wp_add_inline_style( get_template() . '-style', $styles );
985-
},
986-
11
987-
);
988-
}
989-
990-
/**
991-
* Add required styles for video and image headers.
940+
* Add required styles for Twenty Seventeen header.
992941
*
993-
* This is currently used exclusively for Twenty Seventeen.
942+
* This is required since JS is not applying the required styles at runtime.
994943
*
995944
* @since 1.0
996-
* @link https://github.com/WordPress/wordpress-develop/blob/1af1f65a21a1a697fb5f33027497f9e5ae638453/src/wp-content/themes/twentyseventeen/style.css#L1687
997-
* @link https://github.com/WordPress/wordpress-develop/blob/1af1f65a21a1a697fb5f33027497f9e5ae638453/src/wp-content/themes/twentyseventeen/style.css#L1743
998945
*/
999946
public static function add_twentyseventeen_masthead_styles() {
1000-
/*
1001-
* The following is necessary because the styles in the theme apply to img and video,
1002-
* and the CSS parser will then convert the selectors to amp-img and amp-video respectively.
1003-
* Nevertheless, object-fit does not apply on amp-img and it needs to apply on an actual img.
1004-
*/
1005947
add_action(
1006948
'wp_enqueue_scripts',
1007949
static function() {
1008950
$is_front_page_layout = ( is_front_page() && 'posts' !== get_option( 'show_on_front' ) ) || ( is_home() && is_front_page() );
1009951
ob_start();
1010952
?>
1011953
<style>
1012-
.has-header-image .custom-header-media amp-img > img,
1013-
.has-header-video .custom-header-media amp-video > video{
1014-
position: fixed;
1015-
height: auto;
1016-
left: 50%;
1017-
max-width: 1000%;
1018-
min-height: 100%;
1019-
min-width: 100%;
1020-
min-width: 100vw; /* vw prevents 1px gap on left that 100% has */
1021-
width: auto;
1022-
top: 50%;
1023-
padding-bottom: 1px; /* Prevent header from extending beyond the footer */
1024-
-ms-transform: translateX(-50%) translateY(-50%);
1025-
-moz-transform: translateX(-50%) translateY(-50%);
1026-
-webkit-transform: translateX(-50%) translateY(-50%);
1027-
transform: translateX(-50%) translateY(-50%);
1028-
}
1029-
.has-header-image:not(.twentyseventeen-front-page):not(.home) .custom-header-media amp-img > img {
1030-
bottom: 0;
1031-
position: absolute;
1032-
top: auto;
1033-
-ms-transform: translateX(-50%) translateY(0);
1034-
-moz-transform: translateX(-50%) translateY(0);
1035-
-webkit-transform: translateX(-50%) translateY(0);
1036-
transform: translateX(-50%) translateY(0);
1037-
}
1038-
/* For browsers that support object-fit */
1039-
@supports ( object-fit: cover ) {
1040-
.has-header-image .custom-header-media amp-img > img,
1041-
.has-header-video .custom-header-media amp-video > video,
1042-
.has-header-image:not(.twentyseventeen-front-page):not(.home) .custom-header-media amp-img > img {
1043-
height: 100%;
1044-
left: 0;
1045-
-o-object-fit: cover;
1046-
object-fit: cover;
1047-
top: 0;
1048-
-ms-transform: none;
1049-
-moz-transform: none;
1050-
-webkit-transform: none;
1051-
transform: none;
1052-
width: 100%;
1053-
}
1054-
}
1055-
1056954
.navigation-top.site-navigation-fixed {
1057955
display: none;
1058956
}
@@ -1555,7 +1453,7 @@ static function() {
15551453
font-size: 32px;
15561454
line-height: 46px;
15571455
}
1558-
.featured-content .post-thumbnail amp-img > img {
1456+
.featured-content .post-thumbnail amp-img {
15591457
object-fit: cover;
15601458
object-position: top;
15611459
}

includes/sanitizers/trait-amp-noscript-fallback.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
use AmpProject\Dom\Document;
9+
use AmpProject\Attribute;
910

1011
/**
1112
* Trait AMP_Noscript_Fallback
@@ -52,6 +53,13 @@ protected function initialize_noscript_allowed_attributes( $tag ) {
5253
}
5354
}
5455
}
56+
57+
// Remove attributes which are likely to cause styling conflicts, as the noscript fallback should get treated like it has fill layout.
58+
unset(
59+
$this->noscript_fallback_allowed_attributes[ Attribute::ID ],
60+
$this->noscript_fallback_allowed_attributes[ Attribute::CLASS_ ],
61+
$this->noscript_fallback_allowed_attributes[ Attribute::STYLE ]
62+
);
5563
}
5664

5765
/**
@@ -81,13 +89,12 @@ protected function append_old_node_noscript( DOMElement $new_element, DOMElement
8189
$noscript->appendChild( $old_element );
8290
$new_element->appendChild( $noscript );
8391

84-
// Remove all non-allowed attributes preemptively to prevent doubled validation errors.
92+
// Remove all non-allowed attributes preemptively to prevent doubled validation errors, only leaving the attributes required.
8593
for ( $i = $old_element->attributes->length - 1; $i >= 0; $i-- ) {
8694
$attribute = $old_element->attributes->item( $i );
87-
if ( isset( $this->noscript_fallback_allowed_attributes[ $attribute->nodeName ] ) ) {
88-
continue;
95+
if ( ! isset( $this->noscript_fallback_allowed_attributes[ $attribute->nodeName ] ) ) {
96+
$old_element->removeAttribute( $attribute->nodeName );
8997
}
90-
$old_element->removeAttribute( $attribute->nodeName );
9198
}
9299
}
93100
}

src/Transformer/DetermineHeroImages.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,21 @@ final class DetermineHeroImages implements Transformer {
3737
*
3838
* @var string
3939
*/
40-
const CUSTOM_HEADER_XPATH_QUERY = ".//*[ @id = 'wp-custom-header' or @id = 'masthead' or @id = 'site-header' or contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-custom-header ' ) ]//*[ ( self::img or self::amp-img ) and not( @data-hero ) and not( contains( concat( ' ', normalize-space( @class ), ' ' ), ' custom-logo ' ) ) ]";
40+
const CUSTOM_HEADER_XPATH_QUERY = ".//*[ @id = 'wp-custom-header' or @id = 'masthead' or @id = 'site-header' or contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-custom-header ' ) ]//amp-img[ not( @data-hero ) and not( contains( concat( ' ', normalize-space( @class ), ' ' ), ' custom-logo ' ) ) ]";
4141

4242
/**
4343
* XPath query to find the custom logo.
4444
*
4545
* @var string
4646
*/
47-
const CUSTOM_LOGO_XPATH_QUERY = ".//a[ contains( concat( ' ', normalize-space( @class ), ' ' ), ' custom-logo-link ' ) ]//*[ ( self::img or self::amp-img ) and contains( concat( ' ', normalize-space( @class ), ' ' ), ' custom-logo ' ) ][ not( @data-hero ) ]";
47+
const CUSTOM_LOGO_XPATH_QUERY = ".//a[ contains( concat( ' ', normalize-space( @class ), ' ' ), ' custom-logo-link ' ) ]//amp-img[ contains( concat( ' ', normalize-space( @class ), ' ' ), ' custom-logo ' ) ][ not( @data-hero ) ]";
4848

4949
/**
5050
* XPath query to find the featured image.
5151
*
5252
* @var string
5353
*/
54-
const FEATURED_IMAGE_XPATH_QUERY = ".//*[ ( self::img or self::amp-img ) and contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-post-image ' ) ][ not( @data-hero ) ]";
54+
const FEATURED_IMAGE_XPATH_QUERY = ".//amp-img[ contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-post-image ' ) ][ not( @data-hero ) ]";
5555

5656
/**
5757
* XPath query to find the first entry-content.
@@ -65,14 +65,14 @@ final class DetermineHeroImages implements Transformer {
6565
*
6666
* @var string
6767
*/
68-
const INITIAL_COVER_BLOCK_XPATH_QUERY = "./*[1]/descendant-or-self::div[ contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-block-cover ' ) ]/*[ ( self::img or self::amp-img ) and contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-block-cover__image-background ' ) ][ not( @data-hero ) ]";
68+
const INITIAL_COVER_BLOCK_XPATH_QUERY = "./*[1]/descendant-or-self::div[ contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-block-cover ' ) ]/amp-img[ contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-block-cover__image-background ' ) ][ not( @data-hero ) ]";
6969

7070
/**
7171
* XPath query to find Image Block at the beginning of post content (including nested inside of another block).
7272
*
7373
* @var string
7474
*/
75-
const INITIAL_IMAGE_BLOCK_XPATH_QUERY = "./*[1]/descendant-or-self::figure[ contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-block-image ' ) ]/*[ ( self::img or self::amp-img ) ][ not( @data-hero ) ]";
75+
const INITIAL_IMAGE_BLOCK_XPATH_QUERY = "./*[1]/descendant-or-self::figure[ contains( concat( ' ', normalize-space( @class ), ' ' ), ' wp-block-image ' ) ]/amp-img[ not( @data-hero ) ]";
7676

7777
/**
7878
* Apply transformations to the provided DOM document.

0 commit comments

Comments
 (0)