Yet Another Trick
Reinventing CSS sprites, long polling, and JSONP.
During the winter break of 2003, I built my first web game: Minesweeper, written in HTML and VBScript. If you want to know what it looked like, just open Minesweeper in Windows 98. I recreated it pixel for pixel.
Before that, I had already made a Visual Basic version of Minesweeper. The game logic was simple enough, but the interface was awkward to build. Once I started learning web development, I became fascinated with tile-based games like Tetris and Dr. Mario. Their interfaces could be built almost entirely with a single TABLE, which made both layout and event handling surprisingly convenient.
There was also a practical reason to move from VB to the web. Sharing VB games was awkward. Instant messengers often warned people that .exe files might be dangerous, and asking someone to run an executable felt intrusive. A web page, by contrast, needed only a link. So I signed up for a free hosting service and uploaded my Minesweeper game.
To my surprise, the online version felt terrible.
Every flag, mine, and number was a separate image, and the free hosting was slow. After each click, it could take several seconds before anything appeared on the screen. It was probably the first time I seriously thought about user experience.
My first solution was preloading. I would rather make the player wait at the beginning than let the game feel sluggish afterward. It helped, but preloading more than a dozen images still felt clumsy.
When I looked more closely at the images, I noticed that they were all tiny and all the same size, like toolbar icons. That reminded me of programs that stored an entire toolbar as a single strip of images, almost like a reel of film.
So I merged all the images into one. But the problem was how to display only one piece of it at a time.
Get EtherDream’s stories in your inbox
Join Medium for free to get updates from this writer.
I came up with a trick: the outer container would hide the overflow, while the inner IMG would be shifted horizontally with a negative offset to reveal the right frame.
With that approach, the page needed to download only one image.
Years later, I came across CSS sprites and realized there was an even simpler way to do the same thing — using background-image and background-position, without needing a child element at all. But the underlying idea was the same.
That summer, I started thinking about another problem: a chat room without refreshes.
At the time, many web chat rooms simply refreshed the page every few seconds. It looked bad, and it still didn’t feel truly real-time. As a perfectionist, I found that unbearable. I wanted something better.
At first, I was convinced there had to be a way to use the Winsock control directly inside a web page, perhaps through OBJECT tags or ActiveX. I tried for weeks, but nothing worked. Eventually, I gave up on that path and returned to a pure HTML solution.
My first improvement was to move the refreshing logic into a hidden frame. When that frame reloaded and fetched new messages, it would call a function in the parent page to display them. The interface and the data were now separated, and the page no longer felt like it was constantly reloading. The experience became much smoother.
But it still wasn’t truly real-time.
So instead of using an ASP backend, I wrote a small HTTP server in VB. That way, a request no longer had to return immediately. It could stay open until a new message arrived, and then respond. The result felt far more immediate.
I also found another trick that didn’t even require a frame page. Simply changing the src of a SCRIPT tag was enough to send and receive data — though not as a stream.
Only later did I learn that these tricks already had names: long polling and JSONP.
Of course, there were many better solutions I hadn’t discovered yet — Flash sockets, XMLHTTP, and others. After all, I had very limited time to use a computer back then. It was the eve of Web 2.0, and there were probably countless enthusiasts like me, independently trying to push the web a little further.






