Вообще поведение полностью логичное. Вы сами пишите
что, в принципе, естественно, т.к. отчет от экрана, и с этим можно бороться
относительный размер (как у вас) тоже будет считаться от экрана.
Насколько я понимаю эту проблему призван решить position: sticky, (поправьте, если нет) но работает он пока что далеко не везде.
1. В любом решении без JS необходимо будет какое-то фиксированное значение, один из вариантов: добавить контейнеру фиксированный max-width, а блоку
width: inherit;
max-width: inherit;
Таким образом блок унаследует max-width контейнера и не будет выходить за его пределы.
2. Как контролировать поведение и сделать плавное "скольжение" блока без прыжков на старте?
"Прыжок" в вашем случае это премещение на 12px от края экрана, поскольку вы добавляете класс с
position: fixed
top: 12px
только когда scrollTop становится равен offsetTop, а после этого он естественно отпрыгивает вниз на 12px. Чтобы избежать этого надо добавлять класс когда scrollTop равен (offsetTop - 12px), потому что в этом случае блок при добавлении будет уже в "нужном" месте.
https://codepen.io/Alvvi/pen/MEXeaV