Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-selectors] :stuck pseudo-class feature suggestion #1656

Closed
o-t-w opened this issue Jul 27, 2017 · 17 comments
Closed

[css-selectors] :stuck pseudo-class feature suggestion #1656

o-t-w opened this issue Jul 27, 2017 · 17 comments
Labels
selectors-4 Current Work

Comments

@o-t-w
Copy link

o-t-w commented Jul 27, 2017

I would like to propose a new pseudo class for use in conjunction with position sticky.
When an element with a position of sticky is fixed, it would have a pseudo class of :stuck
I see people do this all the time with javascript.

One example can be found https://percussionplus.co.uk/checkout/ where the checkout gets a box-shadow when it goes from acting as if it was statically positioned to acting as if it was fixed positioned.
One very common use case: People often animate the height of sticky headers when the user starts scrolling.

I'm sure this would be easy for browser vendors to implement.

@frivoal
Copy link
Collaborator

frivoal commented Jul 27, 2017

Actually, this wouldn't be easy at all, and falls into a class of problems that unlikely to be solvable in CSS: selectors and pseudo classes in particular cannot depend on layout, because otherwise they could be used to modify layout in a way that made them no longer match, which would modify the layout back to where it was, so they match again, and we get stuck in an infinite loop of contradictions.

For a simple example:

:stuck { position: static; }

Now what?

Some of the changes you might want to apply with a :stuck pseudo class may be safe and not trigger such loops, but selectors are a generic mechanism, and would enable this kind of contradictions, so even though the problem you're trying to address seems legitimate to me, selectors are unlikely to be the answer.

@frivoal frivoal added the selectors-4 Current Work label Jul 27, 2017
@o-t-w
Copy link
Author

o-t-w commented Jul 27, 2017

You could simply disallow/make invalid anything that could cause an infinite loop.

@tabatkins
Copy link
Member

tabatkins commented Jul 27, 2017

You could simply disallow/make invalid anything that could cause an infinite loop.

Say we did this, and explicitly disallowed setting position in a rule targeting a :stuck element. Okay, this works for this case.

Next week, someone comes up with a similar circularity they want to allow (like my Toggle States proposal, which has properties interacting with :checked). We disallow that circularity too.

Now someone writes

.foo { toggle-states: 2; toggle-initial: 1; } /* makes it checked */
:checked { position: sticky; }
:stuck { toggle-states: none; }

When it's checked, it becomes sticky. (Assume the page is scrolled such that it becomes stuck immediately.) When it's stuck, it becomes uncheckable, which means it's no longer sticky, so it's not stuck, so it goes back to being checkable, and so it's checked, and so it's sticky, and so it's stuck, and so it's uncheckable...

If you add a third selector/property pair, the number of cycles you need to manage gets even larger.

The only way around this is to define that none of the properties that affect selectors can be used in rules using any of the selectors affected by properties. That ends up with a lot of confusing action-at-a-distance: it's weird that using :checked means that you can't set position: sticky any more.

Instead of doing all of this, so far we've just short-circuited the entire debate and disallowed selectors from being affected by properties.

@o-t-w
Copy link
Author

o-t-w commented Jul 27, 2017

Ok, all of that makes sense, thanks.

@cvrebert
Copy link
Member

@hunboy
Copy link

hunboy commented Jan 23, 2018

I've worked around this behavior, and run in to some troubleshots.

the position: sticky behaves as a position: relative element by the spec. So when we change the height of the :stuck element, the complete layout changes based on the new height. As a workaround I defined margin-bottom for the :stuck element.
Here is the workaround code:

https://jsfiddle.net/utasir/92L8L85q/18/

I've added 1 indicator to the code, but this is against the separation theory of the style and html structure.
A compromised solution would be useful whilst this ticket is closed.

@zipper
Copy link

zipper commented Mar 15, 2018

@tabatkins There are already possible CSS circularity problems, so should we remove :hover pseudo selector as well to prevent it?
https://codepen.io/zipper/pen/NYNEzM

@inoas
Copy link

inoas commented Mar 15, 2018

Use JS(*) for that.

While I use :hover, :target and :checked a lot I don't think behavioral things should be in CSS (neither should be :active or :visited). In fact I think behavioral CSS should be deprecated and be disable-able. So: Adding more of these doesn't sound like a good idea to me.

(*) My 2 cents: JS still has its big issues in terms of language design, privacy and performance (DOM), but: use JS for behavior, not CSS; And if all it means is toggling classes - that's OK!
However: All built-in browser JS libraries and JS std-lib functions should really become bundled into standardized modules so that for privacy (or preformance) reasons people can disable whole modules/parts of JS/JS-browser-std-lib easily. If done well using HTML for semantic structure, CSS for layouting and JS for behavior/interaction becomes a sane thing again

@zipper
Copy link

zipper commented Mar 15, 2018

The biggest advantage of position:sticky (apart from being very easy to use) is that you get rid of JS. So adding JS to detect when the position is stuck is contra productive. Then I could have just stayed with JS solution in the first place, even for sticking the element.

Checking if the element is stuck with JS means I have to do all the logic (including unstucking the element when bottomed the parent element) and don't need position:sticky at all. When I know (by some piece of JS), the element is stuck, I could "stuck" it by myself using position:fixed. So why bother with position:sticky in the first place (in this kind of use case)? The :stuck pseudo selector makes sense for me. Isn't position:sticky behavioural think by itself btw? So when arguing against behavioural thinks in CSS, this should be deprecated aswell?

@jonjohnjohnson
Copy link

@zipper position:sticky provides more than just swapping to position:fixed if you were running tabs on a scroll event. It also works within internal scrolling nodes, so you'd have to swap to position:absolute AND make sure the sticky-like element's offsetParent was the outer element of the node that is scrolling. It also behaves 'fixed' in one axis, unlike actual position:fixed fixing to a root context in both scrolling directions. So if you need to change something about the stuck element when it's stuck, yes JS is needed, otherwise it's out of scope of what position:sticky at least offers.

PS Even using the boundingClientRect of a sentinel element alongside the boundingClientRect of a sticky element is simpler and more foolproof than running JS to swap in position:fixed.

@tabatkins
Copy link
Member

@zipper See https://wiki.csswg.org/faq#selectors-that-depend-on-layout for our standard answer on why :stuck and similar pseudo-classes aren't going to be added. I just updated it with information on why :hover isn't as bad.

@jobs-git

This comment has been minimized.

@tabatkins
Copy link
Member

tabatkins commented May 15, 2018

@jobs-git This comment violates our Code of Conduct. If you can't comment respectfully, don't comment at all; if you can't help yourself, we'll be happy to ban you until you feel you can conduct yourself as required.

@jobs-git
Copy link

jobs-git commented May 16, 2018

After much pondering, I now get why it was not implemented:

  1. Circular selection issue - breaks the website function and user experience, that's a big No No. We can maybe leave that out for developers to figure out the circular issue, but then, it becomes "buggy".

  2. Performance consideration - we can prevent circular selection issue by implementing logic, that might be checking each class & id's if there are combinations that cause circular selection.

In certain websites, there maybe hundreds or worst thousands of these elements, so implementing it could cause compute resource to go exponentially. Doing the same thing in JS would then become faster for that 1 div we want "stuck" pseudo class for.

Suggested solution 1 so that we can address point 2

  1. Implement :stuck pseudo class without logic, then implement a css developer checker within css engine so whenever the devs. are in inspect mode (chrome or firefox or IDE), they get notified about this issue. When not in inspect mode this check is disabled so we avoid issue 2.

Suggested solution 2 so that we can address both point 1 & 2

  1. Implement the :stuck pseudo class like a function so when the css parser encounters :stuck it calls its function then carry out evaluations, if there is a circular selection drop that css block then continue parsing the css.

It goes like this

:stuck --parser--> function stuck(){//drop if circular selection}

In this implementation, we avoid evaluating each and every element since the "checkers" is only asked to evaluate for :stuck class only.

I think the last suggestion is really sensible enough to enable GREAT features without the dreaded performance problem. Can we reopen this ticket for implementations?

@homerjam
Copy link

@SEUH
Copy link

SEUH commented Sep 3, 2018

One year later and still no result. This feature request is very old and still, in more than 5 years there's no change. My problem isn't that this isn't implemented but rather that the system is not adjusted. Yes, the direction is JS webapps but for html/css websites, this can be a big turningpoint. Done right, it can even lead to more functionality but theres no movement in that direction. Everything gets enhanced. It's CSS right? It has to be unfunctional and static style. I don't know how much restrictions there are to not break compatibility but at some point, either there has to be an alternative to CSS or restrictions should be broken. For me, it doesn't make sense to create an alternative because pseudo classes aren't the problem. It's just a problem that would be caused by the implementation

@tabatkins
Copy link
Member

No result because, as has been explained earlier, there's no reasonable way to create a selector that depends on properties. It's a fundamental layering violation, and any attempted fix for this has serious downsides that the WG hasn't been willing to consider.

This is not a matter of legacy compat; if there weren't fundamental issues, we could add :stuck tomorrow and be fine. This is just fundamentally circular in its definition, and so not realistically doable.

@w3c w3c locked as resolved and limited conversation to collaborators Sep 4, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
selectors-4 Current Work
Projects
None yet
Development

No branches or pull requests