diff --git a/build-system/test-configs/forbidden-terms.js b/build-system/test-configs/forbidden-terms.js index dabe9b632511..8294380f0e59 100644 --- a/build-system/test-configs/forbidden-terms.js +++ b/build-system/test-configs/forbidden-terms.js @@ -1046,7 +1046,6 @@ const forbiddenTermsSrcInclusive = { 'extensions/amp-a4a/0.1/amp-a4a.js', 'extensions/amp-fx-flying-carpet/0.1/amp-fx-flying-carpet.js', 'extensions/amp-script/0.1/amp-script.js', - 'extensions/amp-story/1.0/amp-story-page.js', ], }, 'onLayoutMeasure': { @@ -1064,7 +1063,6 @@ const forbiddenTermsSrcInclusive = { 'extensions/amp-ad-network-adsense-impl/0.1/amp-ad-network-adsense-impl.js', 'extensions/amp-iframe/0.1/amp-iframe.js', 'extensions/amp-script/0.1/amp-script.js', - 'extensions/amp-story/1.0/amp-story-page.js', ], }, '\\.getIntersectionElementLayoutBox': { diff --git a/extensions/amp-story/1.0/amp-story-access.css b/extensions/amp-story/1.0/amp-story-access.css index 7ce37c3813e8..411e316d2bcb 100644 --- a/extensions/amp-story/1.0/amp-story-access.css +++ b/extensions/amp-story/1.0/amp-story-access.css @@ -9,7 +9,7 @@ amp-story-access { height: 100% !important; width: 100% !important; z-index: 100003 !important; /** Above the desktop navigation UI. */ - transform: translate3d(0, 100vh, 0) !important; + transform: translate3d(0, var(--story-100dvh), 0) !important; transition-delay: 0.15s !important; pointer-events: none !important; } diff --git a/extensions/amp-story/1.0/amp-story-desktop-one-panel.css b/extensions/amp-story/1.0/amp-story-desktop-one-panel.css index 4bfdebcaf616..d9c3d4da3c3d 100644 --- a/extensions/amp-story/1.0/amp-story-desktop-one-panel.css +++ b/extensions/amp-story/1.0/amp-story-desktop-one-panel.css @@ -17,7 +17,7 @@ amp-story[standalone] { --i-amphtml-story-desktop-one-panel-ratio: 69 / 116; --i-amphtml-story-desktop-one-panel-responsive-margin: max(74px, 8.25vh); /** Calculates panel height by subtracting responsive vertical margin. */ - --i-amphtml-story-desktop-one-panel-height: calc(100vh - var(--i-amphtml-story-desktop-one-panel-responsive-margin) * 2); + --i-amphtml-story-desktop-one-panel-height: calc(var(--story-100dvh) - var(--i-amphtml-story-desktop-one-panel-responsive-margin) * 2); --i-amphtml-story-desktop-one-panel-width: calc(var(--i-amphtml-story-desktop-one-panel-height) * var(--i-amphtml-story-desktop-one-panel-ratio)); --i-amphtml-story-desktop-one-panel-border-radius: 10px; --story-page-vw: calc(var(--i-amphtml-story-desktop-one-panel-width) * .01) !important; @@ -27,7 +27,7 @@ amp-story[standalone] { @media(max-height: 756px) { :root:not([data-story-supports-landscape]):not([i-amphtml-story-mobile]) { --i-amphtml-story-desktop-one-panel-responsive-margin: 0px; - --i-amphtml-story-desktop-one-panel-width: calc(100vh * var(--i-amphtml-story-desktop-one-panel-ratio)); + --i-amphtml-story-desktop-one-panel-width: calc(var(--story-100dvh) * var(--i-amphtml-story-desktop-one-panel-ratio)); --i-amphtml-story-desktop-one-panel-border-radius: 0; } } diff --git a/extensions/amp-story/1.0/amp-story-page.js b/extensions/amp-story/1.0/amp-story-page.js index 68999224554f..2c29cfb8344b 100644 --- a/extensions/amp-story/1.0/amp-story-page.js +++ b/extensions/amp-story/1.0/amp-story-page.js @@ -51,7 +51,7 @@ import {isPrerenderActivePage} from './prerender-active-page'; import {listen, listenOnce} from '#utils/event-helper'; import {CSS as pageAttachmentCSS} from '../../../build/amp-story-open-page-attachment-0.1.css'; import {propagateAttributes} from '#core/dom/propagate-attributes'; -import {px, toggle} from '#core/dom/style'; +import {toggle} from '#core/dom/style'; import {renderPageAttachmentUI} from './amp-story-open-page-attachment'; import {renderPageDescription} from './semantic-render'; import {whenUpgradedToCustomElement} from '#core/dom/amp-element-helpers'; @@ -167,9 +167,6 @@ export class AmpStoryPage extends AMP.BaseElement { /** @private {?AdvancementConfig} */ this.advancement_ = null; - /** @private {?Element} */ - this.cssVariablesStyleEl_ = null; - /** @const @private {!function(boolean)} */ this.debounceToggleLoadingSpinner_ = debounce( this.win, @@ -217,9 +214,6 @@ export class AmpStoryPage extends AMP.BaseElement { /** @private @const {!./amp-story-store-service.AmpStoryStoreService} */ this.storeService_ = getStoreService(this.win); - /** @private {?../../../src/layout-rect.LayoutSizeDef} */ - this.layoutBox_ = null; - /** @private {!Array} */ this.unlisteners_ = []; @@ -538,51 +532,6 @@ export class AmpStoryPage extends AMP.BaseElement { ]); } - /** @override */ - onLayoutMeasure() { - const layoutBox = this.getLayoutSize(); - // Only measures from the first story page, that always gets built because - // of the prerendering optimizations in place. - if ( - !isPrerenderActivePage(this.element) || - (this.layoutBox_ && - this.layoutBox_.width === layoutBox.width && - this.layoutBox_.height === layoutBox.height) - ) { - return; - } - - this.layoutBox_ = layoutBox; - - return this.getVsync().runPromise( - { - measure: (state) => { - const {height, width} = layoutBox; - state.height = height; - state.width = width; - state.vh = height / 100; - }, - mutate: (state) => { - const {height, width} = state; - if (state.height === 0 && state.width === 0) { - return; - } - this.storeService_.dispatch(Action.SET_PAGE_SIZE, {height, width}); - if (!this.cssVariablesStyleEl_) { - const doc = this.win.document; - this.cssVariablesStyleEl_ = doc.createElement('style'); - this.cssVariablesStyleEl_.setAttribute('type', 'text/css'); - doc.head.appendChild(this.cssVariablesStyleEl_); - } - this.cssVariablesStyleEl_.textContent = `:root {--story-page-vh: ${px( - state.vh - )} !important}`; - }, - }, - {} - ); - } - /** * Reacts to UI state updates. * @param {!UIType} uiState diff --git a/extensions/amp-story/1.0/amp-story-share-menu.css b/extensions/amp-story/1.0/amp-story-share-menu.css index feaf7d053f15..9977d162b35f 100644 --- a/extensions/amp-story/1.0/amp-story-share-menu.css +++ b/extensions/amp-story/1.0/amp-story-share-menu.css @@ -10,7 +10,7 @@ height: 100% !important; width: 100% !important; z-index: 100003 !important; /** Above pagination-buttons. */ - transform: translate3d(0, 100vh, 0) !important; + transform: translate3d(0, var(--story-100dvh), 0) !important; transition-delay: 0.15s !important; pointer-events: none !important; visibility: hidden !important; diff --git a/extensions/amp-story/1.0/amp-story.css b/extensions/amp-story/1.0/amp-story.css index a60975a769d5..e824ead5da95 100644 --- a/extensions/amp-story/1.0/amp-story.css +++ b/extensions/amp-story/1.0/amp-story.css @@ -12,12 +12,19 @@ /** Common */ :root { --story-page-vw: 1vw !important; - --story-page-vh: 1vh !important; + --story-page-vh: var(--story-dvh, 1vh) !important; --story-page-vmin: min(var(--story-page-vw), var(--story-page-vh)) !important; --story-page-vmax: max(var(--story-page-vw), var(--story-page-vh)) !important; + --story-100dvh: calc(var(--story-dvh, 1vh) * 100) !important; font-size: calc(2.5 * var(--story-page-vh, 8px)); } +@supports (height: 1dvh) { + :root { + --story-dvh: 1dvh !important; + } +} + body { animation:none !important; -webkit-animation: none !important; @@ -241,7 +248,7 @@ amp-story-page[distance="1"][distance] { amp-story.i-amphtml-experiment-story-load-inactive-outside-viewport:not([desktop]) amp-story-page[distance="1"]:not(.i-amphtml-story-page-loaded):not(.i-amphtml-visited), amp-story-page[distance="2"][distance] { - transform: translateY(100vh) !important; + transform: translateY(var(--story-100dvh)) !important; } amp-story-page [data-text-background-color] { @@ -398,7 +405,7 @@ amp-story-grid-layer .i-amphtml-embedded-component::after { margin: auto; width: var(--i-amphtml-story-layer-width, 100%); height: var(--i-amphtml-story-layer-height, 100%); - font-size: calc(var(--i-amphtml-story-layer-height, 100vh) / 10); + font-size: calc(var(--i-amphtml-story-layer-height) / 10); margin-left: calc((var(--story-page-vw, 1%) * 100 - var(--i-amphtml-story-layer-width, 100%)) * 0.5); /* Set margin to 1/2 of page-width - layer-width to center layer */ --i-amphtml-aspect-ratio-float: calc(var(--aspect-ratio)) !important; /* Avoid fractions, which don't work with compilers that remove parenthesis */ diff --git a/extensions/amp-story/1.0/amp-story.js b/extensions/amp-story/1.0/amp-story.js index d8063fca6642..5f2d55266e80 100644 --- a/extensions/amp-story/1.0/amp-story.js +++ b/extensions/amp-story/1.0/amp-story.js @@ -67,7 +67,7 @@ import { scopedQuerySelector, scopedQuerySelectorAll, } from '#core/dom/query'; -import {computedStyle, setImportantStyles, toggle} from '#core/dom/style'; +import {computedStyle, px, setImportantStyles, toggle} from '#core/dom/style'; import {createPseudoLocale} from '#service/localization/strings'; import {debounce} from '#core/types/function'; import {dev, devAssert, user} from '#utils/log'; @@ -346,6 +346,10 @@ export class AmpStory extends AMP.BaseElement { // prerendering, because of a height incorrectly set to 0. this.mutateElement(() => {}); + if (!this.win.CSS?.supports?.('height: 1dvh')) { + this.onResize_(this.getViewport().getSize()); + } + const pageId = this.getInitialPageId_(); if (pageId) { const page = this.element.querySelector( @@ -474,7 +478,7 @@ export class AmpStory extends AMP.BaseElement { // Lock body to prevent overflow. this.lockBody_(); // Standalone CSS affects sizing of the entire page. - this.onResize(); + this.onResizeDebounced(); } /** @@ -735,7 +739,9 @@ export class AmpStory extends AMP.BaseElement { attributeFilter: ['class'], }); - this.getViewport().onResize(debounce(this.win, () => this.onResize(), 300)); + this.getViewport().onResize( + debounce(this.win, () => this.onResizeDebounced(), 300) + ); this.installGestureRecognizers_(); // TODO(gmajoulet): migrate this to amp-story-viewer-messaging-handler once @@ -1543,7 +1549,7 @@ export class AmpStory extends AMP.BaseElement { * Handle resize events and set the story's desktop state. * @visibleForTesting */ - onResize() { + onResizeDebounced() { this.uiState_ = this.getUIType_(); this.storeService_.dispatch(Action.TOGGLE_UI, this.uiState_); @@ -1552,6 +1558,22 @@ export class AmpStory extends AMP.BaseElement { this.setOrientationAttribute_(isLandscape, isLandscapeSupported); } + /** + * Handles resize events and sets CSS variables. + * @param {!Object} size including new width and height + * @private + */ + onResize_(size) { + const {height, width} = size; + if (height === 0 && width === 0) { + return; + } + this.storeService_.dispatch(Action.SET_PAGE_SIZE, {height, width}); + setImportantStyles(this.win.document.documentElement, { + '--story-dvh': px(height / 100), + }); + } + /** * Adds an orientation=landscape|portrait attribute. * If the story doesn't explicitly support landscape via the opt-in attribute, diff --git a/extensions/amp-story/1.0/pagination-buttons.css b/extensions/amp-story/1.0/pagination-buttons.css index 6ab92df762be..edee7ce05a9b 100644 --- a/extensions/amp-story/1.0/pagination-buttons.css +++ b/extensions/amp-story/1.0/pagination-buttons.css @@ -12,7 +12,7 @@ width: 30px !important; top: 0 !important; bottom: 0 !important; - height: calc(100vh - 150px) !important; + height: calc(var(--story-100dvh) - 150px) !important; margin: auto 0 !important; background: none !important; transition: 150ms opacity linear, 150ms visibility linear !important; diff --git a/extensions/amp-story/1.0/test/test-amp-story.js b/extensions/amp-story/1.0/test/test-amp-story.js index b89b376c1554..d59b24f03da0 100644 --- a/extensions/amp-story/1.0/test/test-amp-story.js +++ b/extensions/amp-story/1.0/test/test-amp-story.js @@ -272,13 +272,13 @@ describes.realWin( } }, }; - story.onResize(); + story.onResizeDebounced(); expect(isDesktopStub).to.be.calledOnce; expect(story.element.classList.contains('i-amphtml-story-landscape')).to .be.true; story.element.style.width = '10px'; story.element.style.height = '11px'; - story.onResize(); + story.onResizeDebounced(); expect(isDesktopStub).to.be.calledTwice; expect(story.element.classList.contains('i-amphtml-story-landscape')).to .be.false; @@ -420,7 +420,7 @@ describes.realWin( await story.layoutCallback(); story.landscapeOrientationMedia_ = {matches: false}; - story.onResize(); + story.onResizeDebounced(); await Promise.resolve(); expect(story.element).to.have.attribute('orientation'); expect(story.element.getAttribute('orientation')).to.equal('portrait');