diff --git a/scss/_forms.scss b/scss/_forms.scss index 68f13d2c16..964ae402a8 100644 --- a/scss/_forms.scss +++ b/scss/_forms.scss @@ -541,14 +541,14 @@ input[type="checkbox"] { // Quick utility class for applying `.input-lg` and `.input-sm` styles to the // inputs and labels within a `.form-group`. .form-group-lg { - @media (min-width: $screen-sm-min) { + @include media-sm { .control-label { padding-top: $padding-lg-vertical; } } } .form-group-sm { - @media (min-width: $screen-sm-min) { + @include media-sm { .control-label { padding-top: ($padding-sm-vertical + .1); } diff --git a/scss/_grid.scss b/scss/_grid.scss index 6374d77def..1129cff6d0 100644 --- a/scss/_grid.scss +++ b/scss/_grid.scss @@ -10,14 +10,11 @@ .container { @include make-container(); - @media (min-width: $screen-sm-min) { - max-width: $container-sm; - } - @media (min-width: $screen-md-min) { - max-width: $container-md; - } - @media (min-width: $screen-lg-min) { - max-width: $container-lg; + // For each breakpoint, define the maximum width of the container in a media query + @each $breakpoint, $container-max-width in $container-max-widths { + @include media-breakpoint-min($breakpoint) { + max-width: $container-max-width; + } } } @@ -47,47 +44,3 @@ @include make-grid-columns(); - -// Extra small grid -// -// Columns, offsets, pushes, and pulls for extra small devices like -// smartphones. - -@include make-grid(xs); - - -// Small grid -// -// Columns, offsets, pushes, and pulls for the small device range, from phones -// to tablets. - -@include media-sm { - @include make-grid(sm); -} - - -// Medium grid -// -// Columns, offsets, pushes, and pulls for the desktop device range. - -@include media-md { - @include make-grid(md); -} - - -// Large grid -// -// Columns, offsets, pushes, and pulls for the large desktop device range. - -@include media-lg { - @include make-grid(lg); -} - - -// Large grid -// -// Columns, offsets, pushes, and pulls for the large desktop device range. - -@include media-lg { - @include make-grid(xl); -} diff --git a/scss/_mixins.scss b/scss/_mixins.scss index 88ebc3f54f..801b5c7e99 100644 --- a/scss/_mixins.scss +++ b/scss/_mixins.scss @@ -24,6 +24,7 @@ } // Utilities +@import "mixins/breakpoints"; @import "mixins/media-queries"; @import "mixins/hide-text"; @import "mixins/image"; diff --git a/scss/_modal.scss b/scss/_modal.scss index 8fb7d201dd..2566c3ef2d 100644 --- a/scss/_modal.scss +++ b/scss/_modal.scss @@ -126,7 +126,7 @@ } // Scale up the modal -@media (min-width: $screen-sm-min) { +@include media-sm { // Automatically set modal's width for larger viewports .modal-dialog { width: $modal-md; @@ -140,6 +140,6 @@ .modal-sm { width: $modal-sm; } } -@media (min-width: $screen-md-min) { +@include media-md { .modal-lg { width: $modal-lg; } } diff --git a/scss/_variables.scss b/scss/_variables.scss index 2427113143..4b515d3a4c 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -272,29 +272,22 @@ $zindex-modal: 1040 !default; // //## Define the minimum and maximum dimensions at which your layout will change, adapting to different screen sizes. -// Extra large screen / wide desktop -$screen-xl-min: 75em !default; - -// Large screen / desktop -$screen-lg-max: ($screen-xl-min - .1) !default; -$screen-lg-min: 62em !default; - -// Medium screen / tablet -$screen-md-max: ($screen-lg-min - .1) !default; -$screen-md-min: 48em !default; - -// Small screen / phone -$screen-sm-max: ($screen-md-min - .1) !default; -$screen-sm-min: 34em !default; - -// Extra small screen / phone -$screen-xs-max: ($screen-sm-min - .1) !default; - - //== Grid system // //## Define your custom responsive grid. -$grid-breakpoints: (xs sm md lg xl); +$grid-breakpoints: ( + // Extra small screen / phone + xs: 0, + // Small screen / phone + sm: 34em, + // Medium screen / tablet + md: 48em, + // Large screen / desktop + lg: 62em, + // Extra large screen / wide desktop + xl: 75em +) !default; + //** Number of columns in the grid. $grid-columns: 12 !default; //** Padding between columns. Gets divided in half for the left and right. @@ -305,17 +298,12 @@ $grid-gutter-width: 1.5rem !default; // //## Define the maximum width of `.container` for different screen sizes. -//** For `$screen-xs-min` and up. -$container-sm: 34em !default; // 480 - -//** For `$screen-sm-min` and up. -$container-md: 45rem !default; // 720 - -//** For `$screen-md-min` and up. -$container-lg: 60rem !default; // 960 - -//** For `$screen-lg-min` and up. -$container-xl: 72.25rem !default; // 1140 +$container-max-widths: ( + sm: 34rem, // 480 + md: 45rem, // 720 + lg: 60rem, // 960 + xl: 72.25rem // 1140 +) !default; //== Navbar diff --git a/scss/mixins/_breakpoints.scss b/scss/mixins/_breakpoints.scss new file mode 100644 index 0000000000..71a15cd043 --- /dev/null +++ b/scss/mixins/_breakpoints.scss @@ -0,0 +1,85 @@ +// Breakpoint viewport sizes and media queries. +// +// Breakpoints are defined as a map of (name: minimum width), order from small to large: +// +// (xs: 0, sm: 34rem, md: 45rem) +// +// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. + +// Name of the next breakpoint, or null for the last breakpoint. +// +// >> breakpoint-next(sm) +// md +// >> breakpoint-next(sm, $breakpoints: (xs: 0, sm: 34rem, md: 45rem)) +// md +// >> breakpoint-next(sm, $breakpoint-names: (xs sm md)) +// md +@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { + $n: index($breakpoint-names, $name); + @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); +} + +// Minimum breakpoint width. Null for the smallest (first) breakpoint. +// +// >> breakpoint-min(sm, (xs: 0, sm: 34rem, md: 45rem)) +// 34rem +@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: map-get($breakpoints, $name); + @return if($min != 0, $min, null); +} + +// Maximum breakpoint width. Null for the largest (last) breakpoint. +// The maximum value is calculated as the minimum of the next one less 0.1. +// +// >> breakpoint-max(sm, (xs: 0, sm: 34rem, md: 45rem)) +// 44.9rem +@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $next: breakpoint-next($name, $breakpoints); + @return if($next, breakpoint-min($next, $breakpoints) - 0.1, null); +} + +// Media of at least the minimum breakpoint width. No query for the smallest breakpoint. +@mixin media-breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + @if $min { + @media (min-width: $min) { + @content; + } + } @else { + @content; + } +} + +// Media of at most the maximum breakpoint width. No query for the largest breakpoint. +@mixin media-breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $max: breakpoint-max($name, $breakpoints); + @if $max { + @media (max-width: $max) { + @content; + } + } @else { + @content; + } +} + +// Media between the breakpoint's minimum and maximum widths. +// No minimum for the smallest breakpoint, and no maximum for the largest one. +@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) { + // Nested media query combination does not work in libsass yet + // https://github.com/sass/libsass/issues/185 + // Work around until the issue is resolved: + $min: breakpoint-min($name, $breakpoints); + $max: breakpoint-max($name, $breakpoints); + @if $min and $max { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else { + // One of min or max is a no-op, so this branch is not affected by libsass#185 + @include media-breakpoint-min($name, $breakpoints) { + @include media-breakpoint-max($name, $breakpoints) { + @content; + } + } + } +} diff --git a/scss/mixins/_grid-framework.scss b/scss/mixins/_grid-framework.scss index 3eecbae8b2..0d346db57d 100644 --- a/scss/mixins/_grid-framework.scss +++ b/scss/mixins/_grid-framework.scss @@ -3,69 +3,40 @@ // Used only by Bootstrap to generate the correct number of grid classes given // any value of `$grid-columns`. -// Common properties for all breakpoints -@mixin make-grid-columns($columns: $grid-columns, $breakpoints: $grid-breakpoints) { +@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) { + // Common properties for all breakpoints %grid-column { position: relative; // Prevent columns from collapsing when empty min-height: 1px; // Inner gutter via padding - padding-left: ($grid-gutter-width / 2); - padding-right: ($grid-gutter-width / 2); + padding-left: ($gutter / 2); + padding-right: ($gutter / 2); } - @for $i from 1 through $columns { - @each $breakpoint in $breakpoints { + @each $breakpoint in map-keys($breakpoints) { + @for $i from 1 through $columns { .col-#{$breakpoint}-#{$i} { @extend %grid-column; } } - } -} - -// Breakpoint-specific properties -@mixin make-grid($breakpoint, $columns: $grid-columns) { - // Work around cross-media @extend (https://github.com/sass/sass/issues/1050) - %grid-column-float-#{$breakpoint} { - float: left; - } - @for $i from 1 through $columns { - .col-#{$breakpoint}-#{$i} { - @extend %grid-column-float-#{$breakpoint}; - @include grid-column-width($i, $columns); - } - } - @each $modifier in (pull, push, offset) { - @for $i from 0 through $columns { - .col-#{$breakpoint}-#{$modifier}-#{$i} { - @include grid-column-modifier($modifier, $i, $columns) + @include media-breakpoint-min($breakpoint) { + // Work around cross-media @extend (https://github.com/sass/sass/issues/1050) + %grid-column-float-#{$breakpoint} { + float: left; + } + @for $i from 1 through $columns { + .col-#{$breakpoint}-#{$i} { + @extend %grid-column-float-#{$breakpoint}; + @include make-col-span($i, $columns); + } + } + @each $modifier in (pull, push, offset) { + @for $i from 0 through $columns { + .col-#{$breakpoint}-#{$modifier}-#{$i} { + @include make-col-modifier($modifier, $i, $columns) + } + } } } } } - -@mixin grid-column-width($index, $columns) { - width: percentage($index / $columns); -} - -@mixin grid-column-push($index, $columns) { - left: if($index > 0, percentage($index / $columns), auto); -} - -@mixin grid-column-pull($index, $columns) { - right: if($index > 0, percentage($index / $columns), auto); -} - -@mixin grid-column-offset($index, $columns) { - margin-left: percentage($index / $columns); -} - -// Work around the lack of dynamic mixin @include support (https://github.com/sass/sass/issues/626) -@mixin grid-column-modifier($type, $index, $columns) { - @if $type == push { - @include grid-column-push($index, $columns); - } @else if $type == pull { - @include grid-column-pull($index, $columns); - } @else if $type == offset { - @include grid-column-offset($index, $columns); - } -} diff --git a/scss/mixins/_grid.scss b/scss/mixins/_grid.scss index aceaeeb4c4..29af269aac 100644 --- a/scss/mixins/_grid.scss +++ b/scss/mixins/_grid.scss @@ -24,18 +24,29 @@ padding-right: ($gutter / 2); } -@mixin make-col-span($columns) { - width: percentage(($columns / $grid-columns)); +@mixin make-col-span($size, $columns: $grid-columns) { + width: percentage($size / $columns); } -@mixin make-col-offset($columns) { - margin-left: percentage(($columns / $grid-columns)); +@mixin make-col-offset($size, $columns: $grid-columns) { + margin-left: percentage($size / $columns); } -@mixin make-col-push($columns) { - left: percentage(($columns / $grid-columns)); +@mixin make-col-push($size, $columns: $grid-columns) { + left: if($size > 0, percentage($size / $columns), auto); } -@mixin make-col-pull($columns) { - right: percentage(($columns / $grid-columns)); +@mixin make-col-pull($size, $columns: $grid-columns) { + right: if($size > 0, percentage($size / $columns), auto); +} + +@mixin make-col-modifier($type, $size, $columns) { + // Work around the lack of dynamic mixin @include support (https://github.com/sass/sass/issues/626) + @if $type == push { + @include make-col-push($size, $columns); + } @else if $type == pull { + @include make-col-pull($size, $columns); + } @else if $type == offset { + @include make-col-offset($size, $columns); + } } diff --git a/scss/mixins/_media-queries.scss b/scss/mixins/_media-queries.scss index b4e16ed888..28130d2e7e 100644 --- a/scss/mixins/_media-queries.scss +++ b/scss/mixins/_media-queries.scss @@ -1,25 +1,25 @@ -// Media query mixins +// Media query mixins for default breakpoints @mixin media-xs() { - @media (max-width: $screen-xs-max) { @content } + @include media-breakpoint-max(xs) { @content } } @mixin media-sm() { - @media (min-width: $screen-sm-min) { @content } + @include media-breakpoint-min(sm) { @content } } @mixin media-sm-max() { - @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { @content } + @include media-breakpoint-only(sm) { @content } } @mixin media-md() { - @media (min-width: $screen-md-min) { @content } + @include media-breakpoint-min(md) { @content } } @mixin media-md-max() { - @media (min-width: $screen-md-min) and (max-width: $screen-md-max) { @content } + @include media-breakpoint-only(md) { @content } } @mixin media-lg() { - @media (min-width: $screen-lg-min) { @content } + @include media-breakpoint-min(lg) { @content } }