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


#41

I think if we’re going to add center-based absolute/relative positioning to CSS, we should do it across the board, not just for element-relative positioning.

As always, though, I defer all detailed thoughts on CSS Positioning to the current editor of the CSS Positioning spec, @tabatkins.


#42

Agreed! Sounds like a good idea.


#43

Additional use-case: a CSS file that aims to imitate legendary typographer Edward Tufte would be able to more semantically mark up their footnotes if this existed.

Right now, it has to use <span class="sidenote"> as an inline element to get the styling it wants (positioned away from the paragraph, starting at the same height as the footnote marker). If relative-to-element positioning existed, it could use a separate <aside>.

Discussion on GitHub:


#44

That’s not transparent at all. The value of position should not influence the value of display. If the selector does not match, then position should simply take its default value (like other properties do when you define something that doesn’t make sense, e.g. position: banana reverts to position: static.

The behaviour you want would require some way of selecting the target of a relative-to connection from its anchor (ex. 1), or to have some fallback mechanism (ex. 2). I don’t think either of these are winners, and would probably introduce all sorts of interesting possible feedback loops.

Ex. 1

.callout {
    display: none;
    position: relative-to(.anchor);
}

.anchor:focus:relative-to-targets {
    display: block;
}

Ex. 2

.callout {
    display: none;
    position: relative-to(.anchor:focus);
}

.callout:positioned-relative-to {
    display: block;
}

#45

Any updates to this? I would like to implement this but looks like tether is the easiest way to do so instead of messing around with debouncing resize and scroll events.


#46

I think Tether is still the way to go. Update would be great. @tabatkins mentioned last July he had planned to pursue this in the position spec, but I have no idea what the status is on that.


#47

I do agree with @jhnns that just accepting IDs can be problematic, however I think a stronger argument would be that this solution should support multiple elements with the same css classes to simplify the css code necessary to style the elements. After all, if I wanted to have multiple “dialog” elements that “pop up” from one central element, I think I should be able to.


#48

is this work with multiple ids of divs or multiple div’s with same class as below

Change
sample
familiar
popover is displaying always at 1st div position...

my theme is: I need to display popover at second div element when i click on second div…as it is for third div…Can you please help me out…


#49

Using JavaScript we can do this already, and there’s a syntax that allows you to do this sort of positioning very easily that you can use today!

With the idea of scoped styles we can write a query that targets one element and contains a block of CSS rules that can apply to any element in the DOM. If you add in the ability to evaluate a little bit of JS from within the same context as that element, suddenly you can access the scoped element’s properties, like offsetTop or offsetHeight and use the resulting values anywhere in your CSS when writing a rule for any other element!

Here’s an example where we have 2 div elements in our HTML and we want to position the #second element so it’s always touching the bottom-right corner of the #first element, regardless of their relationship in our HTML.

Consider this syntax:

<div id=second></div>
<br><br>
<p>Any HTML can separate these elements, their location & order in the DOM are irrelevant</p>
<div id=first></div>

<style>
  div {
    width: 50%;
    height: 50px;
    background: lime;
  }
  @element '#first' {
    #second {
      width: 50px;
      background: red;
      position: fixed;
      top: eval('offsetTop + offsetHeight')px;
      left: eval('offsetLeft + offsetWidth')px;
    }
  }
</style>

<script src=http://elementqueries.com/EQCSS.js></script>

Here, the eval('offsetTop + offsetHeight') is getting those values from #first because that’s the element we have scoped in our query: @element '#first' {}


#50

It seems to me that what is desired is.

  1. A version of sticky positioning that swaps between absolute and fixed rather than relative and fixed. This part should be simple.
  2. Position relative to an element that isn’t a direct ancestor. I think the best we possibly might get is to position relative to an earlier sibling matching some additional criteria (i.e. like the general sibling selector), but that should be good enough for every use case described.
  3. Ignore certain visibility rules like z-index and overflow to make the element always visible and on top. I know overflow isn’t an issue since you can ignore that using nested absolute/fixed already. Z-index however seems problematic since that would violate core nesting behavior. It doesn’t seem like an impossible issue, but it certainly would be an ugly exception with possible performance implications since the HTML hierarchy would no longer correspond to stacking order.

Personally I solve my dialogs by setting up an event handler + mutation observer when the dialog appears, and display the dialog at the top layer as sticky. Rather than specifying an absolute position I simply give the dialog the coordinates of the element it’s supposed to be attached to as custom properties, which the event handler updates if the element moves for any reason. This preserves responsibility as much as possible since the JS only provides data, it doesn’t set styles. I also handle all movement animations with separate classes with specific prefixes, so I can temporarily copy over only those classes to the dialog and make it follow.

It’s not optimal since obviously transforms like scale should also move the dialog, but those things can’t simply be copied. Still, it works well enough that I could write a little library for it and never concern myself with it again. A CSS solution would be nice, but I can live without it.


#51

I like this article, but I tried this and it pushes the descendant elements down when the elementally positioned element shows. The only way I know to make a tooltip-type element without shifting other elements on the page down is to use position: absolute (or fixed). An example of my password validator:

        <div class="col-4 col-12-xsmall">
            <h4>Password
                <i id="add-mb-btn-gen-pass" class="normalBtn fas fa-refresh" title="Generate Password"></i>
                <i class="normalBtn fas fa-question-circle popHelp" data-topic="password-input"></i>
            </h4>
            <input type="password" id="add-mb-pass" name="pass" value="" placeholder="Password" />
            <div id="pval-cont">
                <div id="pw-validate">
                    <h4>Password must meet the following requirements:</h4>
                    <ul>
                        <li id="pw-letter" class="pw-invalid pw-item">At least <span>one letter</span></li>
                        <li id="pw-capital" class="pw-invalid pw-item">At least <span>one capital letter</span></li>
                        <li id="pw-number" class="pw-invalid pw-item">At least <span>one number</span></li>
                        <li id="pw-symbol" class="pw-invalid pw-item">At least <span>one symbol</span></li>
                        <li id="pw-length" class="pw-invalid pw-item">Be at least <span>8 characters</span></li>
                    </ul>
                </div>
            </div>
        </div>

CSS:

#pval-cont
{
    position: relative;
}
#pw-validate {
    display: inherit;
    position: absolute;
    top: 10px;
    left: 15%;
    z-index: 20;
    width:250px;
    padding:15px;
    background:#fefefe;
    font-size:.875em;
    border-radius:5px;
    box-shadow:0 1px 3px #ccc;
    border:1px solid #ddd;
}

password-validator

This is not the complete CSS (for reasons of brevity), but if anyone wants it, I’d be happy to share. I’ve tested this out on several browsers and mobile and resized the screen and tried every mutation of the page I can think of and it stays in position no matter what I try. I’d appreciate anyone’s thoughts or ways to improve this. Thanks!