Hacker News new | past | comments | ask | show | jobs | submit login
CSS-Only Chat (github.com/kkuchta)
295 points by janandonly on June 30, 2023 | hide | past | favorite | 83 comments



The readme is clear and also hilarious. I love this kind of thing. Anyway, this part sounds like the sort of obscure browser idiosyncrasy that I'll read about in some exploit writeup years from now:

> What's cool is that a browser won't actually load that background image until this selector is used

Intuitively it strikes me as leaky, fingerprintable behavior. I don't see any obvious problem with it, but it does vaguely remind me of those hacks that could exfiltrate browsing history with clever usage of the :visited selector.


Yeah, the original inspiration for this was a tweet where the poster was using that behavior to leak cursor position (by having a big grid of divs with hover-over css classes with background images)!


If the only requirement is "using no JavaScript", you know that you don't need CSS either, right? Dark web chatrooms just use frames — one frame to render the chat transcript (using a forever-loading "Transfer-Encoding: chunked" HTML page); the other with a plain old <form> with an <input type="text"> and a <submit>.


CSS is needed because this app isn't using HTML forms to send the data. That would be easier, but part of the magic here is that in addition to no JavaScript, the page also never reloads.

The readme explains how the CSS :active selector is used to detect button presses.


> the page also never reloads

Well, that's really only technically correct, since the strategy here is to replace the whole page with a new version of it on each virtual keypress, by using CSS to hide the previous HTML and then receiving the new updated version of the web page's content. The only tricks is to use a chunked content-transfer to have this all happen over a single HTTP request, so yes technically the page does noes reload, but it's pretty much the same thing as if it did.

Really cool trick nonetheless! And more importantly fun trick, and fun read :).


I think it'd at least eliminate some of the overhead with establishing new connections on every request with HTTP/1.1 or HTTP/2, but I'm not sure about HTTP/3


I mentioned multipart/x-mixed-replace above and I think it can work here instead of CSS. You never reload the chat history page, just put that in an iframe and use a separate iframe with a form that submits your newest reply.

Edit: actually this should work even without mixed replace.


When the form submits its frame refreshes ("navigates").


Right but reloading a static html asset (the reply iframe consisting of just a textbox) is basically free. So long as you separate the chat history window and the reply textbox/form into two separate frames, I don’t see the problem.


Using JavaScript is also “basically free”.

There’s no problem with either listed approach, GP just seems to consider a method without page reloads as adhering to a harder constraint.


Using JS would have broken the threat model of the dark web chatroom. So it is a non starter in that context.


I thought chrome killed x-mixed-replace (except for jpg images)



This wasn't a "dark web" thing in the late 90s, it was widely used. Unfortunately due to the awfulness of search engines today I can't find it now, but I remember there's a PHP script called "moonchat" which was somewhat common and JS-less.



There’s also multipart/x-mixed-replace for rendering only the latest update (replacing previous content) but iirc Chrome dropped support for that when content type is HTML [0].

[0]: https://news.ycombinator.com/item?id=7349266


I can tell you that it still works in chrome, this method was used by one of my coworkers as a quick and dirty hack until we had time to implement a real solution for data streaming. It worked fine in all major browsers ~2 weeks ago.


I’m not sure what context you were using it in? It still works for non-HTML content types, can be used for mjpeg video streams, etc but you shouldn’t be able to use it to replace the previously rendered HTML contents of a frame.


Hmm I don't remember if we did dom manipulation in there. It was definitely used for video streaming though. There's a good chance we only used it for mjpeg and canvas shenanigans.


In the 90s we used to just call them “chat rooms” (or “HTML chat” if we wanted to differentiate for stand alone clients like IRC).

I even wrote one myself.


I loved them; probably nostalgia, but I was having much more fun with those than today's chatrooms. I also preferred them to IRC for some reason.


Implemented here in haskell, didn't even add screenshots back then ^^'

https://github.com/elikoga/jsless-chat


very cool!


Can we please have a code example for this technique or any similar way of not using JavaScript for this feature set? This is very interesting!

Thanks!


Chatgpt-4 seems to do fine if you ask it to provide the php.

This tech was used in the nineties by a finnish chat site operated by a radio station. I used to go on dates from the site myself. Thought it would be valuable to have this archived in english too

https://www.iltalehti.fi/fiidifi/a/2015021119172724

”KissFM Chat - do you still remember? For many, KissFM's chat was their first contact with the internet.

This is what it looked like back then. KISSFM

Mari Pudas Thursday, February 12, 2015 at 10:40

In the mid-1990s, not every home had an internet connection, in fact, it was quite a luxury. But fortunately, there were computers with internet connections in libraries. Under the watchful eye of the librarian, you could use the computer for up to an hour, sometimes just half an hour.

There were no Youtubes, not to mention Facebook or Twitter. So what did we do on the internet back then? Of course, we went to KissFM's chat!

Kiss FM's chat was founded in 1996, and was initially known as a hotel. Around 1998, the chat site got a brighter, greenish color scheme and the hotel was abandoned. The chat became Chatropol. There you chose a "room" to chat with like-minded people based on your interests.

The most popular rooms, cafe, disco, erotic house, and singles bars, were always occupied, as they could only accommodate about a dozen chatters at a time. Then you had to be content with the office building or the hairdresser. But regardless of the name, the conversation was often hilariously fun.

Over the years, its popularity waned and Kiss also became Voice. But let's let the former chatters reminisce about Kiss's golden age:

My friend and I used to use the names of Finnish schlager stars as our nicknames in the Kiss FM chat. We didn't intend to deceive anyone, we just thought it was a fun joke. Until "Marita Taavitsainen" received a private message thanking her, saying that the new album is wonderful. We politely thanked and that ended the use of real names due to a bout of bad conscience.

Ilona

I spent time and looked for some company while studying in Tampere at the beginning of the millennium. I enjoyed most in the Tampere section of Kiss FM's chat, where I held a quiz for other chatters - the fastest correct answer gets a point, and ten points to win. My nickname was Joe DiMaggio.

The Tampere department also had a nickname, hilleri, and he always said hrrrrrrr when he joined the channel. Others happily welcomed him. I even went on a couple of dates with a girl I met through the chat, but nothing more serious came out of those.

Joe

-The time when there was no internet at home (even with a modem) and you had to reserve hourly slots from the library for chatting after school... and just when you were having a good conversation with some nice guy, the library lady came to complain and you had to stop.

-Choosing rooms based on names, and then they were full!

-When some guy tested if I was old enough by asking when my period starts... younger ones wouldn't probably have known how to crack the code ;)

Jepa

The greatest amusement for teenage girls was to find a boy from the Kiss chat, and we would all respond together. Back then we just exchanged harmless messages, asked about each other's well-being and hobbies. We had no idea if the boy on the other side of the internet existed or not. In middle school, we would sneak into the computer room during breaks to chat or visit that friend who had a computer. Then of course we were nervous that a landline phone call would interrupt the internet connection.

Anna

I participated in discussions, but unfortunately I don't remember any of the topics. I just thought of the most popular internet fashion words of that time such as "peelo" which described an idiot/troublemaker who doesn't follow netiquette (:D).

Oh boy! In middle school (around 1997), I chose ICT as an optional subject. The school had a new fancy computer room, where everyone had their own computers with internet. First, we had to learn touch typing, then we could do what we wanted, i.e., create restless gif animations for our homepages or surf the internet. There wasn't much content on the internet yet - or we didn't know how to find it. But the gates of Kiss FM's chat city were wide open! Initially, I remember the coloring of the site being black-neon green, then the site was renewed and diversified, and the graphic image became city-like. Usernames were of course something like "FlowerGirl82" and the conversation was quite innocent flirting. I guess I learned something from that, but I still wish I had learned that HTML.

FlowerGirl82

Late

Around the age of 12, we pretended to be a bit older and played like we were looking for company. We sweet-talked for a while until we managed to coax out phone numbers. Then we made prank calls to those numbers. This pattern was repeated numerous times.

I'm not proud, but I don't regret it either”


<form action="msg.asp" method="post" target="my_iframe">


When I was at Kagi I implemented their fallback poly-fill for web sockets that way. Worked great!


I remember implementing this a long, long time ago for that purpose. It was a novelty then, didn't know it was still being used.

https://github.com/Miserlou/OnionChat


classic HN comment. do note the name of the project and ask yourself again, was the only constraint to not use javascript?


Can you talk a bit more about how it works? Is the page reloaded on submit?


This is an old trick, so I understand why people probably haven't seen it these days. But you have a page with two frames: the submission frame (i.e. input form, usually on the bottom of the page) is reloaded on submit, while the chat log (usually the top frame) loads infinitely.


Just to be further specific, they're talking about embedding two separate webpages inside of one page, using "iframe" HTML elements. In the bad old days you'd probably use a bare "frame" element, but those aren't valid HTML as of HTML5.


I think they used a frameset with frames. It had the advantage that it could be sized to the browser window as a percentage and both frames could be refreshed/loaded independently without affecting the other.


weren't people also implementing live chat with gifs back in the day?


People were absolutely doing countdowns with gifs that were constructed and delivered to the client a frame at a time. I can't say that I personally ever saw any madman building a live chat feed with that technique but there's unfortunately nobody and nothing that could have stopped them.


This is essentially what they are doing, minus the form frame.


iframe + meta refresh 10s


Inspiration tweet since the author locked his account: https://web.archive.org/web/20190613094358/https://twitter.c... for the interested.

Just curious, what is the update frequency of `Transfer-Encoding: chunked` web pages in browser?


Transfer-encoding chunked is not really meant to be used this way, its normaly just an optimization for the http protocol, so its basically instant/however fast the webserver sends data - with the common case being as fast as possible.


> what is the update frequency of `Transfer-Encoding: chunked` web pages in browser?

The server determines that - when it sends new HTML (whenever it wants to), the client loads and displays the new content immediately.


I assume these are the alternatives that people with javascript disabled really want


Nah. JS is fine for apps that need it. But a lot doesn't (every blog and news site) where JS is used for obnoxious animations and dark patterns.

And now the unwritten contract between users and companies has been broken, so I’d very much prefer most applications to be in the browser where they are contained instead of installed on my computer.


I feel like under all these CSS hacks there lies the kernel of something where you can write javascript, transpile it into a bunch of CSS and html, and effectively run it. Javascript-less javascript.


rich harris' dream world


I may be pedantic, but this is not only CSS, there’s after all an entire Ruby backend. Wouldn’t it be more appropriate to call this something like “No-js chat”, seems to me that would be more correct and less clickbaity.


I feel that is overly pedantic. I think it is clear from context of headline that there is some sort of backend. If there was no backend i think thd headline would be different.


Random question, CSS is a style language, but the intent was that there could be others, are there any other style languages that are alternatives?


It's actually right there in the name: Cascading Style Sheets.

Css was never meant to be a style language (if by language we understand "a syntax with logical constructs"). It was simply meant go be the stylesheet for a given website. Headers look like this. Body looks like that.

Except, they cascade: headers look like this, but headers that are emphasized look like so.

The idea was that one could define a stlesheet for screens, a stylesheet for print, a stylesheet for screenreaders, and so on.

As such, no programming "language" logic was considered, except "how do styles cascade" (ie, how do we resolve which style "wins" when there are multiple candidates).

The alternative to css was inline styles; styling but without the sheet part.


The problem was three-fold:

1. Everyone trying to build a do-all-the-things-junk-ware-drag-and-drop system. Turns out fixed styles are a pain with complex widgets that are supposed to talk to one-another.

2. Turns out that designing something for just desktops was a mistake - media queries sort-of came to the rescue for print/mobile. But opening the door for extensions like this made it all-to-easy to want to simplify/re-use stuff.

3. Semantic HTML was too light-weight. Everyone building single page apps wanted views, html turned into a sort of weird GUI structure language with semantic sprinkled on top, and it was incredibly tempting to see CSS as a main driver of that view (inline styles were awkward but CSS allowed you to sort-of-obviate that).

So we grew weird CSS/HTML extensions that turned into (DSL) languages that got folded back into CSS in a lot of cases.

If we could start over I'd scuttle CSS/HTML separation, styling would just be part of html and html would have first class support for templates. You wouldn't need to cascade anything, because the HTML would just know what it was supposed to look like, and practically auto-cascade. If there were any "style sheets", they would be just default value lists, and again, they would be a part of the html standard, not a separate "standard".

Which I think is practically what CSS used to be, lists of values that applied to various elements. This made it easy e.g. for early web to allow per-user customization by providing access to those lists, or in-browser modification of those values for quick feedback cycles. The mistake was calling it CSS and HTML's shortcomings, not how it functioned.


I think you misunderstood the question. Yea, there definetly was competing ideas for how to do styling on the web. JSSS (JavaScript style sheet) was proposed by Netscape back in '96. (Funny how we now have gone full circle).

https://en.m.wikipedia.org/wiki/JavaScript_Style_Sheets


It looks like there was DSSSL, which was designed to work with any SGML document, including HTML 3.2 documents. Curiously, the syntax was all written in s-expressions! [0] has some working links to materials on it.

Though it appears to have required an external processor, rather than being an alternative to "text/css" handled by the user agent. For that, you'd want to look elsewhere on Wikipedia's list [1]; one partial candidate is JSSS (JavaScript Style Sheets) in Netscape Communicator, which were JavaScript snippets that could actually be placed in <style type="text/javascript"> tags.

[0] http://xml.coverpages.org/dsssl.html

[1] https://en.wikipedia.org/wiki/List_of_style_sheet_languages


The same was true of JS.

But AFAIK, there is only CSS and JS.

You used to have to declare the Script tag as JS, but you don’t anymore since HTML5. Because all scripts are JS.

I don’t think SASS and LESS count, as are not supported by browsers natively, and require pre compilation. :-)


> Because all scripts are JS.

Rip vbscript

You can also declare style types (even an http header for it if i recall) but nobody bothered as nobody ever implemented anything else (not counting xslt but that was attached to documents differently and had a really different model)


> You used to have to declare the Script tag as JS, but you don’t anymore since HTML5. Because all scripts are JS.

I wonder how much data transfer was wasted to this.


Less than the unholy mess which is JS dependencies.


LESS and SASS but I imagine you mean significantly different and not just “dialects.”


I was under the impression that those were tools to generate css (I get the practicality), but is there even another one that has been proposed but never added to browsers?


Ignoring XML based languages (XSL, PGML), some of the early ones, that never made it to browsers, were DSSSL and FOSI. There was also JSS (JavaScript Style Sheets, 1996). Mobile app development (e.g. Flutter) have their own APIs for styling, but they're still quite similar to CSS. There might be other languages used in areas I'm not familiar with.



You can send content of typed data of an input field with CSS to a webserver, as you can use a selector that matches the end of the input field's value.

https://css-tricks.com/css-keylogger/ (2018)


Kevin, you absolute madlad.


Haha, thanks, Nick. :)


Same vibe as the C++ compile-time ray tracers e.g. https://github.com/tcbrindle/raytracer.hpp


Props to the dev with two projects on the HN front page at once


Reminds me of https://cgiirc.org/ i think older versions did nog need js


This is insane.. A great combination of old hacks and workarounds that to be quite honest, even though I've read it twice i still don't understand properly.

I'm under the impression that eventually the Dom elements are just going to eventually crash the browser?

I guess in the end that a moot point given i really hope nobody uses this is production!


Isn't there a way to map keys to buttons without JS? Maybe with an ImageMap? Dear god are those still supported?


I got nerd-sniped into re-implementing this in Node. Running on a local server and reusing buttons to minimize DOM exploding it's fast enough to need serverside key debounce. I suspect the original author chose to re-send the entire button set to avoid this.


The very first chat room I ever used was Sierra Online’s web chat way back in 93. It was comet based, just like this, and I’ve never understood why comet was never more common, especially before websockets were a thing.


Finally just what i needed

On another note, I once had to fetch data in powerbi, but there were some sandbox limitations on fetch requests or something

I ended up fetching images instead and encoding/decoding the image bits being sent to make an arbitary fetch request


I guess people interested in "no JS implementations of things" are here so I would humbly like to ask:

Does anybody know of a viable way to implement (geographic) maps without JavaScript?


What about a static image?


Mapquest did this back in the day.

I suppose you could use similar tricks as CSS-only chat to get the pan buttons to work without a page refresh


Forms. Buttons for things like pan and zoom to load images or SVGs


That’s clever, I love these kinds of hacks.


For a couple of people with javascript disabled?


simple is good


Is there a demo instance?


I hacked this whole thing together in a cafe in Paris over a couple days. It's not exactly what you'd call "scalable" ;). Given that it keeps a long-running streaming http connection to every client, it'd be expensive to set up servers to support this.


Is Paris dangerous now ?


Beats me? I was on vacation there 4 years ago. :)


I'm sure a $5 digital ocean droplet would go a very, very long way.


How could someone make a prototype for "monstrous chat" and not include a demo link with a monstrous amount of users.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: