Problem -
I need to position a popup modal / tooltip / dialog relative to another element, perhaps the button that I clicked to trigger the popup or relative to a block of text that’s relevant to the popup’s information. Something like this:
We want the positioned element relative to the target element at all times. Unfortunately, we really only have a couple of solutions and neither are ideal for this problem:
``1. Make the dialog a sibling/ancestor: As long as the dialog and target element are related, I can position: relative;
a common parent and then position: absolute;
the dialog. From there, I just need set the top
, left
, right
, and bottom
properties (or use transform: translate()
) to set the desired position.
Problems with this solution:
- Not at all DRY: If I have a list of items with buttons that need dialogs, I have to create as many dialogs (even if they say/accomplish the same thing) so that I can ensure they’re positioned correctly. I don’t want to add all those extra elements.
-
At the mercy of the parent: Parent have an
overflow: hidden;
set? Good game bro… this solution’s a no go.z-index
not right? Too bad.
``2. Use JavaScript to calculate the position: Just grab the offset of the target element, position: absolute;
the dialog and start setting styles.
Problems with this solution:
- Violates SoC: I have to rely on JavaScript to stylistically position my dialog to the relevant element. Gross.
- No Guarantees: Did the user resize the window? Guess I have to add an event handler to recalculate. Did the target element shift due to an animation or another event? Ugh, guess I can set some sort of callback(s) to deal with that. JavaScript turned off… oh well??
Suggested Solution -
We need to be able to visually associate one element (the connected) with another (the target), so why not extend the position
property in CSS and allow us to pass in an element selector.
.connected {
position: element(#Target);
transform: translateY(-100%);
}
The syntax was borrowed from Mozilla’s element() function for the
background-image
property
When an element is elementally positioned, it’s X/Y page offset becomes identical to the target element’s. As the target shifts around the page due to various events, the connected element shifts with it. From there, it can be offset from the target by using top
, left
, right
, bottom
, transform: translate;
or a combination of all 5. The connected element would act as if it was contained within the target element so right: 0
, top: 0
would position the connected element in the top right corner of the connected element.
For all children of the connected element, position element()
would act like position: relative
.
With this solution, I can visually associate any element with any other, don’t need to duplicate elements, and I don’t need to rely on JavaScript for presentation.
Popup’s were just one use case, there are several others that I can list if we need them! I apologize for the wall text, please let me know if anything is unclear!