Skip to content
156 changes: 141 additions & 15 deletions files/en-us/web/api/element/scroll/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ browser-compat: api.Element.scroll

{{APIRef("CSSOM view API")}}

The **`scroll()`** method of the {{domxref("Element")}}
interface scrolls the element to a particular set of coordinates inside a given
element.
The **`scroll()`** method of the {{domxref("Element")}} interface scrolls to a particular set of coordinates inside a given element.

## Syntax

Expand All @@ -22,29 +20,34 @@ scroll(options)
### Parameters

- `xCoord`
- : The pixel along the horizontal axis of the element that you want displayed in the
upper left.
- : The pixel along the horizontal axis of the element that you want displayed in the upper left.
- `yCoord`
- : The pixel along the vertical axis of the element that you want displayed in the
upper left.
- : The pixel along the vertical axis of the element that you want displayed in the upper left.
- `options`
- : An object containing the following properties:
- `top`
- `top` {{optional_inline}}
- : Specifies the number of pixels along the Y axis to scroll the window or element.
- `left`
- `left` {{optional_inline}}
- : Specifies the number of pixels along the X axis to scroll the window or element.
- `behavior`
- : Determines whether scrolling is instant or animates smoothly. This option is a string which must take one of the following values:
- `smooth`: scrolling should animate smoothly
- `instant`: scrolling should happen instantly in a single jump
- `auto`: scroll behavior is determined by the computed value of {{cssxref("scroll-behavior")}}
- `behavior` {{optional_inline}}
- : Determines whether scrolling is instant or animates smoothly. This option is a string that must take one of the following values:
- `smooth`: The scrolling animates smoothly.
- `instant`: The scrolling happens instantly in a single jump.
- `auto`: The scroll behavior is determined by the computed value of the {{cssxref("scroll-behavior")}} CSS property on the element.

If omitted, `behavior` defaults to `auto`.

### Return value

None ({{jsxref("undefined")}}).
A {{jsxref("Promise")}} that fulfills with an object containing the following property:

- `interrupted`
- : A boolean value indicating whether the scrolling operation was interrupted (`true`) or not (`false`). Such an interruption typically happens when a programmatic scroll is ongoing, and another programmatic scroll is initiated on the same element before the first one finishes.
Comment thread
hamishwillee marked this conversation as resolved.

## Examples

### Basic usage

```js
// Put the 1000th vertical pixel at the top of the element
element.scroll(0, 1000);
Expand All @@ -60,6 +63,129 @@ element.scroll({
});
```

### Responding to the end of the scroll

Our [element methods demo](https://mdn.github.io/dom-examples/scroll-promises/element-methods/) ([see source code](https://github.com/mdn/dom-examples/tree/main/scroll-promises/element-methods)) demonstrates how the promise return value of `scroll()` can be used to respond to the end of a scrolling operation. This technique is mostly useful in cases where the scrolling occurs smoothly over time (achieved by setting the [`behavior`](#behavior) option to `smooth`, or by setting the scrolling element's {{cssxref("scroll-behavior")}} property to `smooth`).

#### HTML

Our HTML includes a {{htmlelement("section")}} element containing several paragraphs of content and a {{htmlelement("div")}} element toolbar containing {{htmlelement("button")}} elements that trigger various scrolling operations on the `<section>`.

```html
<div>
<button class="scroll">scroll() to 1000</button>
<button class="scrollto">scrollTo() top</button>
<button class="scrollby">scrollBy() 200</button>
<button class="scrollintoview">Scroll last &lt;p&gt; into view</button>
</div>

<section>...</section>
```

#### CSS

We give the `<section>` element a fixed {{cssxref("height")}} and an {{cssxref("overflow-y")}} value of `scroll` so that it scrolls vertically, and set its {{cssxref("scroll-behavior")}} property to `smooth` so that any scroll operations are animated smoothly over time rather than instantly.

```css
section {
border: 1px solid black;
padding: 20px;
margin-top: 60px;
height: 500px;
overflow-y: scroll;
scroll-behavior: smooth;
}
```

We also create two class selectors; when a `fade-out` or `fade-in` class is applied to an element, an {{cssxref("animation")}} is applied so that it smoothly fades out or in, respectively. We also define {{cssxref("@keyframes")}} blocks to define the required {{cssxref("opacity")}} changes for those animations.

```css
.fade-out {
animation: fade-out 0.3s linear both;
}

.fade-in {
animation: fade-in 0.3s linear both;
}

@keyframes fade-out {
from {
opacity: 1;
}

to {
opacity: 0;
}
}

@keyframes fade-in {
from {
opacity: 0;
}

to {
opacity: 1;
}
}
```

The rest of the CSS is not shown, for brevity.

#### JavaScript

We start by grabbing references to the `<button>` that runs the `scroll()` operation, the toolbar `<div>`, and the scrolling `<section>`:

```js
const scrollBtn = document.querySelector(".scroll");
const toolbar = document.querySelector("div");
const section = document.querySelector("section");
```

Next, we define a function called `isInterrupted()`, designed to run in response to a scroll operation finishing, which takes a boolean `interrupted` value as a parameter. It logs a message to the console to say that scrolling is finished and indicate whether the operation was interrupted (`interrupted` is `true`) or not. In addition, if `interrupted` is `true`, it calls an `alert()` to clearly indicate the interruption.

```js
function isInterrupted(interrupted) {
console.log(`Scroll finished;${interrupted ? " " : " not "}interrupted`);
if (interrupted) {
alert("Scroll interrupted!");
}
}
```

When the button is clicked, we immediately apply the `fade-out` class to the toolbar, causing it to fade out. We then run `scroll(0, 1000)` on the `<section>` to scroll its content down 1000 pixels, `await`ing its promise resolution as we do so and storing the `result` in a constant. When the promise has resolved, we call `isInterrupted()` to report that the scroll operation has finished and whether it was interrupted. Finally, we apply the `fade-in` class to the toolbar, causing it to fade back in again.

```js
scrollBtn.addEventListener("click", async () => {
toolbar.className = "fade-out";
const result = await section.scroll(0, 1000);
isInterrupted(result.interrupted);
toolbar.className = "fade-in";
});
Comment on lines +157 to +163

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The examples don't work yet. IMO would prefer in-page examples to these kinds of link elsewhere examples.
  2. IFF the return type is a promise that resolves with undefined (as per spec) the example is good. If the promise actually resolves with interrupted as the docs say then this should output the value instead.

Ditto everywhere.,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. See Add scroll-promises examples dom-examples#386 for the examples. I've just updated the PR so that the example event handlers output an indication of whether the scroll was interrupted or not, rather than just a static log message.
  2. I normally agree that in-page live examples are better. However, in this case, you've got seven pages to document this behavior on, and the promise return value, while significant, is not the be-all and end-all of the methods; it is more of a useful addition. I don't really want to repeat the same nearly identical code on seven pages; instead, I've created two examples — one to cover Element.x and one to cover Window.x, and just shown the pertinent bits on each page.

I will update the example description on each page to match the changes I've made to the example repo before passing this back to you again.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK; descriptions and code snippets updated as per the dom-examples changes.

```

The code not relevant to `scroll()` is not shown, for brevity.

#### Result

Click the buttons to see the scrolling behavior. Note how the toolbar fades out when a button is pressed, and fades in again once the smooth scrolling is finished. Also try pressing one button and then quickly pressing another button before the first scrolling operation has finished. Note how, in these cases, the scrolling is reported as interrupted.

{{EmbedGHLiveSample("dom-examples/scroll-promises/element-methods/", "100%", 620)}}

You can also [load the demo in a separate tab](https://mdn.github.io/dom-examples/scroll-promises/element-methods/) and view the [source code](https://github.com/mdn/dom-examples/tree/main/scroll-promises/element-methods).

#### Aside on feature detection

If you run this example in a browser that doesn't support promise-returning scroll operations, the scroll operations are still smooth, but the toolbar doesn't fade out and then fade back in once the operation is finished. The feature detection is handled by a function called `supportsScrollPromises()`, which runs a scroll operation and tests whether its return value is a promise:

```js
function supportsScrollPromises() {
const test = section.scroll(0, 0);
return test instanceof Promise;
}
```

Check out the [source code](https://github.com/mdn/dom-examples/blob/main/scroll-promises/element-methods/index.js) to see how the feature detection is used.

## Specifications

{{Specifications}}
Expand Down
149 changes: 138 additions & 11 deletions files/en-us/web/api/element/scrollby/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ browser-compat: api.Element.scrollBy

{{APIRef("CSSOM view API")}}

The **`scrollBy()`** method of the {{domxref("Element")}}
interface scrolls an element by the given amount.
The **`scrollBy()`** method of the {{domxref("Element")}} interface scrolls an element by the given amount.

## Syntax

Expand All @@ -21,29 +20,34 @@ scrollBy(options)
### Parameters

- `xCoord`
- : The horizontal pixel value that you want to
scroll by.
- : The horizontal pixel value that you want to scroll by.
- `yCoord`
- : The vertical pixel value that you want to scroll
by.
- : The vertical pixel value that you want to scroll by.
- `options`
- : An object containing the following properties:
- `top`
- `top` {{optional_inline}}
- : Specifies the number of pixels along the Y axis to scroll the window or element.
- `left`
- `left` {{optional_inline}}
- : Specifies the number of pixels along the X axis to scroll the window or element.
- `behavior`
- : Determines whether the scrolling is instant or animates smoothly. This option is a string that must take one of the following values:
- `behavior` {{optional_inline}}
- : Determines whether scrolling is instant or animates smoothly. This option is a string that must take one of the following values:
- `smooth`: The scrolling animates smoothly.
- `instant`: The scrolling happens instantly in a single jump.
- `auto`: The scroll behavior is determined by the computed value of the {{cssxref("scroll-behavior")}} CSS property on the element.

If omitted, `behavior` defaults to `auto`.

### Return value

None ({{jsxref("undefined")}}).
A {{jsxref("Promise")}} that fulfills with an object containing the following property:

- `interrupted`
- : A boolean value indicating whether the scrolling operation was interrupted (`true`) or not (`false`). Such an interruption typically happens when a programmatic scroll is ongoing, and another programmatic scroll is initiated on the same element before the first one finishes.

## Examples

### Basic usage

```js
// scroll an element
element.scrollBy(300, 300);
Expand All @@ -59,6 +63,129 @@ element.scrollBy({
});
```

### Responding to the end of the scroll

Our [element methods demo](https://mdn.github.io/dom-examples/scroll-promises/element-methods/) ([see source code](https://github.com/mdn/dom-examples/tree/main/scroll-promises/element-methods)) demonstrates how the promise return value of `scrollBy()` can be used to respond to the end of a scrolling operation. This technique is mostly useful in cases where the scrolling occurs smoothly over time (achieved by setting the [`behavior`](#behavior) option to `smooth`, or by setting the scrolling element's {{cssxref("scroll-behavior")}} property to `smooth`).

#### HTML

Our HTML includes a {{htmlelement("section")}} element containing several paragraphs of content and a {{htmlelement("div")}} element toolbar containing {{htmlelement("button")}} elements that trigger various scrolling operations on the `<section>`.

```html
<div>
<button class="scroll">scroll() to 1000</button>
<button class="scrollto">scrollTo() top</button>
<button class="scrollby">scrollBy() 200</button>
<button class="scrollintoview">Scroll last &lt;p&gt; into view</button>
</div>

<section>...</section>
```

#### CSS

We give the `<section>` element a fixed {{cssxref("height")}} and an {{cssxref("overflow-y")}} value of `scroll` so that it scrolls vertically, and set its {{cssxref("scroll-behavior")}} property to `smooth` so that any scroll operations are animated smoothly over time rather than instantly.

```css
section {
border: 1px solid black;
padding: 20px;
margin-top: 60px;
height: 500px;
overflow-y: scroll;
scroll-behavior: smooth;
}
```

We also create two class selectors; when a `fade-out` or `fade-in` class is applied to an element, an {{cssxref("animation")}} is applied so that it smoothly fades out or in, respectively. We also define {{cssxref("@keyframes")}} blocks to define the required {{cssxref("opacity")}} changes for those animations.

```css
.fade-out {
animation: fade-out 0.3s linear both;
}

.fade-in {
animation: fade-in 0.3s linear both;
}

@keyframes fade-out {
from {
opacity: 1;
}

to {
opacity: 0;
}
}

@keyframes fade-in {
from {
opacity: 0;
}

to {
opacity: 1;
}
}
```

The rest of the CSS is not shown, for brevity.

#### JavaScript

We start by grabbing references to the `<button>` that runs the `scrollBy()` operation, the toolbar `<div>`, and the scrolling `<section>`:

```js
const scrollByBtn = document.querySelector(".scrollby");
const toolbar = document.querySelector("div");
const section = document.querySelector("section");
```

Next, we define a function called `isInterrupted()`, designed to run in response to a scroll operation finishing, which takes a boolean `interrupted` value as a parameter. It logs a message to the console to say that scrolling is finished and indicate whether the operation was interrupted (`interrupted` is `true`) or not. In addition, if `interrupted` is `true`, it calls an `alert()` to clearly indicate the interruption.

```js
function isInterrupted(interrupted) {
console.log(`Scroll finished;${interrupted ? " " : " not "}interrupted`);
if (interrupted) {
alert("Scroll interrupted!");
}
}
```

When the button is clicked, we immediately apply the `fade-out` class to the toolbar, causing it to fade out. We then run `scrollBy(0, 200)` on the `<section>` to scroll its content down by 200 pixels, `await`ing its promise resolution as we do so and storing the `result` in a constant. When the promise has resolved, we call `isInterrupted()` to report that the scroll operation has finished and whether it was interrupted. Finally, we apply the `fade-in` class to the toolbar, causing it to fade back in again.

```js
scrollByBtn.addEventListener("click", async () => {
toolbar.className = "fade-out";
const result = await section.scrollBy(0, 200);
isInterrupted(result.interrupted);
toolbar.className = "fade-in";
});
```

The code not relevant to `scrollBy()` is not shown, for brevity.

#### Result

Click the buttons to see the scrolling behavior. Note how the toolbar fades out when a button is pressed, and fades in again once the smooth scrolling is finished. Also try pressing one button and then quickly pressing another button before the first scrolling operation has finished. Note how, in these cases, the scrolling is reported as interrupted.

{{EmbedGHLiveSample("dom-examples/scroll-promises/element-methods/", "100%", 620)}}

You can also [load the demo in a separate tab](https://mdn.github.io/dom-examples/scroll-promises/element-methods/) and view the [source code](https://github.com/mdn/dom-examples/tree/main/scroll-promises/element-methods).

#### Aside on feature detection

If you run this example in a browser that doesn't support promise-returning scroll operations, the scroll operations are still smooth, but the toolbar doesn't fade out and then fade back in once the operation is finished. The feature detection is handled by a function called `supportsScrollPromises()`, which runs a scroll operation and tests whether its return value is a promise:

```js
function supportsScrollPromises() {
const test = section.scroll(0, 0);
return test instanceof Promise;
}
```

Check out the [source code](https://github.com/mdn/dom-examples/blob/main/scroll-promises/element-methods/index.js) to see how the feature detection is used.

## Specifications

{{Specifications}}
Expand Down
Loading