Overriding Bootstrap without editing Bootstrap

There are two usual ways to change Bootstrap’s colours. Editing variables.less inside the vendor directory, which the next upgrade overwrites, and adding overriding rules in a stylesheet loaded afterwards, which needs a more specific selector for every rule and ends up nearly as large as the thing it is overriding. Less offers a third, and it works because of how the language resolves variables.

// app.less — the only file the build compiles
@import "vendor/bootstrap/less/bootstrap.less";

// Less resolves a variable where it is USED, not where it is defined,
// and the last definition in a scope wins. These therefore apply to
// every rule compiled above them.
@brand-primary:          #1f6f8b;
@font-family-sans-serif: "Source Sans Pro", Helvetica, Arial, sans-serif;
@font-size-base:         15px;
@grid-gutter-width:      24px;
@navbar-height:          56px;

// and only then, for the things no variable expresses
.navbar-brand { letter-spacing: .02em; }

Lazy evaluation is the whole mechanism. Redefining @brand-primary after the import recolours buttons, links, labels and the active navbar item in one line, and @grid-gutter-width regenerates the grid arithmetic rather than fighting it. Sass does not behave this way — there the overrides go before the import and Bootstrap’s own variables carry !default — so advice copied between the two ecosystems produces a file that compiles cleanly and changes nothing, which is the most confusing possible outcome. The costs are a build step, since you are now compiling Bootstrap from source instead of linking a hosted copy, and the discipline of never editing anything under vendor/. That discipline is the only thing that makes the next upgrade a directory replacement.