
Show HN: MineSweeper implemented in 100% CSS and HTML – no JavaScript - James0x57
https://github.com/propjockey/css-sweeper#readme
======
James0x57
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](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
No way! I've done exactly the same thing.
([https://news.ycombinator.com/item?id=15479160](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](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](https://codepen.io/qaz/pen/bGEzyrJ)

Enjoy!

~~~
James0x57
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
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
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
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/](https://propjockey.github.io/css-media-vars/) [1]
[https://news.ycombinator.com/item?id=23865900](https://news.ycombinator.com/item?id=23865900)
[2]
[https://twitter.com/James0x57/status/1283596399196680192/pho...](https://twitter.com/James0x57/status/1283596399196680192/photo/1)
[3] [https://jsbin.com/xelufoyoka/1/edit](https://jsbin.com/xelufoyoka/1/edit)

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

------
kanobo
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.

~~~
distrill
yeah, i expected it to be instant to be honest, given it's just markup and
there's no "thinking"

~~~
James0x57
It's 1.23MB of CSS & HTML - this is meant to be a stress test of the limits,
lag is expected for the next several years of average-at-the-time computers!

~~~
owl57
Or until someone packages your madness as a popular library and browsers are
forced to optimize it.

~~~
Sebb767
Make it an Electron app!

(I'm joking, please don't. Please.)

~~~
megablast
that would not speed it up at all.

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

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

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

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

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

~~~
James0x57
I saw that a few days before I started making this actually!
[https://news.ycombinator.com/item?id=23867569](https://news.ycombinator.com/item?id=23867569)

~~~
elliekelly
I always wonder what kind of cool stuff HN inspires. There has to be tons. Is
there a list?

~~~
uxamanda
Not curated, but found a whole bunch with this search
[https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...](https://hn.algolia.com/?dateRange=all&page=0&prefix=true&query=inspired%20by%20post&sort=byPopularity&type=story)

------
krspykrm
Good stuff! I made a sudoku in CSS
([https://identicalsnowflake.github.io/sudoku.html](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
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
Every day we stray further from God's light.

------
jagger27
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
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
Very interesting! Can I ask, how did you implement the timer in CSS/HTML?

And also, what causes the lack of responsiveness?

~~~
James0x57
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...](https://raw.githubusercontent.com/propjockey/css-
sweeper/master/index.html)

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
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
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 :)

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

~~~
James0x57
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
What inspired the idea and what was your motivation?

~~~
James0x57
I made a Binary Coded Decimal 7 Segment Display Decoder a couple days prior to
starting this:
[https://github.com/propjockey/bcd7sdd](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
I was sad to discover that Minesweeper is no longer bundled by default with
Windows.

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

~~~
quickthrower2
The bombs are fork bombs

------
aaroninsf
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.

~~~
bawolff
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](http://eli.fox-epste.in/rule110-full.html)

~~~
potiuper
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](http://web.mat.bham.ac.uk/R.W.Kaye/minesw/infmsw.pdf)

~~~
James0x57
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!

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

~~~
jackcosgrove
A 16x16 minesweeper email signature would be a great way to make an
impression.

------
roryokane
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
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
Now do GPT-3.

------
TedDoesntTalk
Oh my god, this is AWESOME!

~~~
James0x57
haha thanks! :D

------
soulofmischief
Very nice. Thanks for sharing.

------
buryat
doesn't work in Safari

~~~
James0x57
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
Doesn’t work on mobile? Safari / iOS 13.4.1 here.

~~~
James0x57
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
Why.

------
draw_down
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
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](http://www.play-minesweeper.com) and the time to
interactivity is recognizable by comparison. The HN community is a funny one,
sometimes.

~~~
hombre_fatal
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
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.

