Решение.
Так как контент секций всегда остается в пределах сетки, а заполнителем выступает лишь фон, и с оглядкой на будущее (вдруг фоном будет выступать картинка, а не сплошной цвет) искал решение на основе варианта, предложенного
#FFFFFF .
Общая разметка колонок страницы
<div class="page">
<div class="page__main"> ... </div>
<div class="page__side"> ... </div>
</div>
Секция размещается внутри основной колонки
<div class="page__main">
<div class="section">
<div class="section__body">
...
</div>
</div>
</div>
Стили колонок представляют собой обычную бутстраповскую сетку (часть медиа-запросов убрана для краткости)
/*==
*== Page layout
*== ======================================= ==*/
.page {
@include make-row();
&__main,
&__side {
@include make-col-ready();
}
&__side {
z-index: 1;
}
// <…cut>
@include media-breakpoint-up(lg) {
&__main {
@include make-col(9);
}
&__side {
@include make-col(3);
order: -1;
}
}
}
И стили самой секции (собственно решение проблемы)
$default-scrollbar-width: 16px;
.section {
@include make-row();
position: relative;
&__body { @include make-col-ready(); }
&::before {
z-index: -1;
position: absolute;
top: 0;
right: percentage(6/9);
width: 100vw;
height: 100%;
transform: translateX(50%);
margin-right: ($default-scrollbar-width / 2);
}
}
Значение для переменной $default-scrollbar-width измерено в браузере линейкой.
Конечно, это не годится для использования, поэтому ширина скроллбара измеряется джавасриптом и в страницу вставляется корректирующий стиль
App.compensateWidthScrollbar = function () {
let width = this.getScrollbarWidth();
let css = '.section::before{margin-right:'+ (width / 2) + 'px';
let style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode(css));
(document.head || document.getElementsByTagName('head')[0]).appendChild(style);
};
Вся эта хрень с правым марджином и шириной скроллбара нужна, чтобы избавиться от горизонтального скроллбара.