diff --git a/scss/_variables.scss b/scss/_variables.scss index cac9a2051d..48cdfd523e 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -222,7 +222,7 @@ $enable-transitions: true !default; $enable-prefers-reduced-motion-media-query: true !default; $enable-grid-classes: true !default; $enable-pointer-cursor-for-buttons: true !default; -$enable-responsive-font-sizes: false !default; +$enable-rfs: true !default; $enable-validation-icons: true !default; $enable-deprecation-messages: true !default; diff --git a/scss/vendor/_rfs.scss b/scss/vendor/_rfs.scss index 43f19ca160..a68e738076 100644 --- a/scss/vendor/_rfs.scss +++ b/scss/vendor/_rfs.scss @@ -2,21 +2,21 @@ // SCSS RFS mixin // -// Automated responsive font sizes +// Automated responsive values for font sizes, paddings, margins and much more // // Licensed under MIT (https://github.com/twbs/rfs/blob/master/LICENSE) // Configuration -// Base font size -$rfs-base-font-size: 1.25rem !default; -$rfs-font-size-unit: rem !default; +// Base value +$rfs-base-value: 1.25rem !default; +$rfs-unit: rem !default; -@if $rfs-font-size-unit != rem and $rfs-font-size-unit != px { - @error "`#{$rfs-font-size-unit}` is not a valid unit for $rfs-font-size-unit. Use `px` or `rem`."; +@if $rfs-unit != rem and $rfs-unit != px { + @error "`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`."; } -// Breakpoint at where font-size starts decreasing if screen width is smaller +// Breakpoint at where values start decreasing if screen width is smaller $rfs-breakpoint: 1200px !default; $rfs-breakpoint-unit: px !default; @@ -24,16 +24,19 @@ $rfs-breakpoint-unit: px !default; @error "`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`."; } -// Resize font size based on screen height and width +// Resize values based on screen height and width $rfs-two-dimensional: false !default; // Factor of decrease $rfs-factor: 10 !default; -@if type-of($rfs-factor) != "number" or $rfs-factor <= 1 { +@if type-of($rfs-factor) != number or $rfs-factor <= 1 { @error "`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1."; } +// Mode. Possibilities: "min-media-query", "max-media-query" +$rfs-mode: min-media-query !default; + // Generate enable or disable classes. Possibilities: false, "enable" or "disable" $rfs-class: false !default; @@ -43,38 +46,63 @@ $rfs-rem-value: 16 !default; // Safari iframe resize bug: https://github.com/twbs/rfs/issues/14 $rfs-safari-iframe-resize-bug-fix: false !default; -// Disable RFS by setting $enable-responsive-font-sizes to false -$enable-responsive-font-sizes: true !default; +// Disable RFS by setting $enable-rfs to false +$enable-rfs: true !default; -// Cache $rfs-base-font-size unit -$rfs-base-font-size-unit: unit($rfs-base-font-size); +// Cache $rfs-base-value unit +$rfs-base-value-unit: unit($rfs-base-value); -// Remove px-unit from $rfs-base-font-size for calculations -@if $rfs-base-font-size-unit == "px" { - $rfs-base-font-size: $rfs-base-font-size / ($rfs-base-font-size * 0 + 1); +// Remove px-unit from $rfs-base-value for calculations +@if $rfs-base-value-unit == px { + $rfs-base-value: $rfs-base-value / ($rfs-base-value * 0 + 1); } -@else if $rfs-base-font-size-unit == "rem" { - $rfs-base-font-size: $rfs-base-font-size / ($rfs-base-font-size * 0 + 1 / $rfs-rem-value); +@else if $rfs-base-value-unit == rem { + $rfs-base-value: $rfs-base-value / ($rfs-base-value * 0 + 1 / $rfs-rem-value); } // Cache $rfs-breakpoint unit to prevent multiple calls $rfs-breakpoint-unit-cache: unit($rfs-breakpoint); // Remove unit from $rfs-breakpoint for calculations -@if $rfs-breakpoint-unit-cache == "px" { +@if $rfs-breakpoint-unit-cache == px { $rfs-breakpoint: $rfs-breakpoint / ($rfs-breakpoint * 0 + 1); } -@else if $rfs-breakpoint-unit-cache == "rem" or $rfs-breakpoint-unit-cache == "em" { +@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == "em" { $rfs-breakpoint: $rfs-breakpoint / ($rfs-breakpoint * 0 + 1 / $rfs-rem-value); } +// Calculate the media query value +$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{$rfs-breakpoint / $rfs-rem-value}#{$rfs-breakpoint-unit}); +$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width); +$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height); + +// Internal mixin used to determine which media query needs to be used +@mixin _rfs-media-query { + @if $rfs-two-dimensional { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) { + @content; + } + } + @else { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) { + @content; + } + } +} + // Internal mixin that adds disable classes to the selector if needed. -@mixin _rfs-disable-class { - @if $rfs-class == "disable" { - // Adding an extra class increases specificity, which prevents the media query to override the font size +@mixin _rfs-rule { + @if $rfs-class == disable and $rfs-mode == max-media-query { + // Adding an extra class increases specificity, which prevents the media query to override the property &, - .disable-responsive-font-size &, - &.disable-responsive-font-size { + .disable-rfs &, + &.disable-rfs { + @content; + } + } + @else if $rfs-class == enable and $rfs-mode == min-media-query { + .enable-rfs &, + &.enable-rfs { @content; } } @@ -84,103 +112,194 @@ $rfs-breakpoint-unit-cache: unit($rfs-breakpoint); } // Internal mixin that adds enable classes to the selector if needed. -@mixin _rfs-enable-class { - @if $rfs-class == "enable" { - .enable-responsive-font-size &, - &.enable-responsive-font-size { - @content; - } - } - @else { - @content; - } -} +@mixin _rfs-media-query-rule { -// Internal mixin used to determine which media query needs to be used -@mixin _rfs-media-query($mq-value) { - @if $rfs-two-dimensional { - @media (max-width: #{$mq-value}), (max-height: #{$mq-value}) { + @if $rfs-class == enable { + @if $rfs-mode == min-media-query { @content; } + + @include _rfs-media-query { + .enable-rfs &, + &.enable-rfs { + @content; + } + } } @else { - @media (max-width: #{$mq-value}) { + @if $rfs-class == disable and $rfs-mode == min-media-query { + .disable-rfs &, + &.disable-rfs { + @content; + } + } + @include _rfs-media-query { @content; } } } -// Responsive font size mixin -@mixin rfs($fs, $important: false) { - // Cache $fs unit - $fs-unit: if(type-of($fs) == "number", unit($fs), false); +// Helper function to get the formatted non-responsive value +@function rfs-value($values) { + // Convert to list + $values: if(type-of($values) != list, ($values,), $values); - // Add !important suffix if needed - $rfs-suffix: if($important, " !important", ""); + $val: ''; - // If $fs isn't a number (like inherit) or $fs has a unit (not px or rem, like 1.5em) or $ is 0, just print the value - @if not $fs-unit or $fs-unit != "" and $fs-unit != "px" and $fs-unit != "rem" or $fs == 0 { - font-size: #{$fs}#{$rfs-suffix}; - } - @else { - // Remove unit from $fs for calculations - @if $fs-unit == "px" { - $fs: $fs / ($fs * 0 + 1); - } - @else if $fs-unit == "rem" { - $fs: $fs / ($fs * 0 + 1 / $rfs-rem-value); - } - - // Set default font size - $rfs-static: if($rfs-font-size-unit == rem, #{$fs / $rfs-rem-value}rem, #{$fs}px); - - // Only add the media query if the font size is bigger than the minimum font size - @if $fs <= $rfs-base-font-size or not $enable-responsive-font-sizes { - font-size: #{$rfs-static}#{$rfs-suffix}; + // Loop over each value and calculate value + @each $value in $values { + @if $value == 0 { + $val: $val + ' 0'; } @else { - // Calculate the minimum font size for $fs - $fs-min: $rfs-base-font-size + ($fs - $rfs-base-font-size) / $rfs-factor; + // Cache $value unit + $unit: if(type-of($value) == "number", unit($value), false); - // Calculate difference between $fs and the minimum font size - $fs-diff: $fs - $fs-min; + @if $unit == px { + // Convert to rem if needed + $val: $val + ' ' + if($rfs-unit == rem, #{$value / ($value * 0 + $rfs-rem-value)}rem, $value); + } + @else if $unit == rem { + // Convert to px if needed + $val: $val + ' ' + if($rfs-unit == px, #{$value / ($value * 0 + 1) * $rfs-rem-value}px, $value); + } + @else { + // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value + $val: $val + ' ' + $value; + } + } + } - // Base font-size formatting - $min-width: if($rfs-font-size-unit == rem, #{$fs-min / $rfs-rem-value}rem, #{$fs-min}px); + // Remove first space + @return unquote(str-slice($val, 2)); +} - // Use `vmin` if two-dimensional is enabled - $variable-unit: if($rfs-two-dimensional, vmin, vw); +// Helper function to get the responsive value calculated by RFS +@function rfs-fluid-value($values) { + // Convert to list + $values: if(type-of($values) != list, ($values,), $values); - // Calculate the variable width between 0 and $rfs-breakpoint - $variable-width: #{$fs-diff * 100 / $rfs-breakpoint}#{$variable-unit}; + $val: ''; - // Set the calculated font-size - $rfs-fluid: calc(#{$min-width} + #{$variable-width}) #{$rfs-suffix}; + // Loop over each value and calculate value + @each $value in $values { + @if $value == 0 { + $val: $val + ' 0'; + } - // Breakpoint formatting - $mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{$rfs-breakpoint / $rfs-rem-value}#{$rfs-breakpoint-unit}); + @else { + // Cache $value unit + $unit: if(type-of($value) == "number", unit($value), false); - @include _rfs-disable-class { - font-size: #{$rfs-static}#{$rfs-suffix}; + // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value + @if not $unit or $unit != px and $unit != rem { + $val: $val + ' ' + $value; } - @include _rfs-media-query($mq-value) { - @include _rfs-enable-class { - font-size: $rfs-fluid; + @else { + // Remove unit from $value for calculations + $value: $value / ($value * 0 + if($unit == px, 1, 1 / $rfs-rem-value)); + + // Only add the media query if the value is greater than the minimum value + @if abs($value) <= $rfs-base-value or not $enable-rfs { + $val: $val + ' ' + if($rfs-unit == rem, #{$value / $rfs-rem-value}rem, #{$value}px); } + @else { + // Calculate the minimum value + $value-min: $rfs-base-value + (abs($value) - $rfs-base-value) / $rfs-factor; + + // Calculate difference between $value and the minimum value + $value-diff: abs($value) - $value-min; + + // Base value formatting + $min-width: if($rfs-unit == rem, #{$value-min / $rfs-rem-value}rem, #{$value-min}px); + + // Use negative value if needed + $min-width: if($value < 0, -$min-width, $min-width); + + // Use `vmin` if two-dimensional is enabled + $variable-unit: if($rfs-two-dimensional, vmin, vw); + + // Calculate the variable width between 0 and $rfs-breakpoint + $variable-width: #{$value-diff * 100 / $rfs-breakpoint}#{$variable-unit}; + + // Return the calculated value + $val: $val + ' calc(' + $min-width + if($value < 0, ' - ', ' + ') + $variable-width + ')'; + } + } + } + } + + // Remove first space + @return unquote(str-slice($val, 2)); +} + +// RFS mixin +@mixin rfs($values, $property: font-size) { + @if $values != null { + $val: rfs-value($values); + $fluidVal: rfs-fluid-value($values); + + // Do not print the media query if responsive & non-responsive values are the same + @if $val == $fluidVal { + #{$property}: $val; + } + @else { + @include _rfs-rule { + #{$property}: if($rfs-mode == max-media-query, $val, $fluidVal); // Include safari iframe resize fix if needed min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null); } + + @include _rfs-media-query-rule { + #{$property}: if($rfs-mode == max-media-query, $fluidVal, $val); + } } } } -// The font-size & responsive-font-size mixins use RFS to rescale the font size -@mixin font-size($fs, $important: false) { - @include rfs($fs, $important); +// Shorthand helper mixins +@mixin font-size($value) { + @include rfs($value); } -@mixin responsive-font-size($fs, $important: false) { - @include rfs($fs, $important); +@mixin padding($value) { + @include rfs($value, padding); +} + +@mixin padding-top($value) { + @include rfs($value, padding-top); +} + +@mixin padding-right($value) { + @include rfs($value, padding-right); +} + +@mixin padding-bottom($value) { + @include rfs($value, padding-bottom); +} + +@mixin padding-left($value) { + @include rfs($value, padding-left); +} + +@mixin margin($value) { + @include rfs($value, margin); +} + +@mixin margin-top($value) { + @include rfs($value, margin-top); +} + +@mixin margin-right($value) { + @include rfs($value, margin-right); +} + +@mixin margin-bottom($value) { + @include rfs($value, margin-bottom); +} + +@mixin margin-left($value) { + @include rfs($value, margin-left); } diff --git a/site/assets/scss/_algolia.scss b/site/assets/scss/_algolia.scss index f86d2fb4b9..5d9951dc3c 100644 --- a/site/assets/scss/_algolia.scss +++ b/site/assets/scss/_algolia.scss @@ -47,7 +47,7 @@ .algolia-docsearch-suggestion--category-header { padding: .125rem 1rem !important; margin-top: 0 !important; - @include font-size(.875rem, true); + @include font-size(.875rem !important); font-weight: 600 !important; color: $bd-purple-bright !important; border-bottom: 0 !important; @@ -107,7 +107,7 @@ .algolia-docsearch-suggestion--title { display: block; margin-bottom: 0 !important; - @include font-size(.875rem, true); + @include font-size(.875rem !important); font-weight: 400 !important; } @@ -115,7 +115,7 @@ flex: 0 0 100%; max-width: 100%; padding: .2rem 0; - @include font-size(.8125rem, true); + @include font-size(.8125rem !important); font-weight: 400; line-height: 1.25 !important; color: $gray-600; @@ -126,7 +126,7 @@ width: auto !important; height: auto !important; padding: .75rem 1rem 0; - @include font-size(.75rem, true); + @include font-size(.75rem !important); line-height: 1 !important; color: $gray-600 !important; border-top: 1px solid rgba(0, 0, 0, .1); diff --git a/site/assets/scss/_content.scss b/site/assets/scss/_content.scss index 1ce9a1722c..9bb9e7e679 100644 --- a/site/assets/scss/_content.scss +++ b/site/assets/scss/_content.scss @@ -58,18 +58,6 @@ // .bd-content { - > h2 { - @include font-size($h2-font-size); - } - - > h3 { - @include font-size($h3-font-size); - } - - > h4 { - @include font-size($h4-font-size); - } - > h2:not(:first-child) { margin-top: 3rem; } diff --git a/site/assets/scss/_variables.scss b/site/assets/scss/_variables.scss index 6cf63600fc..4ebe2be710 100644 --- a/site/assets/scss/_variables.scss +++ b/site/assets/scss/_variables.scss @@ -11,8 +11,3 @@ $bd-warning: #f0ad4e; $bd-danger: #d9534f; $dropdown-active-icon: url("data:image/svg+xml,"); $sidebar-collapse-icon: url("data:image/svg+xml,"); - -// Enable responsive font sizes for font sizes defined in the docs -// The weird if test is made as a workaround to prevent a false fusv error. -// -$enable-responsive-font-sizes: if($enable-responsive-font-sizes, true, true); diff --git a/site/content/docs/4.3/content/typography.md b/site/content/docs/4.3/content/typography.md index aa7247e6b8..54636bc89c 100644 --- a/site/content/docs/4.3/content/typography.md +++ b/site/content/docs/4.3/content/typography.md @@ -102,7 +102,7 @@ Use the included utility classes to recreate the small secondary heading text fr ## Display headings -Traditional heading elements are designed to work best in the meat of your page content. When you need a heading to stand out, consider using a **display heading**—a larger, slightly more opinionated heading style. Keep in mind these headings are not responsive by default, but it's possible to enable [responsive font sizes](#responsive-font-sizes). +Traditional heading elements are designed to work best in the meat of your page content. When you need a heading to stand out, consider using a **display heading**—a larger, slightly more opinionated heading style.
Display 1
@@ -272,6 +272,4 @@ Align terms and descriptions horizontally by using our grid system's predefined ## Responsive font sizes -Bootstrap v4.3 ships with the option to enable responsive font sizes, allowing text to scale more naturally across device and viewport sizes. RFS can be enabled by changing the `$enable-responsive-font-sizes` Sass variable to `true` and recompiling Bootstrap. - -To support RFS, we use a Sass mixin to replace our normal `font-size` properties. Responsive font sizes will be compiled into `calc()` functions with a mix of `rem` and viewport units to enable the responsive scaling behavior. More about RFS and its configuration can be found on its [GitHub repository](https://github.com/twbs/rfs). +In Bootstrap `v5`, we've enabled responsive font sizes by default, allowing text to scale more naturally across device and viewport sizes. Have a look at the [RFS]({{< docsref "/getting-started/rfs" >}}) page to find out how this works. diff --git a/site/content/docs/4.3/getting-started/rfs.md b/site/content/docs/4.3/getting-started/rfs.md new file mode 100644 index 0000000000..744b79cfaf --- /dev/null +++ b/site/content/docs/4.3/getting-started/rfs.md @@ -0,0 +1,86 @@ +--- +layout: docs +title: RFS +description: Bootstrap's resizing engine. +group: getting-started +toc: true +--- + +## What is RFS? + +Bootstrap's side project [RFS](https://github.com/twbs/rfs) is a unit resizing engine which was initially developed to resize font sizes (hence its abbreviation for Responsive Font Sizes). Nowadays RFS is capable of rescaling basically every value for any css property with units, like `margin`, `padding`, `border-radius` or even `box-shadow`. + +The mechanism automatically calculates the appropriate values based on the dimensions of the browser viewport. It will be compiled into `calc()` functions with a mix of `rem` and viewport units to enable the responsive scaling behavior. + +## Using RFS + +The mixins are included in Bootstrap and are available once you include Bootstraps' `scss`. RFS can also be installed [standalone](https://github.com/twbs/rfs#installation) if needed. + +### Using the mixins + +The `rfs()` mixin has shorthands for `font-size`, `margin`, `margin-top`, `margin-right`, `margin-bottom`, `margin-left`, `padding`, `padding-top`, `padding-right`, `padding-bottom` and `padding-left` which can be used like this: + +```scss +.title { + @include font-size(4rem); +} +``` + +which outputs the following CSS: + +```css +.title { + font-size: calc(1.525rem + 3.3vw); +} + +@media (max-width: 1200px) { + .title { + font-size: 4rem; + } +} +``` + +Any other property can be passed to the `rfs()` mixin like this: + +```scss +.selector { + @include rfs(4rem, border-radius); +} +``` + +`!important` can also just be added to whatever value you want: + +```scss +.selector { + @include padding(2.5rem !important); +} +``` + +### Using the functions + +- `rfs-value()` converts a value into a `rem` value if a `px` value is passed, in other cases it returns the same result. +- `rfs-fluid-value()` returns the fluid version of a value if the property needs rescaling. + +In this example we use one of Bootstrap's built-in [responsive breakpoint mixins]({{< docsref "/layout/overview#responsive-breakpoints" >}}) to only apply styling below the `lg` breakpoint. + +```scss +.selector { + @include media-breakpoint-down(lg) { + padding: rfs-fluid-value(2rem); + font-size: rfs-fluid-value(1.125rem); + } +} +``` + +```css +@media (max-width: 991.98px) { + .selector { + padding: calc(1.325rem + 0.9vw); + font-size: 1.125rem; /* 1.125rem is small enough, so RFS won't rescale this */ + } +} +``` + +## Extended documentation + +RFS is a separate project under the Bootstrap organisation. More about RFS and its configuration can be found on its [GitHub repository](https://github.com/twbs/rfs). diff --git a/site/content/docs/4.3/getting-started/theming.md b/site/content/docs/4.3/getting-started/theming.md index 0c5ad09ab3..7c764afedb 100644 --- a/site/content/docs/4.3/getting-started/theming.md +++ b/site/content/docs/4.3/getting-started/theming.md @@ -270,7 +270,7 @@ You can find and customize these variables for key global options in Bootstrap's | `$enable-grid-classes` | `true` (default) or `false` | Enables the generation of CSS classes for the grid system (e.g., `.container`, `.row`, `.col-md-1`, etc.). | | `$enable-caret` | `true` (default) or `false` | Enables pseudo element caret on `.dropdown-toggle`. | | `$enable-pointer-cursor-for-buttons` | `true` (default) or `false` | Add "hand" cursor to non-disabled button elements. | -| `$enable-responsive-font-sizes` | `true` or `false` (default) | Enables [responsive font sizes]({{< docsref "/content/typography#responsive-font-sizes" >}}). | +| `$enable-rfs` | `true` or `false` (default) | Globally enables [RFS]({{< docsref "/getting-started/rfs" >}}). | | `$enable-validation-icons` | `true` (default) or `false` | Enables `background-image` icons within textual inputs and some custom forms for validation states. | | `$enable-deprecation-messages` | `true` or `false` (default) | Set to `true` to show warnings when using any of the deprecated mixins and functions that are planned to be removed in `v5`. | diff --git a/site/content/docs/4.3/migration.md b/site/content/docs/4.3/migration.md index a8aeebd397..ae72010fec 100644 --- a/site/content/docs/4.3/migration.md +++ b/site/content/docs/4.3/migration.md @@ -59,7 +59,7 @@ Changes to any layout tools and our grid system. Changes to Reboot, typography, tables, and more. -- **Todo:** Make RFS enabled by default +- [RFS](https://github.com/twbs/rfs) enabled for automated font size rescaling. [See #29152](https://github.com/twbs/bootstrap/pull/29152) - Reset default horizontal `padding-left` on `