Posts Tagged ‘CSS’

CSS Hitbox Detection

Wednesday, October 24th, 2012

Note: Read this to the end before you get too excited. This is an interesting CSS hack/exercise, but it faces a major hurdle that limits its applicability.

File this under: cool tricks with CSS that might be a poor use of your time, or might be more awesome than two unicorns doing synchronized backflip space diving.

Over the weekend while brushing up on CSS animations, I had an errant thought involving how the brains of certain types of flies operate.

Which I won’t go into for now. Let’s just say that nature is weird, providing very disparate solutions to the same problem. (In the case of the flies it was how they think.)

The relation to what I was doing at the time is that we’re in a situation where we can animate elements in a browser with the aid of Javascript, or we can now do it with just CSS. I was exploring the range of wacky things I could accomplish with pure CSS, sans Javascript. One of the interactions I wanted to see if I could accomplish was hitbox detection.

In video game programming, hitbox detection is used to determine when one moving element (like Blinky the ghost’s ectoplasmic tendrils of love) touches another moving element (like Pac-Man’s glorious, circular body.) And once that event is detected, the game then causes something to happen. (In the family-safe industry of 80′s arcade games, this means that Pac-Man dies a horrible death, questioning the futility of his existence. In my fevered dreams it would instead result in an erotic love scene of the Pac-Man/Blinky slash variety. Which, I think we all agree, would make for an excellent arcade machine hack.)

We’ve established that CSS can animate objects. But detecting a collision between two of them? Impossible!

Actually…

CSS does possess some rudimentary event detection based around the mouse interacting with page elements. :focus, :checked, :hover, etc. Most of them require users to actively do a discrete event, which is less useful for actively polling for something like the collision between two objects in real time.

:hover, however, provides us with a bit of a possibility. The mouse is just hanging out there on the page, doing its thing. It’s typically hovering over something. Can we make that work for us?

Hover over what?

The mouse hovers over one element at any given point in time, which triggers the :hover pseudo-class for CSS on that element and any of its parents, all the way up to the root.

Let’s assume a very simple problem situation which we’ll be turning into this demo. We have a stationary ‘avatar’, which for the purposes of our demo is a green circle sitting in the middle of the page. We also have an animated ‘mob’, which we’ll render as a black square. The mob is animated to sweep horizontally back and and forth across the page underneath the circle.

What we want to do is detect when the mob passes under the avatar in a simplified, horizontal-only collision detection.

We’ll want this to happen regardless of where our mouse is, which presents a problem. We can’t be hovering the cursor over the avatar, so how will we know when the mob lines up with us?

Sensors

What we want is the ability to detect an overlap at any point in time, regardless of the mouse’s position. To do this, we’re going to create a grid of invisible elements that are aligned around both the avatar and the mob. In our demo, we’ll call the ones attached to the avatar .switch, and the ones attached to the mob .sensor. We’re going to create enough sensors on each side of the elements so that regardless of where they are on our page, the mouse can be hovering over a sensor for each of them. In our case we’re only detecting for a horizontal overlap, so our sensors are as tall as the page. In a situation where we’re worried about vertical overlap, we’d be creating a grid of squares, greatly increasing the amount of discrete sensors we’d be making.

The avatar is stationary, so its sensors can remain stationary with it. The mob is not, so its sensors will have to be animated as well to follow its movements.

Double Hover Detection With Pointer-Events

The reason we’ve made all these sensor elements is to help us detect the avatar and mob overlapping regardless of where the mouse is. Each sensor grid is aligned in space around their respective icon, so when the mouse lines up over both the avatar’s sensors and the mob’s sensors of the same corresponding position, we know that where the avatar and mob are, they too are overlapped. (So, for example, if the leftmost avatar sensor and the leftmost mob sensor are both under the mouse, we can know that the avatar and mob are also overlapped).

Of course, the problem is that CSS can’t detect if the mouse is hovering over more than one element. The first one it encounters interrupts detection on the others.

Pointer-events is a CSS property that I don’t see discussed much, but that proves to be very convenient. It interacts with SVG in all sorts of strange ways, but with ordinary markup and CSS it still has two options. When set to “auto”, the element interacts with the mouse as desired. When set to “none”, the element no longer interacts with the mouse at all, becoming ‘transparent’ to mouse events. Hovers, clicks, it completely disregards them, and the events pass under it to whatever element is beneath.

We can exploit this to provide a sort of double hover detection.

In our demo, we make sure that all our .switch elements for the avatar’s sensors are set to a low z-index, and that the .sensor elements of the mob’s sensors are set to a higher z-index, but that .sensor also has been set with pointer-events: none. We also make sure that our .switch elements come earlier in our markup than the sensors.

.switch { z-index: 1; }

.sensor { z-index: 2; pointer-events; none; }

We then give .switch a rule for when it’s hovered over that causes its corresponding .sensor to regain its pointer-events (and keep it as long as the mouse is over it). In my demo I’ve given each sensor/switch pair a specific class that corresponds with each other. So for the leftmost pair we’d see a rule like this:

.switch.s1:hover ~ .sensor.s1 { pointer-events: auto; }

.sensor:hover { pointer-events: auto; }

This then causes the .sensor in question to be able to interact with the mouse. Since it has a higher z-index than .switch, it will then catch the mouse’s attention.

If at any point in time .sensor is being hovered over by the mouse and has its pointer-events: auto catching it, this means that it is also overlapping with the corresponding .switch. At which point we can say that we know that the mob and avatar are overlapped. So all we need now is to create a rule that acts on the hover event for .sensor. In this case, we’ll be turning the avatar red to show the event.

.sensor:hover ~ #avatar { background: red; }

Don’t Pop The Cork Yet

Victory!

Well, sadly, no.

I made this demo while using Firefox. And current builds of Firefox are very distinct from Webkit and Opera in one very crucial fashion: Firefox actively polls the mouse to determine if hover events are occurring even when the mouse is holding still. So if an animated element (like the mob or its sensors) pass under the mouse, it triggers :hover.

However, in these other browsers, they only bother polling for :hover when the mouse is being used (moving it about, clicking, scroll-wheel, etc). Otherwise, it stops looking and any moving elements passing under it don’t catch the :hover.

So here’s my demo of CSS Hitbox Detection. If you check it in a current Firefox build, you’ll see it working. If you check it in any other browser, you will have to keep wiggling the mouse about to make it work. It also appears that nightly builds of Firefox no longer support this, although I don’t know if that’s by intent or not.

I’ve used pretty big sensor boxes in the demo, as I’m only doing a proof-of-concept here. As such, there can be very significant overlap before the collision is detected. In normal circumstances you’d want your sensors to be as tiny as possible (and therefore have tons of them) to provide a much quicker detection.

As it stands, without the support of actively polling for hover, this isn’t useful for any scenario that requires real-time polling. But it may have other useful applications in an on-user demand. (It would be, for example, bad for a CSS-only Pac-Man game [which would be a nightmare in its own right], but might be usable in a situation where you click a button at a specific point to see if two elements are overlapped).

Notes

Here’s a pared down test of the use case of how browsers handle hover when the mouse is stationary when elements move under it.

Here’s a message by Eric Meyer on www-talk about the issue it brings up.

Thoughts? Workarounds? Uses?

So, CSS Hitbox Detection can exist. But due to how browsers support the :hover event, it may only have a narrow band of application. Obviously this is the sort of interaction that would be better handled by JS (which I knew all along, but was curious to see if a CSS alternative could be made to work).

That said, I’m just one guy with just one brain. I may have overlooked a workaround, or might be failing to see ways this would apply to something really cool despite it’s apparent limitations. Do any of you have thoughts? Ideas? Applications? Please let me know!

I’ll Be Speaking At CSS Dev Conference in Honolulu

Monday, September 10th, 2012

I’m really pleased to announce that I’ll be one of twenty speakers at the CSS Dev Conference on December 5th at Honolulu!

Which leads to reason. After all, you can’t spell CSS without CSSquirrel. (My writing team helped me come up with that one.)

Not only that, I’m apparently an “Industry Leader”. I’ve included a screenshot of the speakers page below that clearly states just that. So now we all have proof forever and take that high school jerks who’s laughing now?

Ahem. I mean, yay me.

I’m the one on the lower left corner with the super cute dimples.

I am so printing this out and putting a copy on the fridge right next to my report card.

I’ll be both speaking and performing functions as Cartoonist in Residence.

I would love to see you there. Yes, you specifically. No, don’t be bashful, we both know you’re super cool.

I’ve got a discount code for $50 for anyone who goes and registers at cssdevconf.com. It’s KYLE. So make sure to tell them I sent you.

Ok guys I’m going to go scream into a pillow for a few minutes then call up my best friends and jump on my bed in exciteme- er, I mean act in a cool, professional manner as I gratefully thank CSS Dev Conference and its organizers for this wonderful opportunity.

See you there?

Elsewhere: Pea.rs

Monday, February 6th, 2012

I’m not at An Event Apart: Atlanta. Which is a shame because by all accounts I missed some wicked banjo playing by Dan Cederholm. And I love listening to some good banjo.

However, I am following along via Twitter, and saw this announcement by Jeffrey Zeldman, web design godfather and co-founder of An Event Apart:

.@simplebits just unveiled Pears pea.rs, an open source web design pattern library/WP theme. #aea

Pea.rs looks like a convenient little tool for web designers to bookmark, a library of sorts where commonly needed HTML/CSS patterns for common page elements like navigation, lists and such can be quickly grabbed and used. I’m sure you’re all so amazing that you don’t need it for your markup, but I also think for prototyping some page elements this might be a good resource to go-to to quickly grab and paste. You might also find a few new ideas on how to arrange your markup or CSS, too.

Check it out.

Comic Update: So Cold

Tuesday, September 6th, 2011
CSSquirrel #86: So Cold

In a perfect world, Ethan Marcotte would star opposite of me in a web design-themed, buddy cop action comedy called Beep and the Squirrel.

Actually… I’m writing that one down, just in case.

Until that glorious moment, I’ll enjoy his raw intellect and seasoned wit while envying his creative talent in a suitably stalker-like fashion. (Unless you’re reading this, Ethan, in which case I assure you that I am in no way digging through your refuse bins looking for cast-off brilliant ideas and toothbrushes.)

While we’re in the vein of borderline creepy idol worship, I’m going to agree with Ethan’s succinct tweet on the W3C’s CSS Conditional Rules Module Level 3 Working Draft (which I’ll reduce to the much easier to remember abbreviation “CCR Module”, hereafter nicknamed the “More Cowbell” document). I feel cold.

I’m still perusing the document. Although any judgement leveled while shooting from the hips (hello, ladies) is bound to be rife with bad summaries and skewed views, in my opinion the module doesn’t seem to solve any problems that aren’t already being solved in a better fashion by good CSS practice or other techniques. It’s a lazy man’s shortcut to “supportin’ olla them thar browsers”.

As Dylan Wilbanks said, these aren’t the conditionals I’m looking for.

Just look at @supports, for the love of cheese (or dairy-free cheese alternative for vegans and the lactose intolerant). It lets you test if a browser supports a feature, before (in their examples) you then go and use the feature. What? How bizarre is that? I know in their examples you can get far trickier with not and or and doogie howser, but seriously?

When it comes to the problems that CSS is supposed to solve, although @supports and its ilk would work, they seem to encourage bad or unnecessarily laboriously bloated CSS documents instead of streamlining the process. And when it comes to @document I believe that the authors are trying to make CSS solve problems it wasn’t intended for.

Look, if you’re trying to get your CSS to be flexibly supported across different browsers and devices, I recommend checking out Ethan’s Responsive Web Design, or at least actually using your skullmeat instead of slapping shoddy shortcuts into your CSS. Capiche?

Square Peg, Round Hole

Tuesday, November 2nd, 2010

There is going to be a comic that gets attached to this rant, I assure you. However, I’m so fired up on the topic at the moment that I’m tossing this post out sans the punchline.

I’ve used border-radius quite a bit. As far as CSS3 goes, it’s one of my go-to styles for making something look snazzy. Just round it and it’s cool, right? Right?

While working on an internal project for Mindfly Studio, I found myself grabbing this particular tool for rounding the thumbnail images that were attached with a list of article briefs. When I went to test the results, I found to my dismay that the images were square still, with the rounded borders cutting behind the square of the image.

Then I remembered that I’d encountered this particular issue before. No problem, I thought to myself. Just wrap that bad-boy in a div (or in this case, an anchor that already existed around the image) and use border-radius on the wrapper. Perfect! Right?

No, sadly.

At this point I felt like my CSS cred was rapidly drying up, and started debating going by JSONSquirrel instead.

“To the cloud!” I pronounced, feeling inclined to abuse buzz words, and fired up Twitter. I was informed this was an issue with Firefox (my browser of choice. I like big butts and I cannot lie) but that it’d be all peachy in Webkit (also known as Apple Browser Jesus in web designer circles).

But as it turns out, Webkit also does it wrong. Less wrong, but wrong.

Here’s my proof: border-radius test page.

What Webkit does correctly is round the corner of the image itself (when the border-radius property is set for the image, but not the wrapper), but it clips the border if one exists. If placed in a wrapper, like Firefox, it fails altogether.

I tested on the following browsers: Safari 5, Chrome, Firefox 3, Firefox 4 Beta, Opera 10.63, Internet Explorer 8 and Internet Explorer 9 Beta. It’s no shock that IE8 didn’t do what I wanted, as it doesn’t support border-radius at all. Although, humorously enough, their outright failure to round the border (while leaving the image square) was still more aesthetically pleasing than the clipping/overlapping that were the results in Firefox, Webkit and Opera. And yes, Firefox 4 Beta also failed to round the corners as I desired.

Unexpectedly, IE9 Beta did exactly what I desired, which was rounding the image with the border intact (and rounded) with it. The only one, in fact, to do so. That was a shock.

Maybe I’m expecting this property to do something other than its actual purpose. That said, wouldn’t an image tag be the most likely case of an element that you’d want a rounded border to work properly with? It certainly is for me.

I’m aware that setting a background-image on an element and rounding it is a workaround that functions perfectly. However, if styles are turned off, you lose the image. What if you want the actual image present regardless of whether CSS was present? Well, at present, go with square corners, it seems.

If someone more clever than me comes up with a way around this that is CSS-based (and not overlapping it with a PNG with a rounded hole in it or some other such workaround) then please let me know. I’d be really curious to see how others tackle this shortcoming.