Settings

Theme

Show HN: MineSweeper implemented in 100% CSS and HTML – no JavaScript

github.com

390 points by JaneOri 5 years ago · 96 comments

Reader

JaneOriOP 5 years ago

I realize this is an absurd thing to do, but it was fun and I wanted to test the limits of CSS again so I could share the results!

I linked to the README since any web devs that see this will probably want to know how buuut here's a link to the game if you want to go hands on:

https://propjockey.github.io/css-sweeper/#randommenu

It's all open source, and I discuss some details of how to do it in that readme, but I am more than happy to answer any questions!

Thanks for checking it out!

  • cnees 5 years ago

    No way! I've done exactly the same thing. (https://news.ycombinator.com/item?id=15479160) At first I thought this was my own thread! I guess there's a healthy overlap between loving Minesweeper puzzles and CSS puzzles. :)

    I used HTML/CSS so I could implement it on a Neopets page, which meant I couldn't use forms, inputs, or CSS3, which means it's less feature-complete and the approach is completely different. The final result, though, is still the same delightful Minesweeper experience.

    http://www.neopets.com/~Cism

    Codepen link (so you don't have to be signed into Neopets to see it)

    https://codepen.io/qaz/pen/bGEzyrJ

    Enjoy!

    • cnees 5 years ago

      To emulate Minesweeper's not-a-bomb-on-the-first-click experience, I start the board off with a generous region revealed, and then to emulate flood-filling, I make blank cells sit in an invisible (overflow hidden) scroll box that scrolls to a revealed version of the region when you click the blank cells, which have relative links. That only works for rectangular regions, but I remember having a way to make it work with irregularly shaped regions and being too lazy to implement it because it was going to be even trickier and uglier than what I was already doing. I'll leave that as an exercise for the reader. :P

    • James0x57 5 years ago

      This is awesome - Could you please explain how you're holding state of each box individually without checkbox:checked? It's not immediately obvious to me how that's possible or where it's happening in your code!

      • cnees 5 years ago

        Thanks!

        I use scroll position to keep the state. In effect, each square is in a div with overflow:hidden. (In the actual code I used <i>, not <div>, which might've been to save bytes because the server is so slow). It has a fixed visible height, the height of the square. Above the fold (before scrolling) is the un-clicked square, and below the fold (what you see after scrolling) is the clicked square.

        Since overflow is hidden, you have to use an in-page anchor link to scroll to the clicked state. The unclicked version of each cell is an anchor to the clicked version.

        • James0x57 5 years ago

          wow, that's super clever. I was sitting here reading the code and didn't find a negative margin or positional property anywhere, and further, no switches to hold the state. Couldn't for the life of me figure out what you were doing hahaha I love it

          Thank you!

        • uxamanda 5 years ago

          That is an amazing hack! Awesome.

    • LoSboccacc 5 years ago

      both lack the left+right click that reveals tiles around numbers that have the sufficient amount of bomb marked, I'm curious what's the css/html limitation that prevents the implementation of that behavior?

  • jonny_eh 5 years ago

    This should make white-boarding interviews a lot more fun. "Please implement Minesweeper, but only using HTML + CSS"

    • atoav 5 years ago

      At some point questions like these become more like: Guess which exact sentence I am thinking about

      I am very good with HTML and CSS and would definitely be able to solve sth like this. But not on a whiteboard, I would have to be able to fool around with it.

    • ARandomerDude 5 years ago

      Why would you give "them" ideas?

  • ceocoder 5 years ago

    That is impressive, just impressive. Brought back some fond memories of installing Windows XP over and over again for family and friends with fckgw rhqq2 yxrkt 8tg6w and playing minesweeper before handing it off to them.

    Great job!

    • krrrh 5 years ago

      “fckgw rhqq2 yxrkt 8tg6w. There’s a name I’ve not heard in a long, long time.”

      • ceocoder 5 years ago

        this should be like a secret handshake or even better our version of windmill high-five from Top Gun. Still can't believe that I can enter that S/N without having to even think about it.

    • Aeolun 5 years ago

      Is there something magic about that code?

      • ceocoder 5 years ago

        Yes - https://en.wikipedia.org/wiki/Volume_licensing#Leaked_keys

        tl;dr I grew up in India where the Indian Rupee was quite weak compared to the USD. Most people I knew couldn't really afford a legitimate copy of Windows XP - 1 USD was about 48.61 INR in 2002, and average wage was about 120 INR/day[0]. At that price a copy of Windows XP (priced at around $300/$400 ~ INR 14,000) was prohibitively expensive for pretty much everyone I knew. Because of that we ended up using leaked keys to setup new PCs, I did that enough times for my family, friends, and classmates that now I can type that key up as if I'm typing "hello world" :)

        [0] https://www.ilo.org/wcmsp5/groups/public/---asia/---ro-bangk...

      • panda88888 5 years ago

        It’s the most popular Windows 98 cd key back in the old days.

  • elteto 5 years ago

    Fantastic! Are you proud that you can call yourself an HTML programmer now?

  • Diskutant 5 years ago

    Doesn’t work on iOS?

    • Diskutant 5 years ago

      The "Play it here" link on the github page works.

      Seems like the "click click" message, which is shown only on op's direct link, causes some problems.

      • James0x57 5 years ago

        OHHH I wish the others would have been more specific other than "it doesn't work". Thank you!

        The way that random thing works is:

        1) #randommenu:target shows the overlay (based on hash in the url)

        2) the overlay has a link to "#" (fullscreen) that says "click-click"

        3) Then rendered ontop of the link, all 16 level labels are full screen & transparent

        4) Animations loop through them (hard-coded random scramble) to change their z-index to be on top, one at a time, for about 0.25s each

        5) Clicking on any of the labels causes that layer to disappear, exposing the "#" link

        6) Clicking again changes the url to "#" so #randommenu is no longer :target, thus closing the overlay

        My guess is it's probably flashing too fast for iOS/Safari to register a full click.. I could probably fix it by making the random sequence take longer.

        Can you confirm the URL never changes to "#" and stays stuck on "#randommenu"?

        • Diskutant 5 years ago

          Yes it’s stuck on #randommenu

          Sometimes it works though, needs some „clicking“ (touching), eventually it will (might) work.

    • faeyanpiraat 5 years ago

      Can confirm

uxamanda 5 years ago

This is really cool! I saw your responsive library[0] post [1] the other day, but couldn't quite wrap my head around it.

With this post, I think I am starting to grok the (Space Toggle) trick. The Tweet you linked in your library was really helpful [2].

My current understanding is – in CSS, you can set a variable to nothing (a space). When a property contains that "blank" variable, it is replaced by nothing and so the second, "fallback" value is the default. Because you can update CSS variables within more specific or later CSS, you can update the "blank" variable and give it a new value of "initial", this causes it to switch from the default to the defined override.

I realized, you can even combine this with the CSS checkbox hack. I made a (super hacky) version of CSS-only dark mode toggle based on your JSBin (gotta love an absolute positioned bg, lol) [3]

[0] https://propjockey.github.io/css-media-vars/ [1] https://news.ycombinator.com/item?id=23865900 [2] https://twitter.com/James0x57/status/1283596399196680192/pho... [3] https://jsbin.com/xelufoyoka/1/edit

  • James0x57 5 years ago

    haha, awesome! You nailed it. It's really cool to see it being tested out in the world! Thank you for sharing!

kanobo 5 years ago

That's crazy! The large lag between clicking and the UI updating is slightly annoying, but that's just me nitpicking at something other than the cool technical feat.

jedberg 5 years ago

I think I see my CPU dripping out the side of my laptop.

  • zootboy 5 years ago

    Indeed. This pegged a CPU core and locked up my browser for over a minute just opening the page.

    • AlfeG 5 years ago

      Syrange, but it works almost without lags on S10 phone.

      • rnestler 5 years ago

        Same here, page loaded pretty fast and lag is maybe 200ms on my phone using Firefox.

onion2k 5 years ago

Very cool. CSS can do some amazing stuff these days. I made a game using moving checkboxes recently - https://codepen.io/onion2k/pen/qBbKYee - with a timer and scoring. It's a fun challenge to avoid JS.

krspykrm 5 years ago

Good stuff! I made a sudoku in CSS (https://identicalsnowflake.github.io/sudoku.html) a while back, but it looks like the variable trick mentioned in the readme is a more straightforward way to embed logic, so if I were to make something similar today, I'd probably pursue that route.

  • James0x57 5 years ago

    This is great! I love how there's a bit of a reward for getting past the difficult middle part of gameplay - when there's not many spots left it goes fast and you can click click click to finish up without sitting there cleaning up your notes or counting 1-9 to figure out the last number or two. This is a big improvement haha

krapp 5 years ago

Every day we stray further from God's light.

jagger27 5 years ago

It sort of bothers me how much feature creep CSS itself has undergone. Was it not enough to leave things simpler and just use pre-processors and JavaScript?

What hope does one have to implement the entire CSS spec from scratch now?

  • crumpled 5 years ago

    I see your point about separation of concerns.

    This minesweeper, and the other examples in the comments, seem to capitalize on some hacky aspects of CSS, not features of the CSS spec.

    In the real world, I doubt many people rely on CSS for things that JavaScript can do. (but I bet plenty of beginners use JavaScript, when CSS would have been more appropriate, haha)

osrec 5 years ago

Very interesting! Can I ask, how did you implement the timer in CSS/HTML?

And also, what causes the lack of responsiveness?

  • James0x57 5 years ago

    The timer itself is a CSS animation with 1000 keyframes evenly spread, that runs once for 999s (just realized it should be running for 1000s, oops!). I can't link to lines in the source code because of the 1.23MB filesize but you can search for "timer" in the raw source to see the relevant code: https://raw.githubusercontent.com/propjockey/css-sweeper/mas...

    Here's the part that controls when the animation is running:

        #level-none:not(:checked) ~ #ram #timer::before {
          animation: timer step-end 1;
          animation-duration: 999s;
          animation-fill-mode: forwards;
          --pause-if-won: var(--win-state) paused;
          --pause-if-lost: var(--game-over) paused;
          --pause-if-randommenu: var(--randommenu-visible) paused;
          animation-play-state: var(--pause-if-won, var(--pause-if-lost, var(--pause-if-randommenu, running)));
        }
    
    Though the design is responsive to the width of the window, I suspect you mean how slow it is: it's 1.23MB of HTML + CSS, and clicking anything causes almost everything to redraw. It's only a little laggy on my computer but the idea was to test the limits of what's possible and is expected! :)

    Thank you for checking it out!

    • nitwit005 5 years ago

      Can't you simplify this by making each digit a separate animation, with the ones digit running at full speed, the tens digit running at 1/10th speed, and the hundreds digit running at 1/100th speed? Then you'd only need ten keyframe values.

      • James0x57 5 years ago

        Yes, but I didn't trust them to stay synchronized and it wasn't too difficult to generate the code for 1000 keyframes so I just did that :)

    • uxamanda 5 years ago

      If I understand this timer, is it true that after ~16.5 mins, the game would stop? Are you stopping at 1000 keyframes because of a hard limit or for performance or for?

      • James0x57 5 years ago

        the timer stops at 999 because that's what it does in the real minesweeper, you can keep playing though!

mitchtbaum 5 years ago

If this took you, ballpark, 1 month to do, what do you think you would be able to do in a year?

  • James0x57 5 years ago

    This took ~3.25 days. :)

    Since I'm brushing up against the limits of CSS, there's not enough room for a full year :P

    • angrais 5 years ago

      What inspired the idea and what was your motivation?

      • James0x57 5 years ago

        I made a Binary Coded Decimal 7 Segment Display Decoder a couple days prior to starting this: https://github.com/propjockey/bcd7sdd

        After that blew up on twitter I tried thinking of something else I could test using checkboxes as the state and MineSweeper just popped in my head since it's pretty much 480 fancy checkboxes.

        Motivation was just to see if I could, then to see what the limits are once I realized I'd be able to.

        Thanks for checking it out!

divbzero 5 years ago

I was sad to discover that Minesweeper is no longer bundled by default with Windows.

kristopolous 5 years ago

I tried this on a low end smartphone. Might as well have been called MineSwapper

aaroninsf 5 years ago

Idle question,

is CSS/HTML turing complete?

If so I look forward to a Show HN of a CSS/HTML emulator of JSMESS emulating a 386 running Windows 98.

  • pacificmint 5 years ago

    My understanding is that:

    Neither CSS nor HTML is turing complete.

    The combination of CSS and HTML together is not quite turing complete either.

    The combination of CSS and HTML plus an external source that repeated clicks the mouse is turing complete.

    I could be remembering this wrong, however.

  • bawolff 5 years ago

    It is (and has been since the css 2.0 era) if you include user clicking mouse.

    There is a famous demo of rule110 in css at http://eli.fox-epste.in/rule110-full.html

    • potiuper 5 years ago

      Mouse is not necessary using CSS 3 (animations); Minesweeper[1] is enough to show Turing completeness.

      [1] http://web.mat.bham.ac.uk/R.W.Kaye/minesw/infmsw.pdf

      • James0x57 5 years ago

        edit: ^ previously said "with css variables to hold state" or something similar (or my wires got crossed and I saw that somewhere else)

        CSS variables can't be set by animations yet without JS's CSS Houdini giving them a type - a CSS @ property is in the works to do it without JS though!

  • James0x57 5 years ago

    I would say no because the core boolean mechanic that allows CSS-Sweeper to exist cannot be inverted directly (NOT, !). In order to invert anything here, you have to start with an inverted copy of every bit and do the opposite calculation at every &, |, etc to always have a "NOT" var to reference. Like a shadowy, anti-vein, copy of the main logic.

    There are several edge cases where a sort of simile of NOT is possible though. You can branch from truthy/falsey into falsy/truthy numbers. And if is something is falsey you can "else" into another action.

    Just can't "else" from a truthy state without the ...anti-vein... always being present.

  • Wowfunhappy 5 years ago

    It’s not.

MrSourz 5 years ago

Now, which email clients does this render properly in! I'm looking forwards to diving through this.

roryokane 5 years ago

I was so confused why everyone was saying the game is so impressive when all my clicks did nothing but place a ‘?’ where I clicked. Was each ‘?’ an error message? No, it turned out you need to click each square twice to reveal it. The page really needs some instructions, because that is not how normal Minesweeper works.

The other thing you need to know to play is that right-clicking won’t flag a square. Instead, you need to left-click on the flag in the top left to toggle flag mode, then left-click on a square to flag it.

Sniffnoy 5 years ago

I'm confused -- how do I flag? Right-clicking seems to just bring up the right-click menu.

Edit: Nevermind, figured it out. You click on the flag up top to switch between flagging and clearing.

hughw 5 years ago

Now do GPT-3.

TedDoesntTalk 5 years ago

Oh my god, this is AWESOME!

soulofmischief 5 years ago

Very nice. Thanks for sharing.

buryat 5 years ago

doesn't work in Safari

  • James0x57 5 years ago

    Hmmm... do you know what version you have?

    It should work on iOS 11.3 and up... maybe. They might have smaller limits on the number of operations per calc()..? Can't think of anything overtly incompatible.

    Unfortunately Safari is today's IE6 in web dev since they're so far behind on so many features. Except it's worse since you can't test without owning their products or paying for a service either... wish I could check it out, there's probably something to learn

lostgame 5 years ago

Doesn’t work on mobile? Safari / iOS 13.4.1 here.

  • James0x57 5 years ago

    Any chance you could share a screenshot? I can't test safari without owning apple products or paying for a service :(

    as far as I know iOS 13.4.1 should be completely compatible.. there might a smaller limit on the number of calc() operations? The spec says it must support a minimum of 20 operations, but I'm (ab)using almost 1000 in a max()

edem 5 years ago

Why.

draw_down 5 years ago

This is very slow in my browser, which I don't mean as a criticism. Just refreshing to see something be slow that uses no JS at all :D

  • seangrogg 5 years ago

    It is rather ironic that the chief complaints about JS are how it makes things bloated and unresponsive, yet this is 100x the size of http://www.play-minesweeper.com and the time to interactivity is recognizable by comparison. The HN community is a funny one, sometimes.

    • hombre_fatal 5 years ago

      The OP is a 1.23MB tech demo in CSS absurdism, not a baseline for performance comparisons. You have the wrong take-away if you think you can squeeze any sort of performance point from this.

      It's like seeing that fun tech demo that implements Brainfuck in Rust's type system and going "heh, and they said compiled languages were fast? I can do this faster in PHP!"

      • seangrogg 5 years ago

        You have the wrong take-away if you think the performance points were what I was actually focused on.

        The HN community largely rails against the use of JS anywhere, even if not using JS would make things much more difficult. Therefore, it's funny when someone makes a relatively trivial app not using any JS and it exacerbates the problems people cite for JS rather than not.

        The whole thing is really cool and I love how they managed to get so far using some cool CSS tricks. But per the community it should also be a godsend because by not using JS it should by default make it faster, smaller, and probably cure cancer or solve for FTL travel or something.

    • smichel17 5 years ago

      JS is the right tool for the job when you want to make something highly interactive. I can't remember seeing anybody dispute that here. Having said that, I now expect at least one reply from someone who does dispute it.

      • quickthrower2 5 years ago

        2003 says "what about Flash, Java Applets, ActiveX controls, VBScript, Silverlight"

        Well maybe 2003 didn't mention Silverlight.

    • draw_down 5 years ago

      Trust me, I have a whole trove of rants about how HN talks about JavaScript. Lotta rants in that trove.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection