SpellChucker
SpellChucker

Reputation: 450

Sticky position in Safari with Angular Components

So, position: sticky is awesome, right? And so is Angular, right? Using both in conjunction with Firefox and Chrome work great. The problem starts with Safari.

If you build an Angular component that has a position: sticky div within it as the first element in the template, Safari doesn't know how to handle it. Example:

AppComponent:

@Component({
  template: '<sticky-component></sticky-component>'
})
export class AppComponent {}

StickyComponent:

@Component({
  selector: 'sticky-component',
  template: '<div class="sticky">Should be sticky</div>',
  styles: [
    `
      .sticky {
        position: sticky;
        position: -webkit-sticky;
        top: 0;
      }
    `
  ]
})
export class StickyComponent {}

This will generate a DOM like:

...
<sticky-component>
  <div class="sticky"></div>
</sticky-component>
...

If you physically write out the HTML without the <sticky-component> it works great in Safari. But since the parent of the sticky element is the host element, this fails. Trying to add the sticky CSS to the host element doesn't seem like it works either. Has anyone run into this issue before or has any solution? I know I can implement this sticky functionality using event listeners within Angular, but position: sticky is sooo much easier.

StackBlitz example: https://stackblitz.com/edit/angular-jede8a (works in Chrome/Firefox but not in Safari)

Upvotes: 7

Views: 1528

Answers (4)

Jide&#227;o Filho
Jide&#227;o Filho

Reputation: 85

For me, it worked wrapping the sticky selector inside a div with the height property set in the template.


    @Component({
        selector: 'sticky-component',
        template: 
           `<div style="height: 100%">
              <div class="sticky">Should be sticky</div>
            </div>
           `,
        styles: [
           ` .sticky {
                 position: -webkit-sticky;
                 position: sticky;
                 top: 0;
            }`
        ]
     })
     export class StickyComponent {}

Upvotes: 0

peter he
peter he

Reputation: 11

Not sure about inline styling. But if you move style to an external file. Following should do the trick.

 :host {
    .sticky {
        position: sticky;
        position: -webkit-sticky;
        top: 0;
    }
 }

Upvotes: 1

Lucho
Lucho

Reputation: 1547

First of to make sticky work on safari you need to use position: -webkit-sticky;, but.....

After alot of testing and poking this is simply not working case for Safari when putting position:sticky into a nested element. A good example to check how this behaves i found was this codepen from this post.

There is a bug reported in webkit for this, it also includes a test which i've not completely understood.

So the follow up question, whats your reason to put it in a nested element? Can you work around it?

Upvotes: -1

Lazar Ljubenović
Lazar Ljubenović

Reputation: 19754

This is more of a workaround which might not suit your needs but I guess it deserves an answer since it does solve the problem (not necessarily in the way you'd like it).

If the issue with Safari is a custom element (with a dash) used in the DOM, you can get rid of that by specifying a different selector. Instead of

selector: 'sticky-component',

you could have

selector: 'div[sticky-component]',

and then use the component by adding an attribute.

<div sticky-component></div>

Although certainly not ideal in this use-case, this is a valid way to define components. In fact, it's often done with custom buttons -- for example, Material itself uses this pattern: <button mat-button>.

Upvotes: 5

Related Questions