Experience of using namespaces in client XHTML
Text Rostislav Chebykina.
I brought you a package. But I will not give it to you, because you have no documents.
Postman Pechkin
Together with Denis Lesnov, we are developing an audio player for the site, which was already told here in 2015 . Now an updated version is on the way, which can play not only individual tracks, but also entire playlists.
This article is not about the player itself, but about the unexpected phenomena that we encountered when trying to use real XHTML.
•
The main goal of our project is to enjoy joint programming. Therefore, we write code the way we like it and use technologies that interest us.
For example, I was interested in XHTML since the W3C Consortium published the first drafts of this standard, and many enthusiasts rushed to promote the updated language. At that time, many hoped that the entire Internet was about to switch to XML-compatible markup, and from this there would be a universal happiness.
On my own website, the web pages always followed the syntax of XHTML and were sent with the application / xhtml + xml type to the browsers that supported it. A few years ago, I generally stopped giving text / html.
By now, the hype around XHTML has subsided, the corresponding working group of the Consortium has closed after several years of prostration, and then enthusiasts have switched to other fashionable concepts. I’m sorry that many promising XHTML 2.0 ideas haven’t been so widely implemented. For example, the standard proposed that any element could be turned into a hyperlink by assigning to it the href
attribute:
<li href="/about/"> </li> <li href="/contacts/"></li>
Alas, this did not materialize, so for canonical idioms of web interfaces like “clickable” pictures, you still have to use the img
element and the a element separately, as in the early 1990s.
•
Maybe XHTML “didn’t take off” because enthusiasts never managed to demonstrate its practical advantages. On fan sites, the XHTML code was purely cosmetic in nature and did not contain anything that plain HTML would not provide. On the contrary, XHTML limited the old-school developers by not allowing their favorite document.write
and forcing to explicitly insert tbody
into each table.
In 2016, I finally decided to try the endemic possibilities of XHTML, namely the namespace. I wanted the components of the audio player to be self-made elements in their own namespace:
As expected, the namespace and its prefix are declared in the opening html
tag:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:p="http://rostislav.chebykin.ru/xmlns" lang="ru" xml:lang="ru">
The introduction of self-made elements in the code did not cause any problems, but it did not bring any benefit. The benefit should have come after these elements will take on the appearance with CSS and come to life with JavaScript. And here began the hitch.
•
First, at the stage of the initial testing of the idea, it turned out that the style
attribute does not work for homemade elements:
<p:track style="background: #999;" /> //
The corresponding attribute appears in the DOM tree, but the background element on the page is not painted in the specified color.
But when you connect a separate style sheet (in an external file or in the style
element), the CSS successfully operates, and self-made elements are drawn using the namespace selector:
p|track { background: #999; }
However, for this to work, the first rule in the style sheet is to declare @namespace
:
@namespace p url('http://rostislav.chebykin.ru/xmlns');
Thus, we managed to decorate the track
in the desired color and give the playhead
element a round shape. But it still did not provide the dynamics, which is the essence of the player interface. And this dynamic led us into the wilds.
•
To work with namespaces in the DOM there are methods createElementNS
and getElementsByTagNameNS
. Their behavior in some places confuses me: for example, the p|track
selector acts on an element regardless of whether the namespace prefix is specified in the second argument of createElementNS
:
const ns = 'http://rostislav.chebykin.ru/xmlns'; document.createElementNS(ns, 'p:track'); document.createElementNS(ns, 'track'); // p|track
But getElementsByTagNameNS
wants to get the name strictly without a prefix, no matter which of the two ways the element was created:
document.getElementsByTagNameNS(ns, 'track'); // HTMLCollection document.getElementsByTagNameNS(ns, 'p:track'); // HTMLCollection
But it still does not matter. The trouble began further when we tried to animate the whole structure through JS.
•
Moving the head of the player - it would seem, what could be easier? Get the desired position, convert it to a percentage and assign it to the left
property:
playhead.style.left = pos;
(Here, the playhead
variable points to the desired element in the DOM, and pos
is a percentage line in CSS format, such as '12.34%'
).
But no! It turns out that the playhead
does not have a style
property. To figure out why this happened, playhead
compare the playhead
prototype playhead
with the standard HTML element chain:
playhead: Element ← Node ← EventTarget ← Object div: HTMLDivElement ← HTMLElement ← Element ← Node ← EventTarget ← Object
The style
property, which provides access to the CSS properties of an element, is defined in the HTMLElement
interface and is absent from its parent Element
.
Trying to transfer the "native" style
from the HTMLElement
to homemade elements, we were defeated. Even if you just type in the console HTMLElement.prototype.style
, an error message HTMLElement.prototype.style
, and all the more so with this property you can’t do anything meaningful.
I had to use the CSS Object Model : dynamically connect external CSS, get to its rules, which have the same style
property, and nail this style
to the appropriate elements with nails:
const link = document.createElement('link'); // link' // head playhead.style = link.sheet.cssRules.item(1).style
After this, constructs like playhead.style.left = pos;
started working ... everywhere except Safari. Unexpectedly, it turned out that Element.prototype
does have a style
property in this extravagant browser, and the descriptors of this property do not allow it to be assigned anything. The problem was solved by redefining the style
personally for our elements:
Object.defineProperty(playhead, 'style', { writable: true });
•
Finally, a separate surprise was how the querySelector
, querySelectorAll
and matches
methods that take CSS selectors as arguments are bypassed with namespaces, for example:
document.querySelectorAll('p|track'); playhead.matches('p|playhead');
Here, each browser found its own words to express bewilderment:
Edge | NamespaceError |
Chrome | Uncaught DOMException: Failed to execute 'matches' on 'Element': 'p | playhead' is not a valid selector |
Firefox | SyntaxError: An invalid or illegal string was specified |
Safari | NamespaceError (DOM Exception 14): Namespaces in XML |
The reason is that the listed methods cannot resolve the prefix p
and associate it with the corresponding namespace. In XHTML, there is an xmlns
attribute for declaring namespaces, @namespace in CSS, and @namespace
in JavaScript! - there is nothing. Characteristically, the document.createNSResolver
method works in browsers, but its result is not screwed to methods of the querySelectorAll
type.
The Selectors API says that "namespace prefix needs to be resolved," but is immediately attributed: "This specification does not provide support for resolving arbitrary namespace prefixes." Interestingly, in the draft versions of the specification there was an NSResolver interface and a corresponding argument was proposed in the "selector" methods:
Element querySelector(in DOMString selectors, in NSResolver nsresolver);
However, on the way to the recommendation of the W3C, NSResolver
was villainously drank, and as a result, the specification behaves like the postman Pechkin: “I brought you a package, only I will not give it to you, because you have no documents”.
I would not be surprised if in a few years the Consortium declares XHTML language deprecated and obsolete, and browsers refuse to support application / xhtml + xml. I hope that before this time Denis and I will be able to finish the next version of the audio player so that it will be preserved on the Internet at least as a museum piece.
Source: https://habr.com/ru/post/318984/
All Articles