<iframe> and the History API #184
|
@rniwa what is Apple doing here? |
|
@smaug---- so I guess the problem is all the state exposed on That kind of approach makes sense if you don't want to influence your container, but if you're a simple layout component that breaks expectations. Not sure if there's a good answer here. (We could make it depend on open vs closed...) |
|
For open case I could possibly live with normal nested browsing context handling. Given the recent example, bug in Google Ads where their scripts caused the container page to go back, I'd prefer to never expose history state even in open case, but at least in closed case the state shouldn't be shared. |
|
I would be okay with blocking history from "shadow-iframe" by default. And then later figuring out if we want to make that work. @hayatoito @rniwa? |
|
I'm not sure if throwing would be best by the way. It depends on what kind of things end up being embedded. If you throw a bunch of existing pages will likely break when embedded in this way. |
|
but if the page called go(<not_zero>), it sure would expect something to happen, and if we wouldn't throw, the page would be broken in some other way. This is tricky, but I'm not sure we have any other good option to effectively disable all history API in shadow-iframes. |
I am okay with this. Blocking history from "shadow-iframe" by default should be a safe option. [Updated] On the second thought, go() should work, IMO. Let me think further. |
|
My opinion is:
We might want to have another APIs, such as DocumentOrShadowRoot.history, if we want to make that work somehow later. |
|
|
|
To be a tad more precise, go() works in browsing context tree. Not putting shadow dom iframe loads to session history, but having go() to work would lead to very surprising behavior. The browsing context in iframe could expect its page loads are in session history, but go() wouldn't actually know about those loads so it would always affect to some ancestor or sibling browsing context, never the browsing context in iframe. (go() is super error prone API to use :/ ) |
|
Yeah, I think we can not have a perfect solution here. We have to compromise for window.history because it's globally accessible. |
|
That doesn't really solve this issue though, does it? I guess we still have the corresponding issue against the HTML Standard to define what should happen here... |
|
So the conclusion here is to leave the history API work as is, even in closed shadow root, As dimitri's comment pointed out, whether shadow DOM is detectable is not a concern. I'll work on a draft for pull request. |
|
That does not seem the conclusion here... ;) Let me explain the context: I and @TakayoshiKochi discussed this topic yesterday, and we got a rough consensus: |
|
That conclusion seems directly opposed to comments from folks from Apple and Mozilla that very much want encapsulation at all cost, even if it means losing features like |
|
Yeah, this is the opposite. Actually, I have changed my mind. Yesterday, I tried to have a good proposal, but I can not have any concrete proposal if we are to block iframe in a shadow tree. That made me in a trouble. Some of the concerns in #184 (comment) can not be resolved. After that, I am starting to tend to agree with Dimitir's comment in this particular case:
Maybe I might change my mind again, but as of now, I am fine with "not blocking at all". |
|
I'm very worried about exposing shadow iframes in the the light DOM's session history. It would make using history API in light DOM super error prone: it would become really hard for light DOM to know what the current state actually is. |
|
@smaug---- is the concern shadow-dom specific? I may not be understanding the case you quoted. In my understanding the injected Google Ads script mistakenly ran That's a reasonable concern but it should be addressed at nested browsing context and history API's behavior about joint session history, not at the level of shadow tree boundary. |
|
Let's say a social network site starts using shadow DOM and an iframe for its own widget to display comments. Then, you don't want navigations within that iframe to affect the navigation history of the embedding page. It DOES happen today but I don't think that's really intended / desirable. |
|
Yeah, that's one of concerns. However, I do not want Shadow DOM to control the behavior of iframes. I prefer separating responsibilities to more primitives, in order to isolate our concerns. |
|
In general, that's component user's fault if they use a bad component. As a general rule,
In this particular case, |
|
This DOES seem like a pretty significant concern given changing this behavior later would not be backwards compatible. I don't understand where your rule comes from. As far as I could recall, we've never reached a consensus on such a general principles (or even a consensus that having such a principle is a good idea). |
|
The general rule that Hayato wrote in #184 (comment) isn't the matter of concern in this thread, and everyone doesn't have to agree on it at least here. He just expressed the reasoning behind our opinion. BTW, I read Hayato's #184 (comment) wrong and I thought keeping the behavior as is was the conclusion of this thread in my previous #184 (comment). As everyone already pointed it out, it was totally opposite to what was changed in the spec change 08793be. Sorry for any confusion incurred by my message. |
Yeah, that comes from my attempt to honer a well-established rule (I believe):
We see a similar rule in most of programming languages. Thus, I think having this principle in our mind would be good for us. Actually, you can see several instances of this rule in the current Shadow DOM:
|
|
The problem here is that exposing iframe history in the outer world breaks that very principle. Now the outer DOM can influence what gets shown in the iframe inside a shadow tree by using |
Oh. That makes sense. This is a kind of "Outer to Inner". The problem here is that we do not have any concrete proposal other than "Not blocking at all". |
|
We have options, I see about three paths:
|
(all these also need that loads in shadow iframes don't end up to session history) (7) might not be too bad. Since it is not really acceptable for shadow iframe to affect to the global history, no pages using history API should be loaded to shadow iframes. Or then (3), so that shadow iframe becomes a root of a session history itself. (but then, how would the UI work with several different session histories) |
|
Thank you, @annevk , @smaug---- . Blink is fine with 1 in #184 (comment). Shadow DOM is originally designed to provide an encapsulation for DOM tree structures. It was not designed to provide an encapsulation for scripts. Thus, as long as nodes in a shadow tree are not leaked to outer trees, I am okay. A behavior leakage (I am not sure how I can call this..) which would be caused by scripts is not what I expect Shadow DOM to prevent that. I do not want Shadow DOM to own such a role magically beyond its original role. It would be nice that we could have a separate primitive which prevents these kinds of the behavior influences from happening, other than reusing a tree structure boundary provided by Shadow DOM. A unit of a shadow tree and a unit of joint session history do not have to be always the same, I guess. |
|
As I noted, all other implementers have a wider view as to what encapsulation means. So I don't think 1 is really an option at all, unless @rniwa and @smaug---- suddenly change their mind, which seems unlikely since they've been pretty consistent on this. |
|
I see. Thanks. I think Blink can live in a world with option 3, given that DOM nodes are not leaked anyway. 2 is unacceptable, BTW. However, I still prefer having new primitive by which we can explain the behavior of such a iframe. e.g. a new attribute "XXX" for iframe. On the top of it, we might want to explain the behavior of iframes in a shadow tree. e.g. XXX attribute of iframe in a shadow tree is true by default. That would make Shadow DOM less magical, hopefully. |
|
(Looks like github has weird bug to change list numbering so I updated my comment a bit) |
|
Let me extend @annevk's 3. How about this? Let's define a new attribute "isolatehistory" (or something) for
This may still miss something (very probable). But could we converge on something like this? |
|
That sounds fairly reasonable and similar to what I was thinking of. Could use input from @majido too here I think. |
|
Looks good to me, basically. Thanks.
I prefer iframe does not change the behavior by its root node. |
|
I don't think we can allow the leaky behavior in shadow trees. Certainly not for closed shadow trees and probably not for open shadow trees either based on the discussion thus far. We could have an attribute to let non-shadow-tree iframes opt into this behavior, but for shadow trees I think it has to be mandatory. |
|
I see. I think Blink can live in a such a world. It sounds like that no one likes the current behavior of joint session history. Thus, we are changing the default behavior of iframes, with an exception for that being used in a document tree, due to the compatibility. That would make sense. |
|
FWIW, I agree with anne's latest comment (#184 (comment)) And we are not changing default behavior of anything. Shadow DOM is special so shadow DOM gets special handling. |
|
How does this attribute work, if the default is changed inside shadow DOM? That is: I assume it has a reflected property, a boolean It seems very weird to flip the default behavior inside shadow trees. |
|
@domenic I'm not sure we need an attribute, but if we do, it would be a no-op in shadow trees. (And we'd certainly not have magic like automatic attribute setting.) |
|
A joint session history was a design mistake, right? In other words, if we are allowed to design iframes from scratch, we never let iframes have such a behavior. Is my understanding correct? I thought that there is a use case of a joint session history, but I do not see any use case in this thread. If so, I am okay to re-design iframes for shadow trees. Forget joint session history at all. No new attribute. No customizable. For the compatibility, we will have legacy iframes in a document tree, which have a joint session history. |
|
Thanks @domenic for pointing it out. One way is that rip out the "isolatehistory" attribute at all and enforce the "isolatehistory" If someone come up with a serious need to become "isolatehistory" state in document, |
|
I'd like to add a clarification to my #184 (comment).
|
|
Yes, since moving iframe around DOM doesn't keep any of its history (even without any shadow DOM) anyhow. |
|
@TakayoshiKochi are you interested in working out a patch for this for HTML? |
|
Let me try, assuming no one objects to the proposals above. (was on a holiday week, will work on it next week) |
|
Clarification: Suppose the following tree: #document
<!-- A -->
<iframe name="IF1">
#document
... <!-- B -->
<iframe name="IF3">#document ... <!-- D --> ...</iframe>
</iframe>
<iframe name="IF2">
#document
... <!-- C -->
</iframe>
<shadow-host>
#shadow X
| <!-- E -->
| <iframe name="IF4">
| #document
| ... <!-- F -->
| <iframe name="IF5">#document ... <!-- H --> ...</iframe>
| </iframe>
| <iframe name="IF6">
| #document
| ... <!-- G -->
| <shadow-host2>
| #shadow Y
| | ... <!-- I -->
| | <iframe name="IF7">#document ... <!-- J --> ...</iframe>
| </shadow-host2>
| </iframe>
| <shadow-host3>
| #shadow Z
| | ... <!-- K -->
| | <iframe name="IF8">#document ... <!-- L --> ...</iframe>
| </shadow-host3>
</shadow-host>Any navigation in As #184 (comment) navigation in Then, if
It is still confusing at |
|
I don't understand the tree. Are the nested |
|
Yes, the nested |
|
It might help to repeat |
I think no. Any |
|
@smaug---- thanks for the comment (btw the comment seems having broken formatting, could you fix so I won't miss anything? - thanks for fixing!). I didn't have strong opinion about whether or not to merge |
|
I have been doing feasibility study and getting feedback from colleagues, and In the next comment I'll illustrate my current thinking of how browser UI's back/forward buttons |
|
One of the feedback for showing 'back/forward in this frame' in context menu is So I scratched the idea and started looking at how browser's back/forward buttons See this demo (Shadow DOM not included): The startpage (A1) has a link to next page (A2), and A2 has 2 As I understand browsers create a history entry for a snapshot of a page including Entry1: A1 Within each frame in the demo, it has 2 buttons (back/forward), which directly calls Next, let's assume those iframe B and C are enclosed in Shadow DOM, and There are choices how browser UI's back/forward buttons and each frame document's Question 1: what do browser UI's back/forward buttons work like? If it should be consistent with Question 2: If the answer to the previous question is the latter (UI back button can navigate Possible answer A: a newentry is created with the new state (Entry5) - then Entry1: A1 Possible answer B: the new history state replaces Entry3. Probably this is broken. Entry1: A1 Other answers? |
|
shadow iframe should have its own session history, and that could be exposed only to web page using history API. User doesn't know what is iframe and what is just some random element which content is changed dynamically. So there is no need to have any UI for the shadow iframe history. |
|
I think the point is: e.g.
As far as I understand, this is the current proposal, right? From user's perspective, 6 looks a weird movement. |
|
Yeah, the point is that navigation within This is slightly diverged from the original topic (window.history API) and the spec only says |
|
To amend what hayato said(#184 (comment)), we can keep a joint session history somewhere, and browser can use it for We used to have (implicit?) assumption that history objects in main page/iframes has |
|
@smaug----, in my #184 (comment)
I am not sure you got that point. Usually a user who clicks on a link would expect browser's back button would bring him/her |
|
To pose the problem in a flipped way, after the following user-initiated (click on link) navigation Entry1: A1 Each history object has the following list: A: [A1, A2] current index = 1 then A: [A1, A2] current index = 1 What will happen for each frame and each history object if browser UI's back/forward button |
|
In summary, here are options: 3.1: 3.2: One solution for the con of 3.1 could be that browser UI back/forward buttons don't follow the internal joint session history from the whole frame tree, but use the joint session history of top-level browsing context in the new world (i.e. session history exposed to the top-level
But this is with the downside that the browser back/forward behavior is different from Implementation feedback for 3.1 (specific to Chrome/Blink) is that lots of current code assumes the joint session history and the top-level page has 1:1 mapping, quite a lot of rework has to be done to separate the list, and UX breakage of browser back/forward buttons is anticipated. |
|
Well, shadow DOM is a different beast, effectively trying to hide some implementation details of random elements, which is why I think it is totally fine that the session history API inside shadow iframes is just an API thing, not affecting UI. And the API there is exposed anyhow largely to keep existing pages which use history API working even inside shadow iframes. 3.1, if implemented so that shadow iframe's session history doesn't show up in the UI, should be quite easy to implement in Gecko, but if we need to somehow combine the light and various shadow histories, the implementation, and UI, becomes a lot harder to implement. |
|
@smaug---- thanks for the feedback. we are also concerned about compatibility of existing pages embedded in shadow iframes. So 3.2 is not a viable option for us, though with 3.1 some implementation difficulties are foreseen as you wrote. @rniwa any opinions or ideas? @travisleithead anything from Microsoft? |
|
Let me try to move forward - we seem to get stuck, no perfect idea to solve all the constraints and concerns so far. As we illustrated in #184 (comment) and #184 (comment), if we had separated joint session history to document and shadow iframes, it is expected that there would be inevitable browser back/forward button behavior inconsistency against user expectation. If anyone cannot come up with a way to make it compatible with how back/forward button behaves on current browsers, we cannot mandate the separate list idea in V1. As in @annevk's #184 (comment)
there's much possibility that current behavior is anticipated. Any wisdom? |
Why such limitation? Why does the shadow iframe need to show up in the browser UI? However if we do want to expose shadow iframe navigations in UI, UI could merge the various session history trees by looking at the creation time of the entries. That is anyhow the approach the HTML spec has taken for the normal DOM. One problem with merging various session history trees in UI is that top level page's history.back()/forward()/go() wouldn't map to it anymore. I guess that is fine. |
The rationale for us is that "it works that way without shadow, why do we limit iframe history I'd say that having a separate history list for each iframe is a saner design For us, not including any shadow iframe history in browser UI back/forward button at all is not an option.
I thought a similar solution, and but once history API is used in shadow iframes and UI back button is used, it easily went to weird state or weird behavior, and we haven't come up with a clear solution. Could you have a more formal proposal/algorithm how it sanely works? |
|
I played a little bit with iframe but it looks like all browsers merge session history even for cross-origin navigations. Given that we're not certain special casing session history for iframe inside a shadow tree makes much sense but we don't have a strong opinion either way. We're curious what @travisleithead and the rest of Microsoft folks think of this matter. |
|
I am now checking the status of all Shadow DOM v1 spec issues. I would like to send an "Intent to ship: Shadow DOM v1" in Blink next week or later. |
|
Why wouldn't this be an important issue? And of course there isn't interoperability risk atm if there are no browsers shipping Shadow DOMv1, we can ship whatever random stuff at that point. The thing is that we need to get this kind of core issues sorted out before anyone ships, otherwise we'll end up to the same mess we have/had with previous Shadow DOM version. (Is it v0) |
|
@smaug---- Thank you for the feedback. @TakayoshiKochi, @rniwa, @smaug----, @travisleithead |
|
I could rephrase that a bit. s/Mozilla/smaug/ and a question is here that why would we be ok to break encapsulation here when we're trying to achieve it elsewhere? And functionally it is very surprising if the light dom can affect to the state of shadow iframes via history API, and even more surprising is if different shadow trees can affect to each others via history API. |
|
We understand your concern. The point we'd argue is that "history API usages cause unexpected behavior" (current behavior) vs "splitting session history for shadow iframes causes unexpected behavior for browser UI back/forward navigation". As I understand, no one has come up with a clear solution to the question posed in #184 (comment). In @smaug---- 's #184 (comment)
"UI would operate on the transaction list" is the tricky part. I don't think there are infinite options how UI back button would behave in this case, The most plausible idea I came up with was that such separated session history for So we are comparing cost/benefit of implementing the session history split vs Keeping the current behavior, basically no cost, but has negative benefit that you already On the other hand, splitting the session history, we foresee some non-ignorable implementation We are in the pragmatic position to favor the former.
I'd agree that UI back/forward list and top-level session can diverge, but this is not the |
This is what I'd do. Users don't know what an "iframe" is. and iframe could be implement by the page using just random div element which doesn't add anything to the session history.
Why? If user doesn't even know there is an iframe to navigate back<->forward, what is there to get confused? I would, at least initially, make shadow iframes to have separate session history so that we don't break existing pages using session history, yet don't leak information about shadow iframes to other shadow iframes or light DOM and not expose shadow history in UI. (In my mind not fixing session history for shadow DOM case is similar to the v0 shadow DOM where is-in-document issue was totally not figured out at all.) |
Suppose there are 2 components, one with Shadow DOM and the other without Shadow DOM I don't have the backing data to support this, such as how frequently this pattern would be used in real world, unfortunately. But I guess the situation happens for polyfilled Shadow DOM and native Shadow DOM for the time being until everyone implements. Having separate list and not exposing history to UI doesn't come as free. Even when we can So the question is whether we (browser implementors) can impose the (possible) pain to the users, |
|
I haven't read too far past #184 (comment), but for number 3 to be possible, which is
then this means that Nodes that are distributed into a ShadowDOM tree (into slot elements) must somehow be aware that they have been distributed into a ShadowDOM tree (even if the tree is closed) in order to decide to behave differently than when not in a ShadowDOM tree. There is currently no part of webcomponents spec (as far as I'm aware, please let me know if otherwise) that would explain how a Node can possibly be aware of such a thing as having been distributed into a shadow tree. So, this leads me to link here to an idea I made earlier: |
I'm leaning to this. (I got the same idea and then realized that perhaps it was proposed already) |
|
Thanks @smaug---- for giving more thought on this. How feasible do you feel for implementing it in Gecko/Firefox? I'm curious what do you think if you get back to Entry1: A1 |
|
@smaug---- any update on this? |
|
Sorry, no. I'm hoping this can be chatted during TPAC. But I'll try to look at this before that anyhow. |
See https://www.w3.org/Bugs/Public/show_bug.cgi?id=27325 for details.