Fun fact -- in V8 this is the only case which requires three token lookahead, to distinguish `<!-foo` meaning "less-than not negative foo" from `<!--` meaning "start of HTML comment". There's a whole rewinding mechanism in the scanner which wouldn't have to exist if not for this syntax.
"The scanner chooses a specific scanner method or token based on a maximum lookahead of 4 characters, the longest ambiguous sequence of characters in JavaScript"
In useful code sure. But `<!-f` with its dynamic casting implications may be useful in code golf. I haven’t golfed in years so I’m not sure, but I can imagine it having some benefit I haven’t though of.
For anyone confused, this is actually (semi) sane behavior by javascript standards, because it relies on `-"f"` evaluating to NaN.
Of course, because javascript, there are other string values of `f` for which the two statements are equal as well. (e.g for empty string both statements are true because `-"" === -0`, and for "1" both values are false)
I’ve tried three times to write why I think this is, and each time I get lost in my reasoning. Alas, I’ve been on mobile for this whole thread and I don’t have any more brain cells to try to code like this tonight lol
It's because `f = new Number(0)` is a boxed number (therefore it's an object), and `!f` calls ToBoolean on this object which unconditionally returns true (https://tc39.es/ecma262/#table-toboolean-conversions). `!-f` first applies unary minus, which first performs a ToNumber on the f object (which returns unboxed 0), that's negated to -0, and then ToBoolean of -0 is false.
Right. My question was to ask what it would take to remove it. Backwards compatibility is a concern, but could strict mode or some other flag be used to mark it as disabled?
Comment 0 gets removed by the XML parser so it doesn't go into the alert string. Comment 1 is seen by the JavaScript parser and gets removed at that stage.
Demonstration of this, using a data: URL (paste it in the address bar):
data:application/xhtml+xml,<script xmlns="http://www.w3.org/1999/xhtml">%0Aalert("Hello <!-- Comment 0 -->world");%0A<!-- Comment 1%0Aalert("Bonjour le monde");%0A</script>
(Observe also how what I’ve written here nets you a document that lacks html, head and body tags—HTML syntax fills those in through the magic of optional start and end tags, but XML syntax takes what it’s given and can be used to do things like nesting hyperlinks or putting a heading inside a paragraph. The HTML and XML syntaxes for HTML are actually mutually incompatible.)
Very nice use of media types and data URIs! Indeed, the root of your document is <script>, which is rather funny. Of course HTML and XML syntaxes are incompatible, but there is a reasonable polyglot subset that is compatible with both.
Other common things that HTML syntax won't let you do: <p><p></p></p>, <table><tr><td> without an implicit <tbody>.
A fun thing that I learned recently is that `table > tr` is actually valid, the tbody is genuinely optional in the spec, even though the HTML syntax injects it.
thead/tfoot/tbody were introduced in HTML 4, with tbody mandatory (that is, `table > tr` was now invalid), but implied (that is, its start and end tags were both optional, so that <table><tr>…</tr></table> would be parsed the same as <table><tbody><tr>…</tr></tbody></table>). Source: https://www.w3.org/TR/html4/struct/tables.html#h-11.2:
<!ELEMENT TABLE - -
(CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)>
<!ELEMENT TBODY O O (TR)+ -- table body -->
I’m pretty sure that this will be the reason it’s optional in the HTML spec, since there’d be no point in it being optional otherwise, since it’s not attainable in the HTML syntax.
Ah, the times when I was always trying to serve my site in the strictest way possible. I religiously followed everything Anne van Kesteren [0] wrote, and used his code-snippet [1] to serve application/xhtml+xml to browsers that supported it. He was my same-aged teenage hero :)
Yup that's not valid polyglot HTML5/XHMTL code. In HTML < (and &) aren't special (except at the end tag). But in XHTML < is treated as a tag. Here's the link to that part of the spec for anyone interested:
Huh, that's really interesting, the Firefox dev tools even do proper syntax highlighting. I wonder how JSX parsers react to this. A quick test with an online Babel parser is throwing errors, so I assume it's just not supported? But maybe there's a setting.
JSX also by default doesn't have an easy way to insert comments into the generated HTML, so I don't think JSX is the reason why it wouldn't be supported in Babel. My understanding was always that it has more to do with comments being treated slightly differently than normal document nodes, but I could be wrong.
I guess more likely the reasoning is that it's just obscure. I've been programming JS for a reasonably long time and never knew this was supported.
A challenge: figure out how to get to the script data double escaped state (https://html.spec.whatwg.org/multipage/parsing.html#script-d...), or perhaps cheat by looking at https://stackoverflow.com/questions/23727025/script-double-e.... Then, contemplate the implications, and devise an injection attack for something that is foolish enough to try to emit anything user-controllable into JavaScript (suppose it’s a string: they may have thought it was enough to escape \ and ", but this will rapidly show you that it’s not).
Reading through the specs reveals lots of curious historical details. The HTML spec is a glorious tangled mess because it’s an exhaustive definition of a large amount of functionality that grew⸺ ah⸺ organically.
The reason for the error from Babel is that JSX is an HTML like (more so XML) syntax, not HTML. The obtuse comment syntax is because you need to escape to JavaScript with the braces, then use a multi-line JavaScript comment block. I wish they would've allowed HTML comments in the original design, but my guess is that comments were an oversight that just happened to work due to the escape syntax.
One good reason not to support it is that it’s ambiguous: is it a comment (to be ignored), or does it represent a comment node? If the former, why not just use /…/? If the latter, it requires that the library or compilation target or whatever support comment nodes, which is more work for a dubious feature.
I'd argue that comments only serve to help the developer. And when using JSX, the generated HTML might not look pretty (such as being a single, long line). So an HTML style comment in the JSX should be stripped because debugging the minified HTML isn't something people generally do.
And if, for some reason, you wanted to inject an HTML comment into the output, you could abuse the `dangerouslySetInnerHTML` prop like this:
There are other use cases for (preserved) HTML comments in (or produced by) JSX, but generally more for library authors than end users. For example, comments can be used for hydration markers to delineate “hydration islands” without need for a wrapping element. (I have a proof of concept of this sitting in a Codepen somewhere.)
And while it doesn’t work in React’s Fragment, it can certainly work with another compiler. JSX doesn’t specify anything about what it compiles to, React.createElement/_jsx are just defaults.
The syntax highlighting in Fx dev tools has the same mistake as the article in that they only recognize the "close comment" token if it's at the beginning of the line, even though the spec clearly states that it may be preceded by any number of single-line "multiline" comments on the same line.
However, the way I understand the spec, you shouldn't be able to start a line comment with `-->' after an actual multi-line comment (i.e. a delimited comment that contains line terminators); however, both Firefox and Chrome seem to disagree with my interpretation; for example
i = 1;
while (i /*
*/ --> 0
)
console.log(i); // this loop never terminates
Important footnote: Unless you are in an JavaScript module file. They work in scripts only. E.g. the following is a syntax error in a module but a valid script:
<!-- ok if it's a script only
--> console.log("ok");
It's actually not related to strict mode. HTML comments work fine in strict mode as well as sloppy mode in scripts. The difference here is that modules are a different file format / syntax and they fundamentally don't include parts of the syntax that was supported in the older script file format (and vice versa: they allow syntax like top-level await that wasn't/isn't valid in the script file format).
Technically, they "work" in both scripts and modules, they just work differently in each case. This is valid Javascript that returns true if running in script mode or false if running in module mode:
const isScript = (x = true) => x <!--x
console.log(isScript()) // true or false depending on whether the code is ESM
What's happening is that `<!--` is a comment token in script mode, but it's parsed as `< ! --` in module mode.
IE also had a custom image filtering scripting language embedded in CSS that was pretty dangerous, you could easily hang someone's whole computer if you weren't careful. A common hack to find was adding png transparency which IE infamously lacked, at great computational cost to the user (this was at a time where the lack of other CSS features made PNG transparency quite necessary for building fancy UIs).
It's worth pointing out that many of the old ugly things were IE specific including the feature referenced by the parent comment... it was a time when "standard" had little weight, although some of the good ideas like box-sizing were adopted by W3C.
Today we have CSS custom properties which do similar things:
- Authors can define custom properties as long as they start with a double-dash, like --demo
- Authors can leave these values empty, or put any code that doesn't break CSS's syntax inside. This can be CSS values, it can be JSON, it can be other languages, even some JavaScript could be stored in CSS to be read later
- Using JavaScript you can read the values of CSS custom properties, and set them
So it's possible with a tiny bit of JS to re-create what the old IE expression() function used to do in any modern browser in a fully standards-compliant way
To do what expression() could do you need several event listeners at least which, I mean, of course you can still do it, but it's really unrelated to CSS Properties and just JavaScript at this point.
This is actually part of the design of CSS custom properties. It's not an abuse, but part of how they've been designed to be used. You can trigger updates from your own code programmatically, as well as any event listeners (built-in or custom) or from Observers the browser may have (e.g. Resize Observer, Intersection Observer, Mutation Observer) or any other ways you want to update them!
I would not recommend this, I think it's more trouble than its worth, the syntax highlighting isn't going to be great, and I think you're just going to confuse your coworkers, but if you really want to, you can take advantage of the fact that CSS ignores rules that it doesn't recognize.
.Component__child {
TODO: add theming support
}
Of course, you have some restrictions around syntax here (again, I didn't say I advise doing this), and of course if CSS ever adds a TODO rule you might run into problems.
Do not practice writing invalid CSS, if this gets out online on the internet it will prevent any read `todo` property from being used because people are camping on CSS's name space.
Instead, any author is allowed to invent _any_ property, so long as the property name begins with a double-dash (--) and you can put anything inside as a value so long as it doesn't break CSS syntax
a {
--note:
So you could do this instead and it would be standard CSS, perfectly fine for all people forever!
;
}
Hah, this is my brain thoroughly broken by forced IE-compatibility for so long on legacy apps, but I completely forgot about custom properties when I was writing that comment! You're right, that's a much better solution.
I still don't think I recommend it, because sure it gets rid of the problem of accidentally breaking CSS namespace, but I still think in most cases sticking comments inside of a property is going to end up confusing people on a team more often than it will help, and there are still some syntax issues and conflicts with your own internal variables that can happen.
But for sure, if you're going to use properties for notes, make them custom properties.
----
Edit: I particularly don't recommend this, but off the top of my head using custom properties you also might be able to rig this up with something like `:before` pseudo-classes to even display some of your CSS comments visibly in the page via `content` or by building style toggles[0] or something.
Again, I feel like this is getting too clever for its own good, but as long as we're playing around...
This isn’t much different from the typical JSON comment hack:
{
"//": "comment goes here"
}
Most editors and tooling also know this is commonly use and ignore validation of repeated keys. Unfortunately it doesn’t much help with arrays unless you specifically handle the case (and depending on usage, handle escaped cases as well).
The reason CSS will never have //-style single-line comments is that the entire CSS language is parsed as a single line, so if you ever entered a //-style single line comment there would be no return from it for the rest of the input stream.
(Kind of like the <plaintext> element in HTML, once you write the <plaintext> open tag all text after that is plain text, so you can't write a </plaintext> to get out of it - the whole rest of the file is in that mode with no return)
This sets the property named "//property" to "value". Close enough. (Expressed otherwise: it’s approximately a comment until the next semicolon, barring quoted strings and parentheses.)
//selector {
property: value;
}
This is an invalid selector, and so the entire rule is ignored. (Expressed otherwise: it’s approximately a comment until the next opening curly brace’s matching closing curly brace.)
It is faster to type // than /* ... */ . Any time you type the same character twice it is much faster than typing two separate characters.
Further because I write a lot of JavaScript too I sometimes make the mistake of putting a // -comment into my CSS which breaks things. And when things break in CSS you usually don't get a clear error-message about it.
It is always difficult to switch between two languages. I would prefer something like JavaScript stylesheets, if that was possible.
True. But the IDE can of course help. In WebStorm I can select multiple lines of code and press Ctrl-/ to have them all turned into single-line comments if they were not, and uncomment them if they were.
Single-line comments have the benefit that it is always clear to the reader which lines are comments. Whereas if you use multi-line comments to comment a large section of code it is no longer clear when reading it whether it is indeed "inside" a comment.
And finally having both types of comments available is useful because you can multi-line-comment a section which already contains // -comments, whereas you can not multi-line comment a section which already contains multi-line comments.
This seems like the worst of both worlds. If you're going to use the /* */ I don't see why you'd bother with // unless it's about recognizing a comment in a single line.
I have done the same type of thing to comment out lines of a json file used for configuration . Append “//“ or something to the beginning of a key that I want to have temporarily “commented out”. (Be careful as some programs might expect those keys not to be there of course.)
Me too. I expect though that there'd be lots of breaking changes around existing CSS having, for instance,`background-image: url(https://somedomain.abc/somefile.png)`, as quotes are optional in URL values
Note that //foo/bar.txt is a valid address (a “network-path relative URI reference”[1]). Those are rarely seen but are used sometimes when the same resource or snippet needs to be usable with both HTTP and HTTPS. (I think I first learned about this form while reading a text on gradual migration to HTTPS circa 2014.)
My impression is this form might actually be the original way of expressing network paths, what with UNC in Windows (\\server\share\file etc.) and POSIX carving out an exception specifically for two slashes at the beginning of a pathname (that is, foo//bar is the same as foo/bar and ///foo/bar is the same as /foo/bar, but //foo/bar may or may not be the same as /foo/bar).
Out of curiosity, what editor do you tend to use? Commenting has been a single shortkey for me for so long that I had to remind myself that CSS doesn't support something like the // syntax because my normal editing flow is to either start typing or select text and hit Command+/.
Maybe worth mentioning tangentially related WTH of JS syntax: that there are two additional line breaks besides CR and LF: line separator (\u2028) and paragraph separator (\u2029).
Some editors and text viewers render them as zero width spaces, so you can see something that seems like innocent line comment but what is actually executed:
view-source of that document displays just `<script>//alert(1)</script>` in Firefox. In Chrome there is "P SEP" in dashed rectangle between `//` and `alert`, so you at least get a hint there is something fishy.