Skip to content

Commit

Permalink
feat(back to top): brand new component 🎉
Browse files Browse the repository at this point in the history
  • Loading branch information
ffoodd committed Jan 18, 2021
1 parent 329b15b commit 893944d
Show file tree
Hide file tree
Showing 14 changed files with 347 additions and 10 deletions.
4 changes: 2 additions & 2 deletions .bundlewatch.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
},
{
"path": "./dist/css/boosted.css",
"maxSize": "23.7 kB"
"maxSize": "24 kB"
},
{
"path": "./dist/css/boosted.min.css",
"maxSize": "21.7 kB"
"maxSize": "21.9 kB"
},
{
"path": "./dist/js/boosted.bundle.js",
Expand Down
73 changes: 73 additions & 0 deletions scss/_back-to-top.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Boosted only
// See https://moderncss.dev/pure-css-smooth-scroll-back-to-top/
[id="#{$back-to-top-target-id}"]:target {
scroll-margin-top: $back-to-top-target-offset-top;
}

.back-to-top {
position: absolute;
top: $back-to-top-display-threshold;
right: $back-to-top-offset-right;
bottom: $back-to-top-offset-bottom;
z-index: $zindex-back-to-top;
pointer-events: none;

@include media-breakpoint-up(xl) {
right: $back-to-top-offset-right * 2;
bottom: $back-to-top-offset-bottom * 2;
}
}

.back-to-top-link {
position: sticky;
top: $back-to-top-link-offset-top;
// @TODO Could be dropped when .btn-icon come in
min-width: $back-to-top-width;
min-height: $back-to-top-height;
padding: 0;
// End @TODO
pointer-events: all;

@include media-breakpoint-up(xl) {
top: $back-to-top-link-offset-top-xl;

&[data-#{$boosted-variable-prefix}label]::before {
position: absolute;
right: $back-to-top-title-offset-right;
padding: $back-to-top-title-padding;
color: color-contrast($back-to-top-title-bg-color);
white-space: nowrap;
content: attr(data-#{$boosted-variable-prefix}label);
background-color: $back-to-top-title-bg-color;
}

&[data-#{$boosted-variable-prefix}label]:hover::before,
&[data-#{$boosted-variable-prefix}label]:focus::before {
text-decoration: $link-decoration;
}
}

/* &:not([title]) :only-child {
margin-right: $spacer / -2;
} */

// @TODO Could be dropped when .btn-icon come in
&::after {
display: inline-block;
width: $back-to-top-icon-width;
height: $back-to-top-icon-height;
content: "";
background: $back-to-top-icon-bg;
transform: rotate(.25turn);
}

&:hover:not(:active)::after,
&:focus:not(:active)::after {
filter: $back-to-top-icon-hover-filter;
}

&:not([title]):not([data-#{$boosted-variable-prefix}label])::after {
margin-left: $spacer / 2;
}
// End @TODO
}
1 change: 1 addition & 0 deletions scss/_reboot.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
// See https://developer.mozilla.org/fr/docs/Web/CSS/font-synthesis

body {
position: relative; // Boosted mod: required for back-to-top component
margin: 0; // 1
font-family: $font-family-base;
font-synthesis: none; // Boosted mod // 5
Expand Down
23 changes: 23 additions & 0 deletions scss/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,7 @@ $zindex-modal-backdrop: 1040 !default;
$zindex-modal: 1050 !default;
$zindex-popover: 1060 !default;
$zindex-tooltip: 1070 !default;
$zindex-back-to-top: 1080 !default; // Boosted mod
// scss-docs-end zindex-stack

// Navs
Expand Down Expand Up @@ -1471,3 +1472,25 @@ $pre-line-height: 1.25 !default; // Boosted mod
//// Minimum target size (44×44px)
$target-size: 2.75rem !default;

//// Back to top
// scss-docs-start back-to-top
$back-to-top-display-threshold: 100vh !default;
$back-to-top-target-id: "top" !default;
$back-to-top-target-offset-top: $spacer * 5 !default; // Matching .navbar computed height
$back-to-top-offset: $spacer * 1.5 !default;
$back-to-top-offset-right: $back-to-top-offset !default;
$back-to-top-offset-bottom: $back-to-top-offset !default;
$back-to-top-link-offset-top: subtract(100vh, $back-to-top-offset * 4) !default;
$back-to-top-link-offset-top-xl: subtract(100vh, $spacer * 5) !default;
$back-to-top-title-offset-right: add(100%, $border-width) !default;
$back-to-top-title-padding: subtract($btn-padding-y, 1px) $btn-padding-x add($btn-padding-y, 1px) !default;
$back-to-top-title-bg-color: $white !default;
// scss-docs-end back-to-top
// @TODO Could be dropped when .btn-icon come in
$back-to-top-width: $spacer * 2 !default;
$back-to-top-height: $spacer * 2 !default;
$back-to-top-icon-width: $pagination-icon-width !default;
$back-to-top-icon-height: $pagination-icon-height !default;
$back-to-top-icon-bg: $pagination-icon-background !default;
$back-to-top-icon-hover-filter: $invert-filter !default;
// End @TODO
4 changes: 2 additions & 2 deletions scss/boosted.scss
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@
@import "carousel";
@import "spinners";

// Boosted
@import "back-to-top";

// Helpers
@import "helpers";


// Utilities
@import "utilities/api";

// Boosted
// scss-docs-end import-stack
7 changes: 7 additions & 0 deletions site/assets/scss/_boosted.scss
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,10 @@ body {
text-decoration: none;
}
}

// Back to top offset
[id="#{$back-to-top-target-id}"]:target {
@include media-breakpoint-up(md) {
scroll-margin-top: $offset-top;
}
}
139 changes: 139 additions & 0 deletions site/content/docs/5.0/components/back-to-top.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
layout: docs
title: Back to top
description: Sticky back-to-top link appearing after scrolling down one viewport height.
group: components
toc: true
---

## Overview

Boosted "back to top" provides a way to get back to the top of the page using a simple link. It's built only with HTML and CSS, meaning you don't need any JavaScript. It only requires a `.back-to-top` wrapper and a `.back-to-top-link`, at the end of your `body`— just before your scripts.

For accessibility purposes, back-to-top link contains a `.visually-hidden` text content and a `data-o-label` attribute— whose **value should match hidden text content** to make sure it's usable with speech recognition software. The `data-o-label` attribute content is displayed in a `::before` pseudo-element thanks to the `attr()` CSS function.

We also recommend using a `nav` wrapper —alongside an accurate `aria-label`— to ease discoverability through landmarks.

Make sure you leave enough space between the back-to-top link and the bottom of the viewport to:
- prevent the component being overlapped by bottom navigation bar on mobile and notification tooltips for Windows users,
- avoid proximity with system interactive areas, which could lead to accidentally activating an adjacent target.


{{< callout >}}
### Smooth scroll

Smooth scrolling does not depend on this component. It's turned on only when the user has **not** explicitly signaled that they’d prefer reduced motion (i.e. where `prefers-reduced-motion: no-preference`) through the `scroll-behavior` property. [Read more about `prefers-reduced-motion` in our accessibility page]({{< docsref "/getting-started/accessibility#reduced-motion" >}}).
{{< /callout >}}

## Example

<div class="bd-example">
<nav aria-label="Standard back to top example" class="back-to-top position-static ps-5 ms-5">
<a href="#top" class="back-to-top-link btn btn-secondary position-relative top-0" data-o-label="Back to top">
<span class="visually-hidden">Back to top</span>
</a>
</nav>
</div>
{{< example show_preview="false" >}}
<nav aria-label="Back to top" class="back-to-top">
<a href="#top" class="back-to-top-link btn btn-secondary" data-o-label="Back to top">
<span class="visually-hidden">Back to top</span>
</a>
</nav>
{{< /example >}}

{{< callout warning >}}
### Define a target

Since we're using a link, **you need a valid target**. We recommend adding an anchor link at the beginning of your markup, like so: `<a id="top"></a>`.
You may use another `id`, but if you're using a fixed header you'll need to override our `$back-to-top-target-id` variable to ensure it won't overlap content after scrolling up.
{{< /callout >}}

### Always visible

Add `.position-fixed` utility to your `.back-to-top-link` to make your back-to-top link persistent.

{{< example show_preview="false" >}}
<nav aria-label="Fixed back to top example" class="back-to-top">
<a href="#top" class="back-to-top-link position-fixed btn btn-secondary" data-o-label="Back to top">
<span class="visually-hidden">Back to top</span>
</a>
</nav>
{{< /example >}}

### Label inside

Drop the `data-o-label` attribute and the `<span class="visually-hidden">` and use [spacing utilities]({{< docsref "/utilities/spacing" >}}) to fine tune your button.

<div class="bd-example">
<nav aria-label="Label inside back to top example" class="back-to-top position-static">
<a href="#top" class="back-to-top-link position-static btn btn-secondary px-2">Back to top</a>
</nav>
</div>
{{< example show_preview="false" >}}
<nav aria-label="Back to top" class="back-to-top">
<a href="#top" class="back-to-top-link btn btn-secondary px-2">Back to top</a>
</nav>
{{< /example >}}

### Icon only

Use a `title` attribute instead of `data-o-label` to ensure a visible label is still provided on demand for sighted users.

<div class="bd-example">
<nav aria-label="Icon only back to top example" class="back-to-top position-static">
<a href="#top" class="back-to-top-link position-static btn btn-secondary" title="Back to top">
<span class="visually-hidden">Back to top</span>
</a>
</nav>
</div>
{{< example show_preview="false" >}}
<nav aria-label="Back to top" class="back-to-top">
<a href="#top" class="back-to-top-link btn btn-secondary" title="Back to top">
<span class="visually-hidden">Back to top</span>
</a>
</nav>
{{< /example >}}

## Sass options

Back to top link can be customized in a few ways: either making it appear after more or less vertical scrolling, modify its offset from the bottom right corner, etc.

<table class="table">
<thead>
<tr>
<th>Variable</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>$back-to-top-display-threshold</code></td>
<td>
Defines the vertical threshold at which "back to top" link appears.
</td>
<td><code>100vh</code></td>
</tr>
<tr>
<td><code>$back-to-top-target-id</code></td>
<td>
Target's <code>id</code>, used to apply <code>scroll-margin-top</code> when anchor is active.
</td>
<td><code>"top"</code></td>
</tr>
<tr>
<td><code>$back-to-top-offset</code></td>
<td>
Base offset, used to place "back to top" link in the bottom right corner of the page.
</td>
<td><code>$spacer * 1.5</code></td>
</tr>
</tbody>
</table>

### Variables

For more details, please have a look at the exhaustive list of available variables:

{{< scss-docs name="back-to-top" file="scss/_variables.scss" >}}
41 changes: 41 additions & 0 deletions site/content/docs/5.0/examples/cheatsheet-rtl/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
direction: rtl
---

<a id="top" class="position-absolute"></a><!-- Boosted mod -->

<header class="bd-header navbar navbar-expand-md navbar-dark bg-dark">
<div class="container-fluid">
<h1 class="navbar-brand">
Expand Down Expand Up @@ -45,6 +47,7 @@ <h2 class="h6 pt-4 pb-3 mb-4 border-bottom border-light border-1">على هذه
<ul class="list-unstyled collapse" id="components-collapse">
<li><a class="d-flex" href="#accordion">الأكورديون</a></li>
<li><a class="d-flex" href="#alerts">إنذار</a></li>
<li><a class="d-flex" href="#back-to-top">Back to to</a></li><!-- Boosted mod -->
<li><a class="d-flex" href="#badge">شارة</a></li>
<li><a class="d-flex" href="#breadcrumb">مسار التنقل</a></li>
<li><a class="d-flex" href="#buttons">أزرار</a></li>
Expand Down Expand Up @@ -667,6 +670,36 @@ <h4 class="alert-heading">أحسنت!</h4>
{{< /example >}}
</div>
</article>
<!-- Boosted mod -->
<article class="my-3" id="back-to-top">
<div class="bd-heading sticky-xl-top align-self-start mt-5 mb-3 mt-xl-0 mb-xl-2">
<h3>عد إلى الأعلى</h3>
<a class="d-flex align-items-center" href="{{< docsref "/components/back-to-top" >}}">توثيق</a>
</div>

<div class="row row-cols-3">
{{< example show_markup="false" >}}
<nav aria-label="معيار العودة إلى أعلى مثال" class="back-to-top position-static ps-5 ms-5">
<a href="#top" class="back-to-top-link btn btn-secondary position-relative top-0" data-o-label="عد إلى الأعلى">
<span class="visually-hidden">عد إلى الأعلى</span>
</a>
</nav>
{{< /example >}}
{{< example show_markup="false" class="bd-example mt-0" >}}
<nav aria-label="تسمية من الداخل إلى أعلى مثال" class="back-to-top position-static">
<a href="#top" class="back-to-top-link position-static btn btn-secondary px-2">عد إلى الأعلى</a>
</nav>
{{< /example >}}
{{< example show_markup="false" class="bd-example mt-0" >}}
<nav aria-label="رمز فقط إلى أعلى مثال" class="back-to-top position-static">
<a href="#top" class="back-to-top-link position-static btn btn-secondary" title="عد إلى الأعلى">
<span class="visually-hidden">عد إلى الأعلى</span>
</a>
</nav>
{{< /example >}}
</div>
</article>
<!-- End mod -->
<article class="my-3" id="badge">
<div class="bd-heading sticky-xl-top align-self-start mt-5 mb-3 mt-xl-0 mb-xl-2">
<h3>شارة</h3>
Expand Down Expand Up @@ -1501,3 +1534,11 @@ <h5 class="modal-title h4" id="exampleModalFullscreenLabel">مشروط ملء ا
</div>
</div>
</div>

<!-- Boosted mod -->
<nav aria-label="عد إلى الأعلى" class="back-to-top">
<a href="#top" class="back-to-top-link btn btn-secondary" data-o-label="عد إلى الأعلى">
<span class="visually-hidden">عد إلى الأعلى</span>
</a>
</nav>
<!-- End mod -->
2 changes: 1 addition & 1 deletion site/content/docs/5.0/examples/cheatsheet/cheatsheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
function setActiveItem() {
var hash = window.location.hash

if (hash === '') {
if (hash === '' || hash === 'top') {
return
}

Expand Down
Loading

0 comments on commit 893944d

Please sign in to comment.