[whatwg] <a onlyreplace>
Ian Hickson
ian at hixie.ch
Sun Oct 18 02:30:21 PDT 2009
On Fri, 16 Oct 2009, Aryeh Gregor wrote:
>
> I'm drawn back to my original proposal. The idea would be as follows:
> instead of loading the new page in place of the new one, just parse it,
> extract the bit you want, plug that into the existing DOM, and throw
> away the rest. More specifically, suppose we mark the dynamic content
> instead of the static.
>
> Let's say we add a new attribute to <a>, like <a onlyreplace="foo">,
> where "foo" is the id of an element on the page. Or better, a
> space-separated list of elements. When the user clicks such a link, the
> browser should do something like this: change the URL in the navigation
> bar to the indicated URL, and retrieve the indicated resource and begin
> to parse it. Every time an element is encountered that has an id in the
> onlyreplace list, if there is an element on the current page with that
> id, remove the existing element and then add the element from the new
> page. I guess this should be done in the usual fashion, first appending
> the element itself and then its children recursively, leaf-first.
On Fri, 16 Oct 2009, Tab Atkins Jr. wrote:
>
> Single-page apps are already becoming common for js-heavy sites. The
> obvious example is something like Gmail, but it's becoming more common
> everywhere. The main benefit of doing this is that you never dump the
> script context, so you only have to parse/execute/apply scripting *once*
> across the page, making really heavy libraries actually usable.
>
> In fact, writing a single-page app was explicitly given as a suggestion
> in the "Global Script" thread. Even in contexts with lighter scripts,
> there can still be substantial run-time rewriting of the page which a
> single-page app can avoid doing multiple times (frex, transforming a
> nested list into a tree control).
>
> The problem, though, is that single-page apps are currently a bit clunky
> to write. They require javascript to function, and the necessary code
> is relatively large and clunky, even in libraries like jQuery which make
> the process much simpler. It requires you to architect your site around
> the design, either producing a bunch of single-widget files that you
> query for and slap into place, or some relatively complex client-side
> logic to parse data structures into HTML. It's also very hard to get
> accessibility and graceful degradation right, requiring you to basically
> completely duplicate everything in a static form. Finally, preserving
> bookmarkability/general deeplinking (such as from a search engine)
> requires significant effort with history management and url hacking.
>
> Aryeh's suggestion, though, solves *all* of these problems with a single
> trivial attribute. You first design a static multi-page site like
> normal, with the only change being this attribute on your navigation
> links specifying the dynamic/replaceable portions of the page. In a
> legacy client, then, you have a perfectly serviceable multipage site,
> with the only problems being the reloading of js and such on each
> pageload.
>
> In a supporting client, though, clicking a link causes the browser to
> perform an ordinary request for the target page (requiring *no* special
> treatment from the author), parse/treebuild the new page, and then yank
> out the relevant fragments and replace bits in the current page with
> them. The url/history automatically updates properly; bookmarking the
> page and visiting it later will take you to appropriate static page that
> already exists. Script context is maintained, listeners stay around,
> overall page state remains stable across 'pageloads'.
>
> It's a declarative, accessible, automatic, and EASY way of creating the
> commonest form of single-page apps.
>
> This brings benefits to more than just the traditional js-heavy apps. My
> company's web site utilizes jQuery for a lot of small upgrades in the
> page template (like a hover-expand accordion for the main nav), and for
> certain things on specific pages. I know that loading the library, and
> applying the template-affecting code, slows down my page loads, but it's
> not significant enough to be worth the enormous effort to create an
> accessible, search-engine friendly single-page app. This would solve my
> problem trivially, though, providing a better overall UI to my visitors
> (snappier page loads) without any real effort on my part, and without
> harming accessibility or SEO.
>
> This also trivially replaces most/all uses of bad mechanisms like
> <frameset> used to address similar problems (such as maintaining state
> on a complex nav).
>
> The only addition I'd make to this is to allow a tag in the <head> that
> specifies default replaceability for all same-origin links. Perhaps just
> an attribute on <base>? It would accept a space-separated list of ids,
> just like the @onlyreplace attribute on <a>s. An @onlyreplace attribute
> on a link would completely override this default (this would allow me
> to, frex, have the mainnav only replace the subnav, while all other
> links replace the content instead).
>
> I believe that the single-page app pattern solves a lot of problems that
> exist today and will persist into the future, and that it's worthy of
> being made into a declarative, html-supported mechanism. I also believe
> that Aryeh's suggestion is the correct way to go about this.
>
> The only problem I can see with this is that it's possible for authors
> to believe that they only need to actually write a single full page, and
> can just link to fragments containing only the chunk of content to be
> replaced. This would mostly break bookmarking and deeplinking, as
> visitors would just receive a chunk of unstyled content separated from
> the overall page template. However, because it breaks so *visibly* and
> reliably (unlike, say, framesets, which just break bookmarking by
> sending you to the 'main page'), I think there would be sufficient
> pressure for authors to get this right, especially since it's so *easy*
> to get it right.
On Fri, 16 Oct 2009, Tab Atkins Jr. wrote:
>
> 1. <iframe>s, like frames before them, break bookmarking. If a user
> bookmarks the page and returns to it later, or gets deeplinked via a
> search engine or a link from a friend, the <iframe> won't show the
> correct content. The only way around this is some fairly non-trivial
> url-hacking with javascript, altering the displayed url as the user
> navigates the iframe, and parsing a deeplink url into an appropriate url
> for the iframe on initial pageload. @onlyreplace, on the other hand,
> automatically works perfectly with bookmarking. The UA still changes
> urls and inserts history appropriately as you navigate, and on a fresh
> pageload it just requests the ordinary static page showing the
> appropriate content.
>
> 2. <a target> can only navigate one iframe at a time. Many/most sites,
> though, have multiple dynamic sections scattered throughout the page.
> The main site for my company, frex, has 3 (content, breadcrumbs, and
> section nav) which *cannot* be combined to display as a single <iframe>,
> at least not without including a whole bunch of static content as well.
> You'd have use javascript to hook the links and manually navigate the
> additional iframes. @onlyreplace, on the other hand, handles this
> seamlessly - just include multiple ids in the attribute value.
>
> 3. <iframe>s require you to architect your site around them. Rather
> than a series of independent pages, you must create a single master page
> and then a number of content-chunk mini-pages. This breaks normal
> authoring practices (though in some ways it's easier), and requires you
> to work hard to maintain accessibility and such in the face of these
> atrophied mini-pages. @onlyreplace works on full, ordinary pages.
> It's *possible* to link to a content-chunk mini-page instead, but this
> will spectacularly break if you ever deeplink straight to one of the
> pages, so it should become automatic for authors to do this correctly.
>
> 4. <iframe>s have dubious accessibility and search effects. I don't
> know if bots can navigate <a target> links appropriately. I also
> believe that this causes problems with screen-readers. While either of
> these sets of UAs can be rewritten to handle <iframe>s better (and
> handle @onlyreplace replacement as well), with @onlyreplace they *also*
> have the option of just completely ignoring the attribute and navigating
> the site as an ordinary multi-page app. Legacy UAs will automatically
> do so, providing perfect backwards compatibility.
>
>
> 1. One of the big beneficiaries of @onlyreplace will be fairly ordinary
> sites that are currently using an ordinary multi-page architecture.
> All they have to do is add a single tag to the <head> of their pages,
> and they automatically get the no-flicker refresh of a single-page app.
> These sites are *already* grabbing the whole page on each request, so
> @onlyreplace won't make them take any *additional* bandwidth. It will
> merely make the user experience smoother by reducing flicker and keeping
> js-heavy elements of the page template alive.
>
> 2. Even though site templates are usually weighter than the dynamic
> portions of a site, it's still not a very significant wasteage. For
> comparison, my company's main site is roughly 16kb of template, and
> somewhere around 2-3k of dynamic page content. (Aryeh - I gave you
> slightly different numbers in chat because I was counting wrong.) So
> that's a good 85% of each request being thrown away as irrelevant.
> However, it's also *only 16kb*, and that's UNCOMPRESSED - after standard
> gzip compression the template is worth maybe 5kb. So I waste 5kb of
> bandwidth per request. Big deal. (According to Philip`, my company's
> site's weight is just on the low side of average.)
>
> 3. Because this is a declarative mechanism (specifying WHAT you want,
> not HOW to get it), it has great potential for transparent optimizations
> behind the scenes. For example, the browser could tell the server which
> bits it's interested in replacing, and the server could automatically
> strip full pages down to only those chunks. This would eliminate
> virtually all bandwidth waste, while still being completely transparent
> to the author - they just create ordinary full static pages. Heck, you
> could even handle this yourself with JS and a bit of server-side coding,
> intercepting clicks and rewriting the urls to pass the @onlyreplace data
> in a query parameter, and have a server-side script determine what to
> return based on that. Less automatic, but fairly simple, and still
> easier than using JS to do this in the normal AJAX manner. (And UAs
> that don't run javascript but do support @onlyreplace will still work
> properly, just with a bit more bandwidth waste.)
>
>
> Semantically the replace operation should be identical to grabbing the
> appropriate chunk of text from the new page and setting is as the
> outerHTML of the appropriate element. Any <script>s that are located
> within this chunk would run in the exact same manner. Scripts elsewhere
> in the new page would not be run.
>
> document.write()s contained in <script> blocks inside the target
> fragment will run when they get inserted into the page, but
> document.write()s outside of that won't. Producing the target fragment
> with document.write() is a no-go from the start. Don't do that anyway;
> it's a bad idea.
[...]
On Fri, 16 Oct 2009, Jonas Sicking wrote:
>
> We actually have a similar technology in XUL called "overlays" [1],
> though we use that for a wholly different purpose.
>
> Anyhow, this is certainly an interesting suggestion. You can actually
> mostly implement it using the primitives in HTML5 already. By using
> pushState and XMLHttpRequest you can download the page and change the
> current page's URI, and then use the DOM to replace the needed parts.
> The only thing that you can't do is "stream" in the new content since
> mutations aren't dispatched during parsing.
>
> For some reason I'm still a bit uneasy about this feature. It feels a
> bit fragile for some reason. One thing I can think of is what happens if
> the load stalls or fails halfway through the load. Then you could end up
> with a page that contains half of the old page and half the new. Also,
> what should happen if the user presses the 'back' button? Don't know how
> big of a problem these issues are, and they are quite possibly fixable.
> I'm definitely curious to hear what developers that would actually use
> this think of the idea.
See also Daniel's HTMLoverlays:
http://disruptive-innovations.com/zoo/20040830/HTMLoverlays.html
[...]
On Sat, 17 Oct 2009, Dion Almaer wrote:
>
> This feels like really nice sugar, but maybe the first step should be to
> get the shim out that gets it working using JS now.... and then see how
> it works in practice. I totally understand why this looks exciting, but
> I have the same uneasiness as Jonas. It feels like a LOT of magic to go
> grab a page and grab out the id and ..... and I am sure there are edges.
> Cool idea for sure! It also feels like this should work nicely with the
> history/state work that already exists.
On Sat, 17 Oct 2009, Jonas Sicking wrote:
>
> Yeah, I think this puts the finger on my uneasiness nicely. There's
> simply a lot of stuff going on with very little control for the author.
> I'd love to see a JS library developed on top of pushState/
> XMLHttpRequest that implements this functionality, and then see that JS
> library deployed on websites, and see what the experiences from that
> are.
>
> If it turns out that this works well then that would be a strong case
> for adding this to browsers natively.
>
> In fact, you don't even need to use pushState. For now this can be faked
> using onhashchange and fragment identifier tricks. It's certainly not as
> elegant as pushState (that is, after all, why pushState was added), but
> it's something that can be tried today.
On Sat, 17 Oct 2009, Nelson Menezes wrote:
>
> Well, here's a badly-hacked-together solution that emulates this
> behaviour...
>
> I think it'll be helpful even if it only gets used in a JS library as
> you mention (change the attribute to a classname then). Still, it can be
> made to work with today's browsers:
>
> http://test.fittopage.org/page1.php
On Sat, 17 Oct 2009, Schuyler Duveen wrote:
>
> If you'd like to see what this looks like in Javascript, I implemented
> this technique several years ago. One place you can see it publicly is
> the swapFromHttp() function at:
> http://havel.columbia.edu/media_panels/js/MochiPlus.js
>
> You can see it in action on some pages like:
> http://havel.columbia.edu/media_panels/video_window/?material=abrams
> where it adds in the page on the left from this file
> http://havel.columbia.edu/media_panels/materials/abrams.html
>
> One of the big issues we found using it on some other sites is that
> javascript listeners (rather than onclick="" attributes), and other DOM
> pointers in the system became stale. Thus, only half the problem was
> solved.
>
> Also, the problem (as I implemented it) is that XMLHttpRequest.xml has
> been very finicky in past (and current) browsers. My comments in the
> code reflect some of the things you need to make sure you're doing to
> make it work across browsers (at least if you want a DOM vs. regex
> implementation):
>
> * IE 6 needed the Content-type: text/xml
>
> * Firefox (?2.x) wants xmlns="http://www.w3.org/1999/xhtml" in html tag
>
> * IE and Safari don't handle named entities like well in this
> context and should be numeric (e.g.  )
>
> Vendors might better serve us by reducing these hoops to jump through so
> a javascript library could do the job reliably.
>
> This method did make it much easier to leverage server template code.
> But since it largely simplifies server template code, then why not stick
> with server-side solutions like Ian Bicking's:
> http://blog.ianbicking.org/2008/09/08/inverted-partials/
>
> It's still a bit weird that this proposal, instead of allowing every
> element to be a link (like XHTML2), would allow every element to be
> something like an IFRAME (all while a thread remembering how evil
> framesets are continues).
My recomendation would be to follow the process for adding features:
http://wiki.whatwg.org/wiki/FAQ#Is_there_a_process_for_adding_new_features_to_a_specification.3F
In particular the bit about experimental implementations. I think this
idea looks very interesting, but it's hard to evaluate without concrete
experience with a browser implementing this (or, as Jonas suggests, a
library that hacks it in).
It seems like the kind of thing that we could adopt early on in the next
feature cycle, if it turns out to be a good solid model.
--
Ian Hickson U+1047E )\._.,--....,'``. fL
http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,.
Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
More information about the whatwg
mailing list