Responsive grid system for component development #21662

Closed
kfenner opened this Issue Jan 11, 2017 · 4 comments

Projects

None yet

5 participants

@kfenner
kfenner commented Jan 11, 2017 edited

Quick summary: Media queries do not work for component development, we need another solution.

We are using Bootstrap in our efforts to build a component/widget library. This works very well, but we are running into issues when it comes to more complex, responsive components. When building a component, we don't know in which context the component will be used later. Especially regarding the size of the parent container where it will be embedded in the target application.

The following picture tries to explain the issue. Component A is used in two containers which have a different width. Component A wants to react to the different container sizes and display itself according to the available space. But this is not possible with the Bootstrap grid system, because it relies on media queries which always target the whole screen or iframe and not the size of the container. That means, e.g. the same col-* classes will be active for the small and the large version of Component A at the same time, making it impossible to show a small and a large version of Component A.

image

The main issue lies within the nature of CSS media queries. This is a general issue when developing reusable responsive components. There are some alternative approaches like Element Queries. but it's far from a web standard and has its own drawbacks. Therefore we developed a small extension to the existing Bootstrap grid. Note that this solution is still based on Bootstrap v3 but it shows the approach and should be easily adaptable for v4.

// Grid system
// ===========
//
// Extends the Bootstrap grid system with additional container classes
// which are not based on media queries for their responsiveness.
// Instead, the size classes are manually applied (or via JavaScript).
// Available classes: container-xs, container-sm, container-md, container-lg
//
// This is implemented by resetting (actually setting to "defaults") the bootstrap
// grid framework classes if we're in the context of a `container-*` class.

// These mixins are adapted from upstreams `mixins/_grid-framework.scss`
@mixin reset-float-grid-columns($class, $i: 1, $list: '.col-#{$class}-#{$i}') {
  @for $i from (1 + 1) through $grid-columns {
    $list: '#{$list}, .col-#{$class}-#{$i}';
  }

  #{$list} {
    float: none;
  }
}

@mixin calc-grid-column-reset($index, $class, $type) {
  @if ($type == width) and ($index > 0) {
    .col-#{$class}-#{$index} {
      width: auto;
    }
  }
  @if ($type == push) and ($index > 0) {
    .col-#{$class}-push-#{$index} {
      left: auto;
    }
  }
  @if ($type == push) and ($index == 0) {
    .col-#{$class}-push-0 {
      left: auto;
    }
  }
  @if ($type == pull) and ($index > 0) {
    .col-#{$class}-pull-#{$index} {
      right: auto;
    }
  }
  @if ($type == pull) and ($index == 0) {
    .col-#{$class}-pull-0 {
      right: auto;
    }
  }
  @if ($type == offset) {
    .col-#{$class}-offset-#{$index} {
      margin-left: auto;
    }
  }
}

@mixin loop-grid-columns-reset($columns, $class, $type) {
  @for $i from 0 through $columns {
    @include calc-grid-column-reset($i, $class, $type);
  }
}

@mixin reset-grid($class) {
  @include reset-float-grid-columns($class);
  @include loop-grid-columns-reset($grid-columns, $class, width);
  @include loop-grid-columns-reset($grid-columns, $class, pull);
  @include loop-grid-columns-reset($grid-columns, $class, push);
  @include loop-grid-columns-reset($grid-columns, $class, offset);
}

// Apply the new definitions depending on the container size without media queries
.container-xs {
  @include reset-grid(sm);
  @include reset-grid(md);
  @include reset-grid(lg);

  @include make-grid(xs);
}

.container-sm {
  @include reset-grid(md);
  @include reset-grid(lg);

  @include make-grid(xs);
  @include make-grid(sm);
}

.container-md {
  @include reset-grid(lg);

  @include make-grid(xs);
  @include make-grid(sm);
  @include make-grid(md);
}

.container-lg {
  @include make-grid(xs);
  @include make-grid(sm);
  @include make-grid(md);
  @include make-grid(lg);
}

This extension is used/activated by simply applying the container-* class to the parent container so all the grid classes respond to the container-* size class instead of the media queries of the standard Bootstrap grid. This allows to apply the container-* classes in whichever way makes sense for the application. Most likely it will be applied via JavaScript as a result of a window.resize event handler.

The biggest limitation of this solution is that it is not working recursively which could become a problem when components are containing other components.

I'd love to hear your thoughts and get some feedback if possible. It would be awesome to get a proper solution for this in Bootstrap v4 as component development will become more and more important.

@dmiko
dmiko commented Jan 13, 2017

I totally agree with this suggestion.
It will be really useful feature.
Currently right for these purposes I am trying to modify B4 for myself replacing media queries by containter-* classes.

@jbruni
jbruni commented Jan 15, 2017

Use SamsaraJS for layout, and Bootstrap for the inner contents.

@kfenner
kfenner commented Jan 16, 2017

@jbruni Thanks for the suggestion. But Samsara looks quite complicated when all you want is just filling a layout grid with some components and behave in a responsive way (react to container size changes). Bootstrap has responsive design in its core, so why would I want to use anything on top of this? I'd think that the whole grid system with the responsive utilities is what makes Bootstrap so useful. And I'd like to see an improvement here which allows us to handle also the tiny bit more complicated cases.

@mdo
Member
mdo commented Jan 16, 2017

Cool to see, but not something we'll be implementing within the project itself I think :).

@mdo mdo closed this Jan 16, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment