Sed posuere consectetur est at lobortis. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.
@@ -222,12 +222,12 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
template |
string |
- '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' |
+ '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' |
Base HTML to use when creating the popover.
The popover's title will be injected into the .popover-title .
The popover's content will be injected into the .popover-content .
- .arrow will become the popover's arrow.
+ .popover-arrow will become the popover's arrow.
The outermost wrapper element should have the .popover class.
|
diff --git a/grunt/bs-sass-compile/libsass.js b/grunt/bs-sass-compile/libsass.js
new file mode 100644
index 0000000000..e3d13a989f
--- /dev/null
+++ b/grunt/bs-sass-compile/libsass.js
@@ -0,0 +1,26 @@
+// Compile Bootstrap with [libsass][1] using [grunt-sass][2]
+// [1]: https://github.com/sass/libsass
+// [2]: https://github.com/sindresorhus/grunt-sass
+module.exports = function configureLibsass(grunt) {
+ grunt.config.merge({
+ sass: {
+ options: {
+ includePaths: ['scss'],
+ precision: 6,
+ sourceComments: false,
+ sourceMap: true
+ },
+ core: {
+ files: {
+ 'dist/css/<%= pkg.name %>.css': 'scss/<%= pkg.name %>.scss'
+ }
+ },
+ docs: {
+ files: {
+ 'docs/assets/css/docs.min.css': 'docs/assets/scss/docs.scss'
+ }
+ }
+ }
+ });
+ grunt.loadNpmTasks('grunt-sass');
+};
diff --git a/grunt/bs-sass-compile/sass.js b/grunt/bs-sass-compile/sass.js
new file mode 100644
index 0000000000..d7743515d8
--- /dev/null
+++ b/grunt/bs-sass-compile/sass.js
@@ -0,0 +1,30 @@
+// Compile Bootstrap with [Ruby Sass][1] using [grunt-contrib-sass][2]
+// [1]: https://github.com/sass/sass
+// [2]: https://github.com/gruntjs/grunt-contrib-sass
+module.exports = function configureRubySass(grunt) {
+ var options = {
+ loadPath: ['scss'],
+ precision: 6,
+ sourcemap: 'auto',
+ style: 'expanded',
+ trace: true,
+ bundleExec: true
+ };
+ grunt.config.merge({
+ sass: {
+ core: {
+ options: options,
+ files: {
+ 'dist/css/<%= pkg.name %>.css': 'scss/<%= pkg.name %>.scss'
+ }
+ },
+ docs: {
+ options: options,
+ files: {
+ 'docs/assets/css/docs.min.css': 'docs/assets/scss/docs.scss'
+ }
+ }
+ }
+ });
+ grunt.loadNpmTasks('grunt-contrib-sass');
+};
diff --git a/js/.jscsrc b/js/.jscsrc
index 9612c16833..ac1d73f55e 100644
--- a/js/.jscsrc
+++ b/js/.jscsrc
@@ -22,6 +22,7 @@
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
"requireSpaceAfterLineComment": true,
"requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", "<", ">=", "<="],
+ "requireSpaceBetweenArguments": true,
"requireSpacesInAnonymousFunctionExpression": { "beforeOpeningCurlyBrace": true, "beforeOpeningRoundBrace": true },
"requireSpacesInConditionalExpression": true,
"requireSpacesInFunctionDeclaration": { "beforeOpeningCurlyBrace": true },
diff --git a/js/popover.js b/js/popover.js
index db272bdee4..085584fe87 100644
--- a/js/popover.js
+++ b/js/popover.js
@@ -25,7 +25,7 @@
placement: 'right',
trigger: 'click',
content: '',
- template: '
'
+ template: '
'
})
@@ -50,7 +50,7 @@
this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
](content)
- $tip.removeClass('fade top bottom left right in')
+ $tip.removeClass('fade popover-top popover-bottom popover-left popover-right in')
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
// this manually by checking the contents.
@@ -72,7 +72,7 @@
}
Popover.prototype.arrow = function () {
- return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
+ return (this.$arrow = this.$arrow || this.tip().find('.popover-arrow'))
}
Popover.prototype.tip = function () {
diff --git a/js/tests/unit/popover.js b/js/tests/unit/popover.js
index 466ebace26..8f59d3483a 100644
--- a/js/tests/unit/popover.js
+++ b/js/tests/unit/popover.js
@@ -141,7 +141,7 @@ $(function () {
.bootstrapPopover({
title: 'Test',
content: 'Test',
- template: '
'
+ template: '
'
})
$popover.bootstrapPopover('show')
diff --git a/js/tests/unit/tooltip.js b/js/tests/unit/tooltip.js
index eb578c22af..6232ccdcb3 100644
--- a/js/tests/unit/tooltip.js
+++ b/js/tests/unit/tooltip.js
@@ -85,7 +85,7 @@ $(function () {
.bootstrapTooltip({ placement: 'bottom' })
$tooltip.bootstrapTooltip('show')
- ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied')
+ ok($('.tooltip').is('.fade.tooltip-bottom.in'), 'has correct classes applied')
$tooltip.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'tooltip removed')
@@ -300,8 +300,8 @@ $(function () {
test('should add position class before positioning so that position-specific styles are taken into account', function () {
var styles = ''
var $styles = $(styles).appendTo('head')
@@ -384,7 +384,7 @@ $(function () {
.bootstrapTooltip({ placement: 'auto' })
$topTooltip.bootstrapTooltip('show')
- ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned to bottom')
+ ok($('.tooltip').is('.tooltip-bottom'), 'top positioned tooltip is dynamically positioned to bottom')
$topTooltip.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'top positioned tooltip removed from dom')
@@ -394,7 +394,7 @@ $(function () {
.bootstrapTooltip({ placement: 'right auto' })
$rightTooltip.bootstrapTooltip('show')
- ok($('.tooltip').is('.left'), 'right positioned tooltip is dynamically positioned left')
+ ok($('.tooltip').is('.tooltip-left'), 'right positioned tooltip is dynamically positioned left')
$rightTooltip.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'right positioned tooltip removed from dom')
@@ -404,7 +404,7 @@ $(function () {
.bootstrapTooltip({ placement: 'auto left' })
$leftTooltip.bootstrapTooltip('show')
- ok($('.tooltip').is('.right'), 'left positioned tooltip is dynamically positioned right')
+ ok($('.tooltip').is('.tooltip-right'), 'left positioned tooltip is dynamically positioned right')
$leftTooltip.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'left positioned tooltip removed from dom')
@@ -430,7 +430,7 @@ $(function () {
})
$target.bootstrapTooltip('show')
- ok($('.tooltip').is('.top'), 'top positioned tooltip is dynamically positioned to top')
+ ok($('.tooltip').is('.tooltip-top'), 'top positioned tooltip is dynamically positioned to top')
$target.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'tooltip removed from dom')
@@ -455,7 +455,7 @@ $(function () {
})
$target.bootstrapTooltip('show')
- ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned to bottom')
+ ok($('.tooltip').is('.tooltip-bottom'), 'top positioned tooltip is dynamically positioned to bottom')
$target.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'tooltip removed from dom')
@@ -481,7 +481,7 @@ $(function () {
$('#scrollable-div').scrollTop(100)
$target.bootstrapTooltip('show')
- ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied')
+ ok($('.tooltip').is('.fade.tooltip-top.in'), 'has correct classes applied')
$target.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'tooltip removed from dom')
@@ -507,7 +507,7 @@ $(function () {
$('#scrollable-div').scrollTop(200)
$target.bootstrapTooltip('show')
- ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied')
+ ok($('.tooltip').is('.fade.tooltip-bottom.in'), 'has correct classes applied')
$target.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'tooltip removed from dom')
@@ -537,7 +537,7 @@ $(function () {
$('#scrollable-div').scrollTop(200)
$target.bootstrapTooltip('show')
- ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied')
+ ok($('.tooltip').is('.fade.tooltip-bottom.in'), 'has correct classes applied')
$target.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'tooltip removed from dom')
@@ -563,7 +563,7 @@ $(function () {
$('#scrollable-div').scrollTop(400)
$target.bootstrapTooltip('show')
- ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied')
+ ok($('.tooltip').is('.fade.tooltip-top.in'), 'has correct classes applied')
$target.bootstrapTooltip('hide')
equal($('.tooltip').length, 0, 'tooltip removed from dom')
diff --git a/js/tooltip.js b/js/tooltip.js
index bd376f7727..9d3074cc04 100644
--- a/js/tooltip.js
+++ b/js/tooltip.js
@@ -177,7 +177,7 @@
$tip
.detach()
.css({ top: 0, left: 0, display: 'block' })
- .addClass(placement)
+ .addClass(this.type + '-' + placement)
.data('bs.' + this.type, this)
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
@@ -187,7 +187,7 @@
var actualHeight = $tip[0].offsetHeight
if (autoPlace) {
- var orgPlacement = placement
+ var origPlacement = placement
var $container = this.options.container ? $(this.options.container) : this.$element.parent()
var containerDim = this.getPosition($container)
@@ -198,8 +198,8 @@
placement
$tip
- .removeClass(orgPlacement)
- .addClass(placement)
+ .removeClass(this.type + '-' + origPlacement)
+ .addClass(this.type + '-' + placement)
}
var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
@@ -283,7 +283,7 @@
var title = this.getTitle()
$tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
- $tip.removeClass('fade in top bottom left right')
+ $tip.removeClass('fade in tooltip-top tooltip-bottom tooltip-left tooltip-right')
}
Tooltip.prototype.hide = function (callback) {
diff --git a/package.json b/package.json
index 049eec9999..ef03659e8d 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
},
"devDependencies": {
"btoa": "~1.1.2",
- "glob": "~4.2.1",
+ "glob": "~4.3.1",
"grunt": "~0.4.5",
"grunt-autoprefixer": "~2.0.0",
"grunt-banner": "~0.2.3",
@@ -42,23 +42,24 @@
"grunt-contrib-copy": "~0.7.0",
"grunt-contrib-csslint": "~0.3.1",
"grunt-contrib-cssmin": "~0.10.0",
- "grunt-contrib-jade": "~0.13.0",
+ "grunt-contrib-jade": "~0.14.0",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-qunit": "~0.5.2",
- "grunt-contrib-uglify": "~0.6.0",
+ "grunt-contrib-sass": "^0.8.1",
+ "grunt-contrib-uglify": "~0.7.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-csscomb": "~3.0.0",
"grunt-exec": "~0.4.6",
"grunt-html-validation": "~0.1.18",
"grunt-jekyll": "~0.4.2",
- "grunt-jscs": "~1.0.0",
+ "grunt-jscs": "~1.1.0",
"grunt-sass": "~0.17.0",
- "grunt-saucelabs": "~8.3.3",
+ "grunt-saucelabs": "~8.4.0",
"grunt-scss-lint": "^0.3.4",
"grunt-sed": "~0.1.1",
- "load-grunt-tasks": "~1.0.0",
- "npm-shrinkwrap": "5.0.0",
- "remarkable": "~1.4.2",
+ "load-grunt-tasks": "~2.0.0",
+ "npm-shrinkwrap": "^200.0.0",
+ "remarkable": "~1.6.0",
"time-grunt": "~1.0.0"
},
"engines": {
diff --git a/scss/_alert.scss b/scss/_alert.scss
index 685ca314b1..8ec7d06628 100644
--- a/scss/_alert.scss
+++ b/scss/_alert.scss
@@ -12,17 +12,6 @@
border: 1px solid transparent;
@include border-radius($alert-border-radius);
- // Headings for larger alerts
- h4 {
- margin-top: 0;
- // Specified for the h4 to prevent conflicts of changing $headings-color
- color: inherit;
- }
- // Provide class for links that match alerts
- .alert-link {
- font-weight: $alert-link-font-weight;
- }
-
// Improve alignment and spacing of inner content
> p,
> ul {
@@ -33,6 +22,18 @@
}
}
+// Headings for larger alerts
+.alert-heading {
+ margin-top: 0;
+ // Specified to prevent conflicts of changing $headings-color
+ color: inherit;
+}
+
+// Provide class for links that match alerts
+.alert-link {
+ font-weight: $alert-link-font-weight;
+}
+
// Dismissible alerts
//
// Expand the right padding and account for the close button's positioning.
diff --git a/scss/_forms.scss b/scss/_forms.scss
index 67a4f80203..2d9867d32b 100644
--- a/scss/_forms.scss
+++ b/scss/_forms.scss
@@ -540,14 +540,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 d9f0e7a4b3..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";
@@ -57,3 +58,4 @@
// @import "mixins/navbar-align";
@import "mixins/grid-framework";
@import "mixins/grid";
+@import "mixins/pulls";
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/_navbar.scss b/scss/_navbar.scss
index d4dcb673f0..b163dad9cd 100644
--- a/scss/_navbar.scss
+++ b/scss/_navbar.scss
@@ -199,10 +199,10 @@
@include media-sm {
.navbar-left {
- @extend .pull-left;
+ @include pull-left();
}
.navbar-right {
- @extend .pull-right;
+ @include pull-right();
margin-right: -$navbar-padding-horizontal;
~ .navbar-right {
diff --git a/scss/_popover.scss b/scss/_popover.scss
index 63928a4fce..a614518c7f 100644
--- a/scss/_popover.scss
+++ b/scss/_popover.scss
@@ -24,14 +24,14 @@
border: 1px solid $popover-border-color;
@include border-radius($border-radius-lg);
@include box-shadow(0 5px 10px rgba(0,0,0,.2));
-
- // Offset the popover to account for the popover arrow
- &.top { margin-top: -$popover-arrow-width; }
- &.right { margin-left: $popover-arrow-width; }
- &.bottom { margin-top: $popover-arrow-width; }
- &.left { margin-left: -$popover-arrow-width; }
}
+// Offset the popover to account for the popover arrow
+.popover-top { margin-top: -$popover-arrow-width; }
+.popover-right { margin-left: $popover-arrow-width; }
+.popover-bottom { margin-top: $popover-arrow-width; }
+.popover-left { margin-left: -$popover-arrow-width; }
+
.popover-title {
padding: 8px 14px;
margin: 0; // reset heading margin
@@ -47,9 +47,9 @@
// Arrows
//
-// .arrow is outer, .arrow:after is inner
+// .popover-arrow is outer, .popover-arrow:after is inner
-.popover > .arrow {
+.popover-arrow {
&,
&:after {
position: absolute;
@@ -60,70 +60,68 @@
border-style: solid;
}
}
-.popover > .arrow {
+.popover-arrow {
border-width: $popover-arrow-outer-width;
}
-.popover > .arrow:after {
+.popover-arrow:after {
content: "";
border-width: $popover-arrow-width;
}
-.popover {
- &.top > .arrow {
- bottom: -$popover-arrow-outer-width;
- left: 50%;
- margin-left: -$popover-arrow-outer-width;
- border-top-color: $popover-arrow-outer-color;
+.popover-top > .popover-arrow {
+ bottom: -$popover-arrow-outer-width;
+ left: 50%;
+ margin-left: -$popover-arrow-outer-width;
+ border-top-color: $popover-arrow-outer-color;
+ border-bottom-width: 0;
+ &:after {
+ bottom: 1px;
+ margin-left: -$popover-arrow-width;
+ content: "";
+ border-top-color: $popover-arrow-color;
border-bottom-width: 0;
- &:after {
- bottom: 1px;
- margin-left: -$popover-arrow-width;
- content: "";
- border-top-color: $popover-arrow-color;
- border-bottom-width: 0;
- }
- }
- &.right > .arrow {
- top: 50%;
- left: -$popover-arrow-outer-width;
- margin-top: -$popover-arrow-outer-width;
- border-right-color: $popover-arrow-outer-color;
- border-left-width: 0;
- &:after {
- bottom: -$popover-arrow-width;
- left: 1px;
- content: "";
- border-right-color: $popover-arrow-color;
- border-left-width: 0;
- }
- }
- &.bottom > .arrow {
- top: -$popover-arrow-outer-width;
- left: 50%;
- margin-left: -$popover-arrow-outer-width;
- border-top-width: 0;
- border-bottom-color: $popover-arrow-outer-color;
- &:after {
- top: 1px;
- margin-left: -$popover-arrow-width;
- content: "";
- border-top-width: 0;
- border-bottom-color: $popover-arrow-color;
- }
- }
-
- &.left > .arrow {
- top: 50%;
- right: -$popover-arrow-outer-width;
- margin-top: -$popover-arrow-outer-width;
- border-right-width: 0;
- border-left-color: $popover-arrow-outer-color;
- &:after {
- right: 1px;
- bottom: -$popover-arrow-width;
- content: "";
- border-right-width: 0;
- border-left-color: $popover-arrow-color;
- }
+ }
+}
+.popover-right > .popover-arrow {
+ top: 50%;
+ left: -$popover-arrow-outer-width;
+ margin-top: -$popover-arrow-outer-width;
+ border-right-color: $popover-arrow-outer-color;
+ border-left-width: 0;
+ &:after {
+ bottom: -$popover-arrow-width;
+ left: 1px;
+ content: "";
+ border-right-color: $popover-arrow-color;
+ border-left-width: 0;
+ }
+}
+.popover-bottom > .popover-arrow {
+ top: -$popover-arrow-outer-width;
+ left: 50%;
+ margin-left: -$popover-arrow-outer-width;
+ border-top-width: 0;
+ border-bottom-color: $popover-arrow-outer-color;
+ &:after {
+ top: 1px;
+ margin-left: -$popover-arrow-width;
+ content: "";
+ border-top-width: 0;
+ border-bottom-color: $popover-arrow-color;
+ }
+}
+
+.popover-left > .popover-arrow {
+ top: 50%;
+ right: -$popover-arrow-outer-width;
+ margin-top: -$popover-arrow-outer-width;
+ border-right-width: 0;
+ border-left-color: $popover-arrow-outer-color;
+ &:after {
+ right: 1px;
+ bottom: -$popover-arrow-width;
+ content: "";
+ border-right-width: 0;
+ border-left-color: $popover-arrow-color;
}
}
diff --git a/scss/_tooltip.scss b/scss/_tooltip.scss
index 033c19f3b0..49af2b2881 100644
--- a/scss/_tooltip.scss
+++ b/scss/_tooltip.scss
@@ -17,26 +17,23 @@
opacity: 0;
&.in { opacity: $tooltip-opacity; }
+}
- &.top {
- padding: $tooltip-arrow-width 0;
- margin-top: -3px;
- }
-
- &.right {
- padding: 0 $tooltip-arrow-width;
- margin-left: 3px;
- }
-
- &.bottom {
- padding: $tooltip-arrow-width 0;
- margin-top: 3px;
- }
-
- &.left {
- padding: 0 $tooltip-arrow-width;
- margin-left: -3px;
- }
+.tooltip-top {
+ padding: $tooltip-arrow-width 0;
+ margin-top: -3px;
+}
+.tooltip-right {
+ padding: 0 $tooltip-arrow-width;
+ margin-left: 3px;
+}
+.tooltip-bottom {
+ padding: $tooltip-arrow-width 0;
+ margin-top: 3px;
+}
+.tooltip-left {
+ padding: 0 $tooltip-arrow-width;
+ margin-left: -3px;
}
// Wrapper for the tooltip content
@@ -58,62 +55,31 @@
border-color: transparent;
border-style: solid;
}
-// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1
-.tooltip {
- &.top .tooltip-arrow {
- bottom: 0;
- left: 50%;
- margin-left: -$tooltip-arrow-width;
- border-width: $tooltip-arrow-width $tooltip-arrow-width 0;
- border-top-color: $tooltip-arrow-color;
- }
- &.top-left .tooltip-arrow {
- right: $tooltip-arrow-width;
- bottom: 0;
- margin-bottom: -$tooltip-arrow-width;
- border-width: $tooltip-arrow-width $tooltip-arrow-width 0;
- border-top-color: $tooltip-arrow-color;
- }
- &.top-right .tooltip-arrow {
- bottom: 0;
- left: $tooltip-arrow-width;
- margin-bottom: -$tooltip-arrow-width;
- border-width: $tooltip-arrow-width $tooltip-arrow-width 0;
- border-top-color: $tooltip-arrow-color;
- }
- &.right .tooltip-arrow {
- top: 50%;
- left: 0;
- margin-top: -$tooltip-arrow-width;
- border-width: $tooltip-arrow-width $tooltip-arrow-width $tooltip-arrow-width 0;
- border-right-color: $tooltip-arrow-color;
- }
- &.left .tooltip-arrow {
- top: 50%;
- right: 0;
- margin-top: -$tooltip-arrow-width;
- border-width: $tooltip-arrow-width 0 $tooltip-arrow-width $tooltip-arrow-width;
- border-left-color: $tooltip-arrow-color;
- }
- &.bottom .tooltip-arrow {
- top: 0;
- left: 50%;
- margin-left: -$tooltip-arrow-width;
- border-width: 0 $tooltip-arrow-width $tooltip-arrow-width;
- border-bottom-color: $tooltip-arrow-color;
- }
- &.bottom-left .tooltip-arrow {
- top: 0;
- right: $tooltip-arrow-width;
- margin-top: -$tooltip-arrow-width;
- border-width: 0 $tooltip-arrow-width $tooltip-arrow-width;
- border-bottom-color: $tooltip-arrow-color;
- }
- &.bottom-right .tooltip-arrow {
- top: 0;
- left: $tooltip-arrow-width;
- margin-top: -$tooltip-arrow-width;
- border-width: 0 $tooltip-arrow-width $tooltip-arrow-width;
- border-bottom-color: $tooltip-arrow-color;
- }
+.tooltip-top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -$tooltip-arrow-width;
+ border-width: $tooltip-arrow-width $tooltip-arrow-width 0;
+ border-top-color: $tooltip-arrow-color;
+}
+.tooltip-right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -$tooltip-arrow-width;
+ border-width: $tooltip-arrow-width $tooltip-arrow-width $tooltip-arrow-width 0;
+ border-right-color: $tooltip-arrow-color;
+}
+.tooltip-left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -$tooltip-arrow-width;
+ border-width: $tooltip-arrow-width 0 $tooltip-arrow-width $tooltip-arrow-width;
+ border-left-color: $tooltip-arrow-color;
+}
+.tooltip-bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -$tooltip-arrow-width;
+ border-width: 0 $tooltip-arrow-width $tooltip-arrow-width;
+ border-bottom-color: $tooltip-arrow-color;
}
diff --git a/scss/_type.scss b/scss/_type.scss
index 3954173245..5bbbf5873e 100644
--- a/scss/_type.scss
+++ b/scss/_type.scss
@@ -116,7 +116,7 @@ ol {
// Inline turns list items into inline-block
.list-inline {
- @extend list-unstyled();
+ @extend .list-unstyled;
margin-left: -5px;
> li {
diff --git a/scss/_utilities.scss b/scss/_utilities.scss
index aeffdcd781..5e297fc75e 100644
--- a/scss/_utilities.scss
+++ b/scss/_utilities.scss
@@ -10,11 +10,12 @@
.center-block {
@include center-block();
}
+
.pull-right {
- float: right !important;
+ @include pull-right();
}
.pull-left {
- float: left !important;
+ @include pull-left();
}
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 }
}
diff --git a/scss/mixins/_pulls.scss b/scss/mixins/_pulls.scss
new file mode 100644
index 0000000000..6bdff025d4
--- /dev/null
+++ b/scss/mixins/_pulls.scss
@@ -0,0 +1,6 @@
+@mixin pull-left {
+ float: left !important;
+}
+@mixin pull-right {
+ float: right !important;
+}
diff --git a/test-infra/S3Cachefile.json b/test-infra/S3Cachefile.json
index 04d8092467..90eae796dc 100644
--- a/test-infra/S3Cachefile.json
+++ b/test-infra/S3Cachefile.json
@@ -5,8 +5,8 @@
"generate": "./uncached-npm-install.sh"
},
"rubygems": {
- "key": "../pseudo_Gemfile.lock",
- "cache": "$GEMDIR",
- "generate": "gem install -N scss-lint -v $SCSS_LINT_VERSION && gem install -N jekyll -v $JEKYLL_VERSION && gem install -N rouge -v $ROUGE_VERSION"
+ "key": "$BUNDLE_GEMFILE",
+ "cache": "../vendor/cache",
+ "generate": "cd .. ; bundle install --path=\"`pwd`/vendor/cache\""
}
}
diff --git a/test-infra/gemfiles/core.gemfile b/test-infra/gemfiles/core.gemfile
new file mode 100644
index 0000000000..6a83726919
--- /dev/null
+++ b/test-infra/gemfiles/core.gemfile
@@ -0,0 +1,7 @@
+# Ruby Gems for the 'core' set of tests
+# Run `grunt update-gemfile-lock` to update to the latest compatible versions
+
+source 'https://rubygems.org'
+
+gem 'sass', '~> 3.4.9'
+gem 'scss-lint', '~> 0.31'
diff --git a/test-infra/gemfiles/core.gemfile.lock b/test-infra/gemfiles/core.gemfile.lock
new file mode 100644
index 0000000000..03580d83bb
--- /dev/null
+++ b/test-infra/gemfiles/core.gemfile.lock
@@ -0,0 +1,15 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ rainbow (2.0.0)
+ sass (3.4.9)
+ scss-lint (0.31.0)
+ rainbow (~> 2.0)
+ sass (~> 3.4.1)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ sass (~> 3.4.9)
+ scss-lint (~> 0.31)