CSS mouse events (e.g. click)


#1

Hi all! Did not find the relevant topic, so decided to open it here.

We still do a lot on the client with JavaScript, however some simple things could be done with CSS as well (I hope :wink:). For example, why don’t we have something like click in CSS? For example, when we have an information block on the page with close button, we still use some JS to close it. To emulate some click behavior we can do something like input[type="checkbox"]:checked + p {...} to make an accordion and other things without JavaScript. But all that looks like a hack with these hidden checkboxes.

What if we could have, say, pseudo-class as :clicked and use it the same way? Then things would go easier, you could do something like: .close-button:clicked .modal-body {display: none;}

Of course, there are some things to think about, like getting the state of the element back (if we need to show the info block once again, we need to reset the clicked state though).

Any way, does it make any sense? May be other ideas how we could do that and what events we could use?


#2

I’m already working on a solution to this! I don’t think we can handle JS events the same way we handle CSS pseudo-classes, but the elementqueries.com syntax could easily be extended to include JS events!

How EQCSS works is CSS styles are scoped to a selector, the plugin adds a unique identifier to each element with queries on it, JS watches the page, and when the query condition is met, it adds a <style> tag to the end of the page with CSS written for the unique identifier of the element that matches the query. For a more in depth explanation of the workings of the plugin, check out the technical documentation: https://github.com/eqcss/eqcss/wiki/EQCSS-1.0.0-~-Technical-documentation

Now, how to handle CSS for events? I propose a syntax like this:

@element 'button' and (event: click) {
  body {
    background: red;
  }
}

But I’m not sure which syntax looks better:

@element 'button' and (click) {}

@element 'button' and (onclick) {}

@element 'button' and (event: click) {}

Unlike CSS pseudo-classes, like :hover which CSS applies and then also removes, there is no way the browser would know to remove the styles from the click query.

Imagine you have code like this:

<input>

<style>
  @element 'input' and (event: keydown) {
    $this {
      background: red;
    }
  }
</style>

After pressing a key, the bottom of your page might look like this:

<input data-EQCSS_1>

...

<style>
  [data-EQCSS_1] {
    background: red;
  }
</style>

Now suppose you added a keyup event as well:

<input>

<style>
  @element 'input' and (event: keydown) {
    $this {
      background: red;
    }
  }
  @element 'input' and (event: keyup) {
    $this {
      background: lime;
    }
  }
</style>

Let’s say you press a keyboard key twice, here’s what the bottom of the page would look like:

<input data-EQCSS_1>

...

<style>
  [data-EQCSS_1] {
    background: red;
  }
  [data-EQCSS_1] {
    background: lime;
  }
  [data-EQCSS_1] {
    background: red;
  }
  [data-EQCSS_1] {
    background: lime;
  }
</style>

Resulting in the last keyup condition’s style being the one that applies. This is closer to how JavaScript events apply CSS styles to elements when you’re working with JS - but you’re right, it sure would be nice to write those CSS styles in a CSS-like syntax.

I was going to make EQCSS v.1.2.0 all about performance enhancements - but if you want to explore adding conditions for events on elements then I can definitely boost the priority of that feature.

Also, note how instead of applying to just one element, in my proposed syntax it acts as a container query, like a @media query it could hold multiple sets of CSS rules applying to many different elements on the page, not just the element that meets the condition.

Let me know what you think, we’ve already got the hard part of this polyfill/plugin done! This is just another feature we can add on top :slight_smile:

(How I think EQCSS would implement the functionality in JavaScript is when it parsed the EQCSS syntax it would add an addEventListener() for that event on that element. When the listener fires would be when that specific CSS would be appended to the page)


#3

Tracking that state would certainly be an issue here like requiring timing events to unset the state. Having JavaScript able to set the state might be the first step along this path which would also be extensible.

@tomhodgins this (shameless plug of some crappy notes I made) https://github.com/jonathanKingston/notes/blob/master/ideas/pseudo-media-query.md was a direction I was going for the same issue as element queries.


#4

@tomhodgins , your syntax suggestion looks quite cool - it gives a possibility to manipulate actually any elements on the page. You think, this elementqueries would be implemented in browsers one day? Actually, the idea is quite promising itself :slight_smile:

The only thing that looks not nice (we should think about it) is he polluting the page with the styles after events are changed, like you’ve described. But for the moment nothing better is coming to my mind. Thanks for the feedback!


#5

This feature sounds pretty awesome and would definitely reduce the necessity for JavaScript (I like JS, but pushing layout stuff to CSS, like animations and transitions, was definitely a good idea).

One thing that bugs me though is that events are different to states. And CSS is all about state. That’s why :hover and media queries work so well in CSS: They describe a state. Events, however, are not a state, they are just a single point in time, they just notify about something. Whether the element is in a different state after that depends heavily on the element. Of course, you can always turn an event in artificial states, like beforeclick, onclick, afterclick but I don’t think that this would be really useful.

Wouldn’t it be better to have a CSS syntax to push elements to a different state, e.g. by adding/removing CSS classes? Thus CSS would not only describe what different states would look like, but also how to transition between them, basically describing a state machine. And that’s usually what we do with JavaScript: Listening on events and modifying CSS classes.

It’s hard to imagine a CSS-ish syntax for it, because the CSS language has no way to describe change. But I do think that it would perfectly fit to the declarative way of describing layouts. It could look like this, for example:

.some-btn {
    onclick: #some-form => (+.dirty, -.pristine)
}

This would add the .dirty class (hence +) and remove the .pristine class (hence -) from the element matching #some-form. I know, the syntax looks pretty weird and there’s probably a more beautiful syntax. But what do you think?


#6

to be clear, this would only be something for situations where a click only has as a result a change in visual presentation, right? i think the number of situations where this is true, compared to situations where you’d also want to execute some actual logic/code first, is quite small…not to mention it just feels very dirty with regards to the old “CSS for presentation, JS for behavior” idea.


#7

There’s precedent for this; :active will fire on anything when clicked, and mobile browsers implement this behavior for :hover as a shim.

CSS has been straining “style and not behavior” for a while now (user-select, pointer-events, will-change, that old “ARIA assigned through CSS” idea, not to mention behavior and binding)—it seems inevitable that we’ll bite the bullet and rename them Cascading Specification Sheets someday. Its declarative assignment mechanism is probably the best thing about it (how great would it be to specify, say, an abbreviation’s expansion through its syntax, instead of repeating title on every <abbr>?), so I’m looking forward to any changes like this.


#8

Well, yes, it is about behavior. But, is this old paradigm still valuable? Are CSS animations or media-queries can be treated only as “presentation” part? :slight_smile: