Как заверстать блок во всю ширину окна внутри блока с произвольной шириной
Пока переделывал блог, захотелось, чтобы посреди поста можно было ворваться с каким-нибудь блоком во всю ширину окна. Например, вот так:
Ширина основной колонки с контентом при этом абсолютно произвольная и может меняться в зависимости от размеров окна, настроения браузера и фазы луны. Единственное, что про нее достоверно известно — она выровнена по центру:
Самый очевидный способ — прервать блок с контентом, сделать блок без маржинов, затем продолжить контент:
Проблема в том, что посты удобно писать маркдауном, а в маркдауне от такого способа получается адская каша, за которой сложно следить:
<div class="text-content">
# Пост!
Бла бла бла-бла бла. Бла бла? Бла бла-бла...
...бла блабла:
</div>
<div class="fullwidth">
<!-- какая-то демка -->
</div>
<div class="text-content">
Бла блаааа бла бла-бла...
<!-- ...one eternity later -->
</div>
А хочется вот так:
# Пост!
Бла бла бла-бла бла. Бла бла? Бла бла-бла...
...бла блабла:
<div class="fullwidth">
<!-- какая-то демка -->
</div>
Бла блаааа бла бла-бла...
Окей, вставляем блок в контент и даем ему width: 100vw
:
Теперь его надо сдвинуть к левому краю окна. Расстояние неизвестно, но у нас есть ширина блока с контентом (100%
) и ширина окна (100vw
). Сначала двигаем блок направо с помощью margin-left: 50%
:
Теперь блок начинается ровно с середины окна. Отнимаем 50vw
, чтобы блок уехал к левому краю. Получается margin-left: calc(50% - 50vw)
, блок встает на нужное место:
Стиль блока выглядит так:
.fullwidth {
width: 100vw;
margin-left: calc(50% - 50vw);
}
Класс, то что надо.
... или нет? А это что за хрень?
Горизонтальный скролл, блин, откуда?
Оказывается, ширина вертикального скроллбара включается в ширину вьюпорта, то есть 100vw
— это больше, чем нам нужно, и появляется горизонтальный скролл. Не представляю, зачем это сделано именно так, не могу придумать случая, когда это было бы полезным.
А счастье было так близко. Окей, время костылей. Гуглением находится один приемлемый костыль: засунуть в <head>
скрипт, который будет класть в css-переменную 1vw
здорового человека (то есть без учета ширины скроллбара) и пересчитывать его при ресайзах:
<script>
(function () {
function setVw() {
const vw = document.documentElement.clientWidth / 100;
document.documentElement.style.setProperty('--vw', `${vw}px`);
}
setVw();
window.addEventListener('resize', setVw);
}());
</script>
Теперь у нас есть переменная var(--vw)
, в которой лежит нужное нам количество пикселей. Но по старой традиции лучше использовать ее с фоллбеком на обычный 1vw
, вот так: var(--vw, 1vw)
.
В результате стиль блока превращается в...
.fullwidth {
width: calc(100 * var(--vw, 1vw));
margin-left: calc(50% - 50 * var(--vw, 1vw));
}
Мде.
Препроцессоры немного сглаживают эту жесть. Я себе сделал переменную $vw: var(--vw, 1vw)
, мой стиль теперь выглядит как-то так:
.fullwidth
width: calc(100 * $vw)
margin-left: calc(50% - (50 * $vw))
Жить можно.
P.S. Скроллбары на маке
Если вы верстаете на маке, рекомендую включить в настройках системы постоянное отображение скроллбаров: сразу будут видны косяки с горизонтальным (а иногда и с вертикальным) скроллом.
Подавляющее большинство ваших пользователей на винде, где скроллбары всегда видны. Будьте чуть ближе к ним.