Position an element relatively to another element from anywhere in the DOM


#21

I think these are all solid concerns, but I also think they might be outside the scope of what this feature is trying to accomplish. Since these are all edge-cases contingent on the project, I think the solution to solving these problems is Javascript, but it would be really neat to see rules that could handle these cases.


#22

I like this! Container queries (or whatever they end up being) might help some of the special cases, but there will always be others.

Absolutely, they’d have a great perspective on this issue! I’ll hit them up on Github.


#23

Thanks for the example, but it seems like this could be adequately solved using position: absolute/relative. Do you have a more specific use case?

.card {
  position: relative;
}
.unread {
  position: absolute;
  top: 2px;
  left: 2px;
}

#24

Say there are multiple elements in .card.


#25

Author of Tether here…

First off, thanks so much for bringing this up. @cvrebert’s A–C complications/use-cases are great; we’ve certainly see all those with Tether. Some things that come to mind (in no particular order):

  • This may seem obvious or I may have missed somebody mention it, but overflow: hidden needs to be ignored by the element for all of the target’s parents as well as the target itself.
  • Similarly, overflow: scroll (or auto when the scrollHeight/Width exceeds the clientHeight/Width) needs to be addressed for all of the target’s parents as well.
  • Allowing an element to be the target of anotherElement (a tethered chain) would be marvelous.
  • Expanding on @cvrebert’s (A), allowing for a simplistic version of Tether’s notion of Constraints & Attachment would be nice. Syntactical strawman:
#element {
  position: element(#target) constrain-to-window;
  left: 0;
  top: 100%
}
  • I wonder if there might be an overlap with position: sticky, or any of the work there.

In general, my two cents are that when in doubt, making the behavior match how positioning would work if the element were position: absolute and a direct descendent of the target is probably the right call. So for example in @cvrebert’s (B), setting left: 0; right: 0 would render the width 0.

I hope this helps! Happy to share more of my experiences working on Tether or its consumer libraries Tooltip, Drop, Select, Shepherd, etc.


#26

This feature would solve one of CSS’ biggest problems in UI designs. However, just accepting IDs makes this feature as a no-js-solution completely useless, because UI components usually don’t use IDs :worried:


#27

Hi all

It would be a very usefull technique and it would help in moving UI-JS logic more into CSS. Although it is little bit ambiguous, I like the idea with:

#element{
   position: element(#target)
}

I have another suggestion to the problem, what about using an at-rule(!) or a css function:

@@stick(#element to #target)
or
@@design( group(#element to #target) )

-fn-group(#element to #target);

What do you think?


#28

Maybe I’m just missing something here, but doesn’t restricting to IDs just put us back at square one? If we can only target by ID then either:

  1. It’s not DRY because we have to have a different CSS rule for every single “relative-to” element, or
  2. We have to use JS to retarget dynamically

…which is exactly what we wanted to avoid in the first place, no?


#29

The original use case was focused on positioning one element against another and that cannot be adequately accomplished today (outside of stylistically positioning with JS). Using tooltips, popups, modals, etc. outside of JavaScript has never been a use case for me (as they’re typically a reaction to some DOM event) so I could keep things DRY by simply switching the target Id.

When it comes to positioning the element, stuff we have (directional properties, media queries, transforms) and stuff that’s in the works (container queries) looks like it’d pretty much accomplish what I needed.

The suggested syntax accomplished everything I needed, would be super easy to implement for the end developer, and has a track record in existing browsers.

As other use cases are added/considered my suggested syntax probably won’t be all things for all people and that’s why it’s awesome to see everyone commenting. They have more cases from a variety of different perspectives.

If you have another use case in mind, please link it up or post it here! Ultimately, any additional flexibility the spec could give us in this area is a good thing.

When you say this it makes me think you’ve got a list of items with counters, tooltips, etc. I’ve been able to accomplish this effect with a combination of position: relative/absolute; as outlined in one of my earlier posts. If you have other use cases, please link or add them to the thread.

Sort of. My main goal was to eliminate styling in my JavaScript. Using JavaScript to change target Id’s or toggling classes on and off in response to DOM events works for me. Did you have a specific use case in mind where you wouldn’t want to use JS?

Hopefully that makes sense! As long as I can accomplish my simple use case I’ll be happy with anything :smile:


#30

That’s an interesting remark, you often need IDs in many UI components to be accessible.

In the example associated with this proposal, it would be hard to uniquely identify the appropriate element the dialog (in open mode as the dialog presentation available via showModal() would be irrelevant here) should be relative to.

An ID would be needed for the dialog be associated with the correct element as far as what its information is relevant to. For similar reasons, WAI-ARIA attributes primary only accepts IDs.

In general, seemingly classes & other selectors much less specific than ID would need things like the content CSS property to be much more powerful across all browsers for it to be worthwhile to allow things that traditionally only accepted IDs to also accommodate them.


#31

Using CSS for layouting and JS just to target the element is surely better and less error prone than using JS for everything. However, if I use JS to target the element, it’s still a bit complicated. I would need to generate a unique ID, assign it to element1 and then add dynamically the required position styling to element2.

Wouldn’t it be more helpful to have IDs that are only valid within a specific scope? Or is the Shadow DOM just the thing we’re searching for?


#32

How about something like this?

<div class="wrapper">
    <div class="tooltip">Tooltip Text</div>
    <input type="text">
</div>

<style>
    .tooltip {
        position: relative-to(input:focus);
    }
</style>

When the input isn’t in focus, the match fails and the tooltip reverts to display: none.

Of course, this would require that the browser only match to elements with a common ancestor, as previously discussed—but if it works then you could just have the one rule apply to an entire set of tooltips on a form.


#33

You’ve got me here. I mentioned earlier that pseudo states would be a powerful tool to have in the spec:

I think it’ll all come down to performance and what browser makers can allow. Maybe just allow a single selector with an optional pseudo state? From there, any selector that matches multiple elements could automatically imply :first-of-type. What would you think about that?

.tooltip {
    /* Perfectly Valid */
    position: relative-to(input:focus);
    position: relative-to(.input:invalid);
    position: relative-to(#input);
    position: relative-to([type="text"]:disabled);
    position: relative-to(*:hover);

    /* Just no... */
    position: relative-to(*.list-item:not(.blue):not(.red):not(.green):not(.yellow) + *:last-child);
}

#34

I don’t think that DRY needs to apply to rendered code (ie HTML)


#35

:+1: Something along those lines might actually solve all the issues—if the browser finds multiple matches, it goes with the first/closest and ignores the others. The spec would need rules to define “closest”, but once that’s done it opens up the possibility of using just about any kind of selector.

We would probably need something like that for hover states anyway since they propagate up the tree.


#36

I would think it’s pretty good, which is why I proposed the function work that way three days ago.


#37

Better? I’m genuinely not trying to steal your thunder here bud. If you have a problem with something I said, feel free to PM me and we can work it out there.


#38

I don’t care about attribution (if I did, I wouldn’t have signed the W3C CCLA). What I care about is that you disregarded this idea when I initially proposed it, then revived it - incompletely - without even alluding to the earlier discussion. This is how specs get holes in their coverage.


#39

If you don’t care about attribution, then why does it matter if it was disregarded? The idea resurfaced and others seem on board.

Also, I didn’t disregard your idea. We have several posts back and forth where we hashed things out. Your use case was a poor example (in my opinion) and then there was your follow up comment:

It seemed to me like you were being more contrarian than actually being constructively critical. I just decided to drop it and talk it out with other posters.

Spare us the hyperbole. You seem like a smart person who has use cases for this so I don’t want you to feel like you’re not being heard. If you have great use cases that make sense to me then I’ll address them with my use cases and thoughts (as will hopefully everyone else). That’s what this thread is about. The spec writers are experts and will do their thing if they feel this thread warrants it.

Let’s get back on topic. If you want to keep arguing about this, I’d be happy to work it out over PM.


#40

Just been reading through the majority of the comments here, sounds awesome! Just another thought, would it be beneficial to add a center option to the standard positioning - top, right, bottom, left… or would you just handle that with translate?