responsive designweb design

How to Add a New Breakpoint in Bootstrap

Bootstrap claims to be a “mobile first” framework. However, judging from the breakpoints, it’s a mobile-only layout framework. The largest breakpoint is 1200 pixels wide. Even my 15” MacBook has much more screen estate: its screen is 1440 pixels wide. Many desktop monitors have a width of 1920 pixels, and 4k monitors are gaining popularity by the day. Obviously, the “lg” breakpoint of Bootstrap 3 is merely a toy in 2018. Bootstrap 4 adds a new breakpoint called “xl”, but in reality, it only adds a breakpoint for super-narrow screens. The largest breakpoint is still 1200 pixels wide.

Luckily, both Bootstrap 3 and Bootstrap 4 can be customized. Adding a breakpoint to the new version (BS4) is very simple. It’s a little more work in Bootstrap 3. It took me a while to collect the information from the web, so it’s high time for a compact walk-through.

Before that, let me explain why I’m unhappy with the default breakpoints. If you’re eager to see the source code first, just scroll down.

Excursion: what is a breakpoint, and what are sensible breakpoints?

If you’re reading this article, you’re almost certainly familiar with the concept of layout breakpoints. This is a clever concept allowing web designers and programmers to make the most of the available screen estate. If the application is shown on a wide screen, it shows everything at once. If the screen is small, the application shows less content. Information that’s less important is hidden. Input fields are stacked on top of each other, as opposed to showing them side-by-side on large screens.

Breakpoints are (slightly artificial) screen sizes you can use to define different layouts. Basically, these breakpoints are t-shirt sizes. In Bootstrap 4, you can use the “xl” breakpoint to define the layout on screens wider than 1200 pixels. Similarly, you can use the “lg” breakpoint for screens wider than 992 pixels. “md” is wider than 768 pixels, and “sm” is wider than 576 pixels. There’s also the “xs” breakpoint, which basically applies to every screen.

Bootstrap 3 is similar. There’s no 576 pixels breakpoint, so the remaining breakpoints are pushed one t-shirt size down. But other than that, there’s not much of a difference.

Here’s the catch: these breakpoints don’t match any device I’m using in real life. I’ve already mentioned desktop monitors and laptops. Most users work with these machines, but they are ill-supported by Bootstrap.

Excursion: Material Design

Remains the question what sensible breakpoints are. Material Design gives a hint: it uses breakpoints at 480, 600, 840, 960, 1280, 1440, and 1600 pixels. I’d also add popular screen sizes like 1920 pixels, 2560 pixels, and the 4K monitors (3840 pixels).

At the end of the day, it depends on the requirements of your application. This article describes how to customize Bootstrap to your needs.

Level 1: modifying the existing breakpoints

Let’s start with something simple. Both versions of Bootstrap provide a file called variables.less (BS3) and _variables.scss (BS4) to make modifying Bootstrap a breeze. So all you have to do is to clone the Bootstrap repository from GitHub, modify the variables.* file, and to compile Bootstrap yourself. There’s even a demo at Codeply showing you how to modify the “xl” breakpoint:

/* taken from https://stackoverflow.com/a/47753600/3466464 */
@import "bootstrap/functions";
@import "bootstrap/variables";

$grid-breakpoints: (
  xs: 0,
  sm: 600px,
  md: 800px,
  lg: 1000px,
  xl: 1280px  // <-- modified!
);

$container-max-widths: (
  sm: 600px,
  md: 800px,
  lg: 1000px,
  xl: 1220px  // <-- modified!
);

@import "bootstrap";

Level 2: add a new breakpoint with Bootstrap 4

If you need to support everything from a budget Android smartphone to a 4K desktop monitor, modifying the existing breakpoints probably gets you nowhere. You need to add one or more breakpoints. That’s pretty simple with Bootstrap 4:

/* example taken from https://stackoverflow.com/a/48976550/3466464 */
/* import what we need to override */
@import "bootstrap/functions";
@import "bootstrap/variables";

/* set the overriding variables */
$grid-breakpoints: (
  xxxs: 0,
  xxs: 320px,
  xs: 568px,
  sm: 667px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1440px,
  xxxl: 1600px
)
$container-max-widths: (
  xxxs: 0,
  xxs: 320px,
  xs: 568px,
  sm: 667px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1440px,
  xxxl: 1600px
);

/* override the !default vars with the values we set above */
@import "bootstrap";

If you’re using a current version of Angular, you can easily integrate generating Bootstrap with the build process. Without Angular, read the build instructions at the Bootstrap documentation.

Bonus level: add a new breakpoint with Bootstrap 3

Before continuing, let me spend some kudos. This section is a refined version of an article written by Bryan Elkus. Thanks, Bryan!

Bootstrap 3 is less flexible than Bootstrap 4, so we need to modify several files instead of a single one. I didn’t want to modify any of the standard files of Bootstrap in BootsFaces 1.2, so I added a couple of new files and included them from the core.less file. That makes updating to the next version of Bootstrap 3.x easier.

By the way, there’s a lot of source code below. If you want to follow this walk-through, you don’t have to copy everything from this blog. You can also have a look at the corresponding GitHub commit to BootsFaces. You only have to take into account that BootsFaces already uses a customized version of bootstrap.less (called bs-core.less).

It all starts with a modified bootstrap.less file. This is a file which basically consists of a long list of import statements. I’ve added a few additional lines to this file. The idea is that this file probably never changes, so it’s a good idea to modify this file. Future versions of Bootstrap won’t affect this file, so our modifications aren’t lost. All the other files are much more likely to change. So I didn’t modify them directly but added a companion file. These companion files are the “extra-” files below:

// Core variables and mixins
@import "variables.less";
@import "mixins.less";
@import "mixins/extra-grid.less";  // <-- new!

// Extra Variables (override)
@import "extra-variables.less";  // <-- new!

// Reset and dependencies
@import "normalize.less";
@import "print.less";

// Load fonts from this directory.
@icon-font-path: "../../../fonts/";
@import "glyphicons.less";

// Core CSS
@import "scaffolding.less";
@import "type.less";
@import "code.less";
@import "grid.less";
@import "extra-grid.less";  // <-- new!
@import "tables.less";
@import "forms.less";
@import "buttons.less";

// Components
@import "component-animations.less";
@import "dropdowns.less";
@import "button-groups.less";
@import "input-groups.less";
@import "navs.less";
@import "navbar.less";
@import "breadcrumbs.less";
@import "pagination.less";
@import "pager.less";
@import "labels.less";
@import "badges.less";
@import "jumbotron.less";
@import "thumbnails.less";
@import "alerts.less";
@import "progress-bars.less";
@import "media.less";
@import "list-group.less";
@import "panels.less";
@import "responsive-embed.less";
@import "wells.less";
@import "close.less";

// Components w/ JavaScript
@import "modals.less";
@import "tooltip.less";
@import "popovers.less";
@import "carousel.less";

// Utility classes
@import "utilities.less";
@import "responsive-utilities.less";
@import "extra-responsive-utilities.less"; // <-- new!

@import "customizations.less";
@import "theme-customizations.less";

The new breakpoint “xl” is defined in the extra-variables.less like so:

// Large screen / wide desktop
//** Deprecated `@screen-lg` as of v3.0.1
@screen-xl: 1400px;
@screen-xl-min: @screen-xl;
//** Deprecated `@screen-lg-desktop` as of v3.0.1
@screen-xl-desktop: @screen-xl-min;

@screen-lg-max: (@screen-xl-min - 1);

@container-xlarge-desktop: (1400px + @grid-gutter-width);
//** For `@screen-xl-min` and up.
@container-xl: @container-xlarge-desktop;

The next file defines functions to generate the grid classes. Basically, we have to add the new breakpoints. Create a new file called extra-grid-framework.less:

// Framework grid generation
//
// Used only by Bootstrap to generate the correct number of grid classes given
// any value of `@grid-columns`.

.make-grid-columns() {
  // Common styles for all sizes of grid columns, widths 1-12
  .col(@index) {
    // initial
    @item: ~'.col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}, .col-xl-@{index}';
    .col((@index + 1), @item);
  }
  .col(@index, @list) when (@index =< @grid-columns) {
    // general; "=<" isn't a typo
    @item: ~'.col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}, .col-xl-@{index}';
    .col((@index + 1), ~'@{list}, @{item}');
  }
}

The function calls to actually generate the grid classes are defined in grid.less. So we add the new breakpoint in the new file extra-grid.less:

//
// Set the container width, and override it for fixed navbars in media queries.

.container {
  .container-fixed();
  @media (min-width: @screen-xl-min) {
    width: @container-xl;
  }
}

// xLarge grid
//
// Columns, offsets, pushes, and pulls for the xlarge desktop device range.

@media (min-width: @screen-xl-min) {
  .make-grid(xl);
}

A part of the grid definition is defined in a second file called grid.less (in the mixins folder). So we also have to add an extra-mixins-grid.less:

// Generate the xlarge columns
.make-xl-column(@columns; @gutter: @grid-gutter-width) {
  position: relative;
  min-height: 1px;
  padding-left: (@gutter / 2);
  padding-right: (@gutter / 2);

  @media (min-width: @screen-xl-min) {
    float: left;
    width: percentage((@columns / @grid-columns));
  }
}
.make-xl-column-offset(@columns) {
  @media (min-width: @screen-xl-min) {
    margin-left: percentage((@columns / @grid-columns));
  }
}
.make-xl-column-push(@columns) {
  @media (min-width: @screen-xl-min) {
    left: percentage((@columns / @grid-columns));
  }
}
.make-xl-column-pull(@columns) {
  @media (min-width: @screen-xl-min) {
    right: percentage((@columns / @grid-columns));
  }
}

The CSS classes for showing and hiding screen elements depending on the screen size is defined in the reponsive-utilities.less class. So we add the file extra-responsive-utilities.less:

// Visibility utilities
.visible-xl {
  .responsive-invisibility();
}

.visible-xl-block,
.visible-xl-inline,
.visible-xl-inline-block {
  display: none !important;
}

.visible-lg {
  @media (min-width: @screen-lg-min) and (max-width: @screen-lg-max) {
    .responsive-visibility();
  }
}
.visible-lg-block {
  @media (min-width: @screen-lg-min) and (max-width: @screen-lg-max) {
    display: block !important;
  }
}
.visible-lg-inline {
  @media (min-width: @screen-lg-min) and (max-width: @screen-lg-max) {
    display: inline !important;
  }
}
.visible-lg-inline-block {
  @media (min-width: @screen-lg-min) and (max-width: @screen-lg-max) {
    display: inline-block !important;
  }
}

.visible-xl {
  @media (min-width: @screen-xl-min) {
    .responsive-visibility();
  }
}
.visible-xl-block {
  @media (min-width: @screen-xl-min) {
    display: block !important;
  }
}
.visible-xl-inline {
  @media (min-width: @screen-xl-min) {
    display: inline !important;
  }
}
.visible-xl-inline-block {
  @media (min-width: @screen-xl-min) {
    display: inline-block !important;
  }
}

.hidden-xl {
  @media (min-width: @screen-xl-min) {
    .responsive-invisibility();
  }
}

We’re almost there! The last file to add is the variable definition of the new breakpoint. In other words, the size of the breakpoint. We define it in the new file extra-variables.less:

// Large screen / wide desktop
//** Deprecated `@screen-lg` as of v3.0.1
@screen-xl: 1400px;
@screen-xl-min: @screen-xl;
//** Deprecated `@screen-lg-desktop` as of v3.0.1
@screen-xl-desktop: @screen-xl-min;

@screen-lg-max: (@screen-xl-min - 1);

@container-xlarge-desktop: (1400px + @grid-gutter-width);
//** For `@screen-xl-min` and up.
@container-xl: @container-xlarge-desktop;

Now you should be able to generate your custom version of Bootstrap 3 by running grunt dist, as described in the documentation of Bootstrap.

Wrapping it up

Bootstrap 4 has been written with a lot of customizing in mind, so adding custom breakpoints is not a big deal. However, it’s also possible with Bootstrap 3.3 with slightly more work.

BTW, I’d like to hear from you. Did you ever feel the need to modify the breakpoints? Which breakpoints did you define?