Open triblondon opened 6 years ago
It seems to me that the portalactivate
event satisfies this, at least unless we have a JS-restricted mode. If so, then adding a media query or similar seems like a possible ergonomic improvement to consider later (though I lean against it).
e.g.
<script>
window.addEventListener('portalactivate', e => {
document.documentElement.classList.add('activeportal');
});
</script>
<style>
.activeportal .call-to-action {
opacity: 0.5;
}
</style>
@jeremyroman What would be the mechanism through which a website would know that it is in the yet-to-be-activated state? I imagine that a website would only want an inert styling if it's in this special state. For the no JS until activated mode, it sounds like we would need a CSS thing.
Thoughts?
I think it would be better to to not require JS for not-yet-activated styling. Even if JS is allowed, it would be nice to be able to avoid a restyling when JS executes.
Ah, knowing whether you're initially in a portal is a good point (though also solvable via a JS API). As far as restyling goes, sure, though I don't know that it's a big deal (you can change state before you create the DOM, for instance).
I'm mostly not sure whether such applications are really interested in "am I in a portal element", as opposed to "am I logically activated [in some embedder-defined sense]" or "am I frozen/inert" (in the event that we do eventually provide a "freeze").
In the event we do ship a no-script mode, then I agree that a declarative CSS approach becomes more essential. Currently I'm not aware of other features having media queries for such things (e.g. I don't think there's an "am-I-in-an-iframe" query), but that seems the natural fit if this proves necessary.
I want to chime in on the utility of this for a slightly different use case. Let's say I run a site and expect that my existing pages will be loaded into an aggregator and activated via portal elements. For the sake of the argument, let's assume the <portal>
my page is initially loaded into on the aggregator, before activated, is smaller than the full-sized aggregator page. On a mobile device the portal's dimensions may be below the height/width that my responsive site is designed for and the layout may be suboptimal or just plain broken.
My page being able to know if it was in a portal would allow it to render a more optimal "portal view". Having this available in css via would be much more efficient than via javascript. Additionally to mention a media query would be useful if/when javascript does execute on my page, via window.matchmedia()
.
I think this is a different case than an "am i in an iframe" query, since portals are poised to do a lot more work than iframes have been capable of.
cc: @darobin
Hi Justin, when you say (emphasis added):
I think this is a different case than an "am i in an iframe" query, since portals are poised to do a lot more work than iframes have been capable of.
I assume that you meant "capable of" in terms of what one would want to render in a Portal given that the work can be used for the resulting navigation, versus an iframe where a "teaser" experience is built and dropped on the actual navigation. Is that the correct interpretation?
Can you build on your idea? In particular, if you could share some thoughts on how you would create a seamless activation experience from the custom/mini portal view to the full experience, with just CSS and an hypothetical activated/not-yet-activated state.
Thanks!
Yes, that is the correct interpretation.
Here's a situation that might illustrate the utility: Imagine an e-commerce site for a clothing retailer. A catalog page on the site is a grid of shirts that are for sale. Each t-shirt listed is actually a <portal>
element that uses the t-shirt detail page as the src
. A t-shirt detail page would have to know in some way to display a smaller view when in a portal, which might be just the name, image, and price. Whereas the full detail page would want to display the full page with a larger image, rating, reviews, etc.
In terms of hypothetical css to achieve a seamless experience, a media query would allow for hiding of page chrome (nav, footer) on the in-portal view. A media query for the in-portal state could be combined with media query for screen size to transition the opacity of page chrome elements. Transitioning text from an in-portal view to a full page view may be challenging; there would likely be reflow and size change issues that would have to be carefully considered. The smoothest transition between an in-portal view to a full-page view would be for the image of the t-shirt itself. An image (using `srcset) could cleanly transition and scale between views and would be a clear object for a user's eyes to follow and maintain visual continuity.
There are certainly many trade-offs in usage like this (performance, SEO), but some potential benefits too (UX, server simplicity). I see this as a potential way to achieve many of the benefits of ajax + history api patterns afford, but done in almost pure html/css and get smooth transitions in the process.
Thanks for the example. This does match with some of the UX we've seen from our early partners. Obviously, there are many ways to achieve the same user experience and in that case, it was driven by JS.
I think the JS approach provides more flexibility, i.e. adjust the UX but also the runtime activity. I'm not sure if it's possible/easy to do the latter with CSS only. So, in terms of priority, it seems that JS surfaces (events, apis) come first and then CSS surfaces. Would you agree?
Hopefully, we will have a better sense of these nuances through an Origin Trial (same-origin use cases to start). The covid19 situation threw a wrench into our original plans, but we'll get there (crossing fingers).
I missed this issue when I filed #241 so I closed it in favor of this one. I'll repost my suggestion from there which appears to basically a rehash of what's already been proposed here.
To the outer page, the portal should behave as a replaced object like an . The embedder page can lightly control the "image" inside the portal using object-fit
and object-position
. More detailed customization of a portal preview is left to the embeddee page and we do this by introducing a media query:
@media (render-mode: preview) {
#logo {
position: fixed;
width: 100%; height: 50%;
left: 0; top: 0;
}
#title {
position: fixed;
width: 100%; height: 50%;
left: 0; top: 50%;
}
}
@jeremyroman correctly points out that in some cases (very small portal), a page might want to use a thumbnail (like above), but that may not be appropriate in other cases (e.g. the scroll into article mentioned above). It'd seem useful (for cross-origin cases where one party doesn't control both ends) to also have some notion of the size we're being displayed in.
I'd propose adding some low-granularity signal (probably also media query, e.g. @media (preview-scale <= 0.5)
to let the page adjust itself for a variety of scenarios. To prevent using this as a communication channel, I think this wouldn't be able to change dynamically and the granularity would need to be fixed to some arbitrary increments (e.g. 0.25).
IIUC, authors can register hooks in script for changes to media queries so this looks like it'd be quite flexible. Does a model like this satisfy the use cases folks here are thinking of?
I want to point out that if we want pages to display differently inside a portal vs. outside, a CSS hook seems really important. E.g. using the example above, you'd currently have to do something like
<script>
if (window.portalHost) {
const style = document.createElement('style');
style.textContent = `
#logo {
position: fixed;
width: 100%; height: 50%;
left: 0; top: 0;
}
#title {
position: fixed;
width: 100%; height: 50%;
left: 0; top: 50%;
}
`;
document.body.appendChild(style);
window.addEventListener("portalactivate", () => {
style.remove();
}, { once: true });
}
</script>
which is madness.
The example of making your logo and title elements big might not fit that well with the proposal's more recent focus on prerendering. But a more important stylesheet might be something like
@media (render-mode: preview) {
.signup-prompt, a.signin, a.signup {
display: none;
}
}
(again using GitHub as an example), to avoid the "flash of un-logged-in content".
So IMO some kind of styling hook is pretty high priority, even for an MVP. Something that allows differentiating between small previews and large prerenders, like the preview-scale
@bokand mentions, might not be necessary yet; it'll depend on what we see people building with portals.
I mean, it's not quite that bad:
if (window.portalHost)
document.documentElement.classList.add('in-portal');
addEventListener('portalactivate', () => document.documentElement.classList.remove('in-portal'));
Agree adding a class isn't horrible but media queries do seem purpose-built for this case.
The example of making your logo and title elements big might not fit that well with the proposal's more recent focus on prerendering.
It depends a lot on the use case. It doesn't fit with "swipe to navigate" type cases but I recall seeing a real-world demo someone made with small ~100x100 link buttons expanding to become the page. In that case, we're still prerendering the successor page but the button is too small to show the page contents - you could have a pretty simple but slick transition that translates the Logo+Title from button-filling into it's final position on the page. That will be a lot easier to do from inside the page than trying to coordinate across pages:
#title-and-logo {
transition-duration: 1s;
transition-property: transform;
}
@media (render-mode: preview) {
#title-and-logo {
transition-duration: 1s;
transition-property: transform;
transform: scale(3) translate3d(-100px, -100px, 0);
}
}
I think this still fits with the prerendering focus as something like this really relies on being prerendered.
I have a concern over the activation of a portal that is only partially in the viewport. Example: I scroll down to the bottom of an article and another article appears for me to ‘scroll into’. But while still only occupying the lower half of the screen, I attempt to interact with some element of the portal content. This will presumably necessarily activate a transition, filling the viewport with the portal content, and activating it, after which I’d have to perform my interaction again. Therefore in this use case, it might make sense for developers to be have a CSS hook to apply certain styles only when a document is inside an unactivated portal, so that explicit calls to action can be dimmed or hidden until the document is activated
source