
Фикс скроллбар-сдвига
Сегодня расскажу про старый-добрый CSS-трюк.
Бывает кейс, когда интерфейс сайта центрируется, и при появлении и скрытии скроллбара контент начинает сдвигаться чуть в сторону на ширину скроллбара. Особенно актуально в случае модалок, при появлении которых общий скролл «выключается» и интерфейс «прыгает» вправо, а при сокрытии — обратно влево.
Это можно решить, задав в CSS принудительный показ скроллбара с overflow-y: scroll
. Но тогда скролл будет показываться в том числе, когда в этом нет необходимости.
Можно также придумать или найти разные варианты решения этой проблемы на JS: высчитывать ширину скроллбара и вычитать её из общей ширины body, либо вычислять разницу между интерфейсом со скроллом и без скролла, а затем компенсировать эту разницу опять же для body
. Но всё это кажется неизящными костылями. Даже если пробросить вычисленное значение в CSS кастомными свойствами.
Есть более изящный костыль на CSS, который применяется только когда нужно и не нагружает скрипты ненужными махинациями.
Суть в том, чтобы задать контейнеру, внутри которого располагается центрирующийся контент, компенсирующий отступ слева, если скроллбара нет. А если скроллбар есть, то этот отступ должен убираться.
.container { margin-left: Npx;}
Как вычислить это значение без прибегания к скриптам? На помощь приходит то, чему равняются значения 100%
и 100vw
для блока со скроллом. В случае vw
— это ширина всего вьюпорта, включая скроллбар, а в случае %
— это ширина блока без скроллбара. То есть разница между этими двумя значениями — это и есть ширина самого скроллбара:
.container { margin-left: calc(100vw - 100%);}
Если скроллбар есть, то отступ будет, так как 100vw
будет больше 100%
. Если скроллбара нет, то 100vw
и 100%
будут равны между собой и отступа не будет.
Демо тут: попробуйте понажимать на кнопку, которая включает и выключает скролл, и увидеть сдвиг, а затем раскомментировать фикс.