Home > Enterprise >  CSS arrow placement "top" is not based off top of page when setting absolute value
CSS arrow placement "top" is not based off top of page when setting absolute value

Time:01-25

I am setting the position of the arrow seen in the screenshot using the calculation in the typescript, however, the position is getting based from the top of the black popup instead of the top of the screen.

  • top of screen to middle of button = 250px
  • top of popup to arrow = 250px

So the offset is correct but it is using the top of the popup for 0px instead of the top of the screen. What can I do to place the arrow using the top of the screen or fix my formula to account for the positioning?

When I use relative positioning: Arrow relative position

When I use absolute positioning: Arrow absolute position

Here is how the css looks (I tried setting relative to absolute which doesn't work:

  .menu-popup {
    --arrow-left-offset: 50%;
    --arrow-top-offset: 50%;

    padding: var(--spacing-s) 0;
    margin: 10px;
    position: relative;

    &::after {
      content: ' ';
      position: absolute;
    }

    // The placement of the arrow
    &.menu-popup-right.standard-variant::after {
      top: var(--arrow-top-offset);
      right: 100%; /* To the left of the menu-popup */
      margin-top: -5px;
    }
  }

I am then updatinging the css variable like this:

  // Changes the placement of the arrow:
  private changeArrowPlacement() {
    if (typeof this.menu === 'undefined') return;

    // The button
    const tRect = this.triggerRef.nativeElement.getBoundingClientRect();
    // The menu
    const mRect = this.menu.nativeElement.getBoundingClientRect();

    if (typeof this.position === 'string' && ['left', 'right'].includes(this.position)) {
      const top = tRect.height / 2   tRect.top   'px';
      this.setArrowOffset('top', top);
    }
  }

  // Sets the the css property:
  private setArrowOffset(position: 'left' | 'top', value: string) {
    if (typeof this.menu === 'undefined') return;
    this.menu.nativeElement.style.setProperty('--arrow-left-offset', '0%');
    this.menu.nativeElement.style.setProperty('--arrow-top-offset', '0%');

    this.menu.nativeElement.style.setProperty(`--arrow-${position}-offset`, value);
  }

The popup is generated via Angular CDK, which creates a div element.

Here is a simple mockup of the html

<!-- Created by me -->
<div id="application">
  <button (click)="openPopup()">Open Popup</button>
</div>

<!-- Created by Angular CDK -->
<div >
  <div >
    <div >
    </div>
  </div>
</div>

Here is what angular generates for the popup:

/* Overlay element */
.overlay {
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
  position: absolute;
}

/* Overlay Pane */
.pane {
  top: 144.5px;
  left: 573.844px;
}

CodePudding user response:

absolute is positioned relative to the parent relative container. So, just remove position: relative from parent container, and you're good to go - your absolute will be then relative to the page body itself (if there's no other containers with position set in between).

Also, if you have no control over parent container, you can try using fixed for your arrow. Note though, it's position will be fixed even if you scroll the page - it will stay in its place on screen.

Finally, you could just place your absolutely positioned arrow by experimentally finding the right coordinates for it. Note, you could use not only px as units, but also %. Or even transform: translate(X, Y); where X and Y could also be either pixels or percentiles.

CodePudding user response:

So it looks like the calculation that I needed was this as it takes into account relative positioning:

const top = tRect.top - mRect.top   tRect.height / 2   'px';
  1. Get the top of the button
  2. Get the top of the menu
  3. Subtract the two to get the difference (arrow is now placed at the top of the button)
  4. Add half the height of the button (arrow is now placed at half the height of the button)

This works if the button is at the top, bottom, left, right, or center of the page.

  • Related