Output external images with unknown dimensions in AMP pages
authorTim Düsterhus <duesterhus@woltlab.com>
Thu, 25 Jun 2020 09:47:19 +0000 (11:47 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Thu, 25 Jun 2020 09:53:54 +0000 (11:53 +0200)
The `layout="fill"` attribute allows to embed an `<amp-img>` with unknown
dimensions. This comes with the drawback that the image will stretch as
far as possible, not maintaining the aspect-ratio and taking up the whole
page.

To solve this a container with known dimensions needs to be put around it
and the `<img>` within needs to have the `object-fit: contain` property.
This property will contain the image within the container while maintaining
aspect ratio at the drawback that the empty space of the container will be
filled with void.

This container was selected to be a 16:9 aspect ratio, with a size of
384×216 Pixels (one fifth of Full HD in each dimension), hopefully
minimizing the void on common image formats.

The resulting AMP was checked against the AMP validator and passed.

Fixes #3264

com.woltlab.wcf/templates/ampHeader.tpl
wcfsetup/install/files/lib/system/html/output/AmpHtmlOutputProcessor.class.php

index 31b3c23fc383bea21527f7b026152ac804bcd6a5..78ca050c65d7fb53329ef1028b1beee57455749c 100644 (file)
                                overflow: auto;
                                padding: 10px;
                        }
+                       
+                       .unknownDimensionContainer {
+                               position: relative;
+                               width: 384px;
+                               height: 216px;
+                               max-width: 100%;
+                               display: inline-block;
+                       }
+                       
+                       .unknownDimensionContainer amp-img img {
+                               object-fit: contain;
+                       }
                </style>
                {literal}<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>{/literal}
                <script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
index 0e5b2cb27bc6e08512d8d2f67794c6390c6aa04c..b343b1fe7b8a36318c09cd33888445d7f91ed846 100644 (file)
@@ -65,18 +65,6 @@ class AmpHtmlOutputProcessor extends HtmlOutputProcessor {
                        while ($elements->length) {
                                /** @var \DOMElement $element */
                                $element = $elements->item(0);
-                               if ($tag === 'img') {
-                                       $styles = $element->getAttribute('style');
-                                       if (preg_match('~\bheight:\s*(\d+)px\b~', $styles, $matches)) $element->setAttribute('height', $matches[1]);
-                                       if (preg_match('~\bwidth:\s*(\d+)px\b~', $styles, $matches)) $element->setAttribute('width', $matches[1]);
-                                       
-                                       if (!$element->getAttribute('height') || !$element->getAttribute('width')) {
-                                               DOMUtil::removeNode($element);
-                                               continue;
-                                       }
-                                       
-                                       $element->removeAttribute('style');
-                               }
                                
                                $newElement = $element->ownerDocument->createElement('amp-' . $tag);
                                
@@ -87,6 +75,22 @@ class AmpHtmlOutputProcessor extends HtmlOutputProcessor {
                                        $newElement->setAttribute($attr->localName, $attr->nodeValue);
                                }
                                
+                               if ($tag === 'img') {
+                                       $styles = $newElement->getAttribute('style');
+                                       $newElement->removeAttribute('style');
+                                       if (preg_match('~\bheight:\s*(\d+)px\b~', $styles, $matches)) $newElement->setAttribute('height', $matches[1]);
+                                       if (preg_match('~\bwidth:\s*(\d+)px\b~', $styles, $matches)) $newElement->setAttribute('width', $matches[1]);
+                                       
+                                       if (!$newElement->getAttribute('height') || !$newElement->getAttribute('width')) {
+                                               $newElement->setAttribute('layout', 'fill');
+                                               
+                                               $container = $newElement->ownerDocument->createElement('span');
+                                               $container->setAttribute('class', 'unknownDimensionContainer');
+                                               $container->appendChild($newElement);
+                                               $newElement = $container;
+                                       }
+                               }
+                               
                                $element->parentNode->insertBefore($newElement, $element);
                                DOMUtil::removeNode($element);
                        }