bootstrap icon indicating copy to clipboard operation
bootstrap copied to clipboard

Grid System should support CSS Container Queries for responsive column sizing

Open NateRadebaugh opened this issue 2 years ago • 9 comments

Prerequisites

Proposal

CSS Container Queries are becoming widely supported.

  • https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries
  • https://caniuse.com/css-container-queries

Proposal: _breakpoints.scss should be extended to be configurable to use container queries, perhaps defaulting to the body or falling back to media queries where appropriate for backwards compatibility.

Motivation and context

I have pages that can be displayed in either modal or full-page and currently there isn't a good way to wire up this sort of functionality.

Layouts with collapsible side navigation or modal dialogs would benefit from Container Queries instead of using normal Media Queries for responsive widths.

NateRadebaugh avatar Jan 04 '23 21:01 NateRadebaugh

I'm having the same issue, with grid layouts that get squished when rendered inside modals. Here's a quick hack that just stacks grid columns inside modals:

// Stack grid columns when displayed in a modal
@each $breakpoint in map-keys($grid-breakpoints) {
  $infix: breakpoint-infix($breakpoint, $grid-breakpoints);
  @for $i from 1 through $grid-columns {
    .modal .col#{$infix}-#{$i} {
      width: 100%;
    }
  }
}

Adding this, any .col-BP-I class inside a modal will just stretch to full-width. It's a bit brutal but it works well. And it doesn't even need container queries, making it compatible with older browsers 😉

goulvench avatar Jan 05 '23 17:01 goulvench

Thanks @goulvench this is a nice workaround, but doesn't fully solve the need. For instance, if we have a shared component inside one of bootstrap's various modal sizes: https://getbootstrap.com/docs/5.3/components/modal/#optional-sizes

An additional scenario I'm trying to support is a layout with a side nav menu that can be expanded or collapsed. I'd like the grid system to be based on the width of the "main" component rather than the whole page width.

NateRadebaugh avatar Jan 09 '23 13:01 NateRadebaugh

I solved my problem (which was that i wanted to be responsive against the size of my content-container) with patch-package with the following patch (named patches/bootstrap+5.2.3.patch) :

The following Code does not set breakpoints relative to @media but relative to the element you add a specific class to.

diff --git a/node_modules/bootstrap/scss/mixins/_breakpoints.scss b/node_modules/bootstrap/scss/mixins/_breakpoints.scss
index 286be89..f80a7ea 100644
--- a/node_modules/bootstrap/scss/mixins/_breakpoints.scss
+++ b/node_modules/bootstrap/scss/mixins/_breakpoints.scss
@@ -61,7 +61,7 @@
 @mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
   $min: breakpoint-min($name, $breakpoints);
   @if $min {
-    @media (min-width: $min) {
+    @container #{$containerName} (min-width: #{$min}) {
       @content;
     }
   } @else {
@@ -74,7 +74,7 @@
 @mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {
   $max: breakpoint-max($name, $breakpoints);
   @if $max {
-    @media (max-width: $max) {
+    @container #{$containerName} (max-width: #{$max}) {
       @content;
     }
   } @else {
@@ -89,7 +89,7 @@
   $max: breakpoint-max($upper, $breakpoints);
 
   @if $min != null and $max != null {
-    @media (min-width: $min) and (max-width: $max) {
+    @container #{$containerName} (min-width: #{$min}) and (max-width: #{$max}) {
       @content;
     }
   } @else if $max == null {
@@ -112,7 +112,7 @@
   $max:  breakpoint-max($next, $breakpoints);
 
   @if $min != null and $max != null {
-    @media (min-width: $min) and (max-width: $max) {
+    @container #{$containerName} (min-width: #{$min}) and (max-width: #{$max}) {
       @content;
     }
   } @else if $max == null {


and an additional styling:


$containerName: mainSection;

// to have a fallback if certain elements are not inside the .breakpoint-container class (like modals or notifications)
body{
  container-type: inline-size;
  container-name: $containerName;
}

.breakpoint-container {
  container-type: inline-size;
  container-name: $containerName;
}

and used like this:

...
<app-sidebar ></app-sidebar>
  <div>
    <app-header></app-header>
    <section class="breakpoint-container">
      ...
    </section>
    <app-footer ></app-footer>
  </div>
...

But i hope it gets built in in some form!

EDIT: added fallback to body container

Joniras avatar Mar 06 '23 10:03 Joniras

@Joniras where did you add the additional styling? Could you create a Repository or something like that for your fix?

Thank you!

Schwarcelo avatar Jun 05 '23 08:06 Schwarcelo

@Schwarcelo The additional styling has to be applied on a global level. It has to be included before the bootstrap scss because the scss variable is defined in the additional styling and used in the (changed) bootstrap mixins.

Joniras avatar Jun 05 '23 20:06 Joniras

+1 for that feature. E.g. creating cards or square-tiles holding lots of content (e.g. header, sub-header, text, buttons, ...) where the font-size should be scaled beside being rendered in 1-4 responsive columns depending on the parents width, is a huge mess just using breakpoints.

Moongazer avatar Oct 26 '23 14:10 Moongazer

Bootstrap are in dire need of adding this, it is such a basic necessity, that columns should be based on the container that they're in and not the device width. iFrames, modals, even just adding in an aside to a page stuffs up all of your bootstrap responsive classes.

### PLEASE ADD THIS IN ASAP!!!!!!!!!!!!!!!!!!!!!!

lana-white avatar Jan 16 '24 01:01 lana-white

I have added this to my scss for the time being:

.cq {
    display: flex;
    flex-wrap: wrap;
    container-type: inline-size;

    & > * {
        flex: 0 0 auto;
        width: 100cqw;
    }
}

@each $infix, $breakpoint in $grid-breakpoints {
    @container (min-width: #{$breakpoint}) {
        .cq-#{$infix}-1 {
            width: 8.33333333cqw;
        }

        .cq-#{$infix}-2 {
            width: 16.66666667cqw;
        }

        .cq-#{$infix}-3 {
            width: 25cqw;
        }

        .cq-#{$infix}-4 {
            width: 33.33333333cqw;
        }

        .cq-#{$infix}-5 {
            width: 41.66666667cqw;
        }

        .cq-#{$infix}-6 {
            width: 50cqw;
        }

        .cq-#{$infix}-7 {
            width: 58.33333333cqw;
        }

        .cq-#{$infix}-8 {
            width: 66.66666667cqw;
        }

        .cq-#{$infix}-9 {
            width: 75cqw;
        }

        .cq-#{$infix}-10 {
            width: 83.33333333cqw;
        }

        .cq-#{$infix}-11 {
            width: 91.66666667cqw;
        }

        .cq-#{$infix}-12 {
            width: 100cqw;
        }
    }
}

so you can use it like row/col:

<div class="cq">
    <div class="cq-sm-6 cq-lg-4">Hello</div>
    <div class="cq-sm-6 cq-lg-4">Hello</div>
    <div class="cq-sm-6 cq-lg-4">Hello</div>
</div>

manstie avatar Mar 21 '24 03:03 manstie

I have started a repo to try implementing container queries in the bootstrap way, but it's still work in progress: https://github.com/bastienmoulia/bootstrap-container-queries PR welcomed 😉

bastienmoulia avatar Mar 26 '24 06:03 bastienmoulia