csscss-gridbootstrap-5container-queries

How to use specific divs to measure Bootstrap's breakpoints?


Can Bootstrap 5 provide responsive layouts for two columns whose mutual, vertical border can be dragged? Answer: Yes, by reconfiguring Bootstrap to use container queries rather than media queries. Container queries are supported by major browsers since Feb 2023.

Background: Two divs are stacked side-by-side as columns. Between them is a draggable separator affordance. E.g., the leftmost div has the css resize property set to horizontal, while the rightmost has Bootstrap class flex-grow-1. The user can then drag the separator affordance to the left or right.

Desired outcome: Bootstrap's grid tiers inside the column divs should be chosen based on the divs' individual widths as opposed to relying on the viewport width.

Illustration (all gray divs have class="col-sm-12 col-md-6 col-lg 4"):

enter image description here

So, when using the col-sm-12 col-md-6 col-lg 4classes etc. in Bootstrap, how to best add logic to “do measurements based on the parent div” or “div with id #X”?

Here is a working example that illustrates this problem...

{
    var startDrag = -1;
    var startWidth = -1;
    $(document).on('mousemove', function(e) {
        let $totalArea = $('#total-area'); 
        let $leftSide = $('#left-side');
        let $rightSide = $('#right-side');
        let lx = $leftSide.offset().left;
        let ly = $leftSide.offset().top;
        let lWidth = $leftSide.outerWidth();
        let rWidth = $rightSide.outerWidth();
        let tWidth = $totalArea.outerWidth();
        let lHeight = $leftSide.height();
        let sliderWidth = 20;
        const x = e.clientX;
        const y = e.clientY;
        const lSlider = lWidth + lx - sliderWidth/2;
        const rSlider = lSlider + sliderWidth;
        let inSlider = x > lSlider && x < rSlider && y > ly && y < lHeight + ly;
        if(e.which == 1 && startDrag >= 0) {
            let diff = x - startDrag;
            $leftSide.css('width', startWidth + diff);
            $rightSide.css('width', tWidth - startWidth - diff);
        } else if(e.which != 1 && startDrag >= 0) {
            $leftSide.css('cursor', 'default');
            $rightSide.css('cursor', 'default');
            startDrag = -1;
            startWidth = -1;
        } else if(inSlider) {
            $leftSide.css('cursor', 'ew-resize');
            $rightSide.css('cursor', 'ew-resize');
            startDrag = x;
            startWidth = lWidth;
        }
    });
}
<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="icon" href="BootstrapBench.png">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"             rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <title>Bootstrap 5 template</title>
</head>
<body>
    <div class="container-fluid">
        <div class="row" id="total-area">
            <div class="border-end border-dark border-1" id="left-side" style="width:50%">
                <div class="container-fluid">
                    <div class="row bg-info">
                        <div class="col-sm-12 col-md-6 col-lg-4">
                            <div class="bg-secondary text-white text-center m-2 p-2">
                                <h1>1</h1>
                            </div>
                        </div>
                        <div class="col-sm-12 col-md-6 col-lg-4">
                            <div class="bg-secondary text-white text-center m-2 p-2">
                                <h1>2</h1>
                            </div>
                        </div>
                        <div class="col-sm-12 col-md-6 col-lg-4">
                            <div class="bg-secondary text-white text-center m-2 p-2">
                                <h1>3</h1>
                            </div>
                        </div>
                        <div class="col-sm-12 col-md-6 col-lg-4">
                            <div class="bg-secondary text-white text-center m-2 p-2">
                                <h1>4</h1>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="border-start border-1 border-dark" id="right-side" style="width:50%">
                <div class="container-fluid">
                    <div class="row bg-warning">
                        <div class="col-sm-12 col-md-6 col-lg-4">
                            <div class="bg-secondary text-white text-center m-2 p-2">
                                <h1>5</h1>
                            </div>
                        </div>
                        <div class="col-sm-12 col-md-6 col-lg-4">
                            <div class="bg-secondary text-white text-center m-2 p-2">
                                <h1>6</h1>
                            </div>
                        </div>
                        <div class="col-sm-12 col-md-6 col-lg-4">
                            <div class="bg-secondary text-white text-center m-2 p-2">
                                <h1>7</h1>
                            </div>
                        </div>
                        <div class="col-sm-12 col-md-6 col-lg-4">
                            <div class="bg-secondary text-white text-center m-2 p-2">
                                <h1>8</h1>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <script
          src="https://code.jquery.com/jquery-3.7.1.slim.min.js"
          integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8="
          crossorigin="anonymous"></script>        
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>

</html>
Starting layout... original configuration

Slider to the right... slider to the right

Slider to the left... slider to the left


Solution

  • For each desired Bootstrap class, e.g. col-sm-6,col-md-4 and col-lg-3, override the width set by Bootstrap's media queries and use a width based on container queries, as below. This allows the changes to be done only in CSS, with no changes to the HTML and no JavaScript, using vanilla Bootstrap classes, just adding a ucq (“use container queries”) class where desirable.

    CSS:

    .container-query-target { container-type: inline-size; }
    
    /* ucq: use container queries */
    .ucq .col-sm-6,
    .ucq .col-md-4,
    .ucq .col-lg-3,
    { width: 100%; }
    
    @container (min-width:576px) {
        .ucq .col-sm-6 { width: 50%; }
    }
    @container (min-width:768px) {
        .ucq .col-md-4 { width: 33.33333333%; }
    }
    @container (min-width:992px) {
        .ucq .col-lg-3 { width: 25%; }
    }
    

    HTML:

    <div class="row container-query-target ucq">
        <div class="test col-sm-6 col-md-4 col-lg-3">Sample content</div>
    </div>