> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/browser/dom/type/element/+boxes.md).

# Element+boxes

[browser](/web/browser.md) ⟩ [DOM](/web/browser/dom.md) ⟩ [type](/web/browser/dom/type.md) ⟩ [Element](/web/browser/dom/type/element.md) ⟩ +boxes&#x20;

{% hint style="success" %}
extend [Element](/web/browser/dom/type/element.md) with various [**box models**](/web/browser/dom/type/element/boxes.md).

* [.paddingBox](/web/browser/dom/type/element/+boxes/padding.md) = <mark style="color:yellow;">**content**</mark> + <mark style="color:orange;">**padding**</mark>
* [.borderBox](/web/browser/dom/type/element/+boxes/border.md) = <mark style="color:yellow;">**content**</mark> + <mark style="color:orange;">**padding**</mark> + <mark style="color:blue;">**border**</mark> (+ <mark style="color:red;">**scrollbars**</mark>, if present)\
  (a [**Rect**](/web/appendix/custom/class/rect.md) relative to .[offsetParent](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent))
* [.boundingBox](/web/browser/dom/type/element/+boxes/bounding.md) - a [**Rect**](/web/appendix/custom/class/rect.md) relative to [**viewport**](/web/browser/dom/type/window/viewport.md).
* [.scrollBox](/web/browser/dom/type/element/+boxes/scroll.md) = <mark style="color:yellow;">**content**</mark> + <mark style="color:orange;">**padding**</mark> + <mark style="color:red;">**overflow**</mark>
* [viewport](/web/browser/dom/type/window/viewport.md)

:point\_right: [custom](/web/appendix/custom.md)
{% endhint %}

{% tabs %}
{% tab title="🗺️ 圖表" %}
:point\_right: compare： [mouse event](/web/browser/event/type/mouse.md), [elem.position()](/web/browser/dom/type/element/+ext/elem.position.md)

<img src="/files/oFVthbeFxo3ypJh09YQD" alt="Element+boxes" class="gitbook-drawing">
{% endtab %}

{% tab title="💾 程式" %}

* replit ⟩ [various boxes](https://replit.com/@pegasusroe/docviewport-size-2#script.js) ,  require -> [Rect](/web/appendix/custom/class/rect.md)

```javascript
// 2023.01.18 - 16:30 (+) ._box (refactor), .toString(), viewport
// 2023.01.17 - 21:09 (•) first draft
// -----------------------------------------------

const {log} = console;

// ⭐️ import
import {rect} from './Rect.js';       // 👔 Rect
// -----------------------------------------------

// ⭐️ viewport
// -----------------------------------------------
// .size, .width, .height
// .origin, .x, .y
// -----------------------------------------------
// .toString()
//
const viewport = {

    // private
    get _box() {
        const {scrollX: x, scrollY: y} = window;
        const {innerWidth: w, innerHeight: h} = window;
        return rect(x, y, w, h);              // 👔 Rect
    },
    
    // 🔸 .size
    get size() { return this._box.size },
    get width() { return this.size.width },   // .width
    get height() { return this.size.height }, // .height
    
    // 🔸 .origin (relative to document)
    get origin() { return this._box.origin },
    get x() { return this.origin.x },         // .x
    get y() { return this.origin.y },         // .y

    // .toString()
    toString() { return this._box.toString() }
};

// ⭐️ Element + box models
// -----------------------------------------------
// 🔸 .paddingBox     - Rect properties + .info
// 🔸 .borderBox      - Rect properties + .info
// 🔸 .boundingBox    - Rect properties + .info
// 🔸 .scrollBox
//
Object.defineProperties(Element.prototype, {
    
    // 🔸 .paddingBox
    paddingBox: {        
        get() {
            const {clientLeft: x, clientTop: y} = this;
            const {clientWidth: width, clientHeight: height} = this;
            const box = rect(x, y, width, height);        // 👔 Rect
            
            box.info = [
                `🔲 padding box`,
                `---------------`,
                `• size: ${box.size}`,
                `  (❗ inline elements / elements with no CSS: return (0,0))`,
                `• origin: ${box.origin}`,
                `  (⭐️ relative to its "border box")`,
                `  (❗ inline elements (like <i>, <code> ...): return (0,0))`,
            ].join('\n');
            
            return box;
        },
    },

    // 🔸 .borderBox
    borderBox: {
        get() {
            
            const {offsetLeft: x, offsetTop: y} = this;
            const {offsetWidth: width, offsetHeight: height} = this;
            const box = rect(x, y, width, height);        // 👔 Rect
            
            box.info = [
                `🔲 border box`,
                `---------------`,
                `• size: ${box.size}`,
                `• origin: ${box.origin}`,
                `  (⭐️ relative to its "offsetParent")`,
                `• offsetParent: ${this.offsetParent ?. nodeName ?? 'null'}`,
                `  (❗ returns "null" if the element: )`,
                `    • display : none (or its parent)`,
                `    • position: fixed`,
                `    • is <html> or <body>`,
            ].join('\n');
            
            return box;
        },
    },

    // 🔸 .boundingBox
    boundingBox: {
        get() {
            
            const {x, y, width, height} = this.getBoundingClientRect();
            const box = rect(x, y, width, height);        // 👔 Rect
            
            box.info = [
                `🔲 bounding box`,
                `----------------`,
                `• size: ${box.size}`,
                `• origin: ${box.origin}`,
                `  (⭐️ relative to the "viewport")`,
            ].join('\n');
            
            return box;
        },
    },

    // 🔸 .scrollBox
    scrollBox: {
        get() { 
            
            const {scrollLeft: x, scrollTop: y} = this;
            const {scrollWidth: width, scrollHeight: height} = this;
            const box = rect(x, y, width, height);        // 👔 Rect
            
            box.info = [
                `🔲 scroll box`,
                `----------------`,
                `• size: ${box.size}`,
                `  (= padding box size, if no overflow.)`,
                `• origin: ${box.origin}`,
                `  (⭐️ relative to its "origin", = (0,0) if it can't scroll.)`,
            ].join('\n');
            
            return box;
        },
    },
    
});

// export
export {viewport};    // ES module export
```

{% endtab %}

{% tab title="👥 相關" %}

* [box models](/web/browser/dom/type/element/boxes.md)
* [viewport](/web/browser/dom/type/window/viewport.md)
* [elem.position()](/web/browser/dom/type/element/+ext/elem.position.md)
* [Window](/web/browser/dom/type/window.md)
  {% endtab %}

{% tab title="💈範例" %}

* [scroll progress](/web/browser/event/type/scroll/scroll-progress.md) - use viewport.
* [scroll me](/web/browser/event/type/scroll/scroll-me.md) - use .paddingBox, .scrollBox.
* [click to move ball](/web/browser/event/type/mouse/click/click-to-move-ball.md)
  {% endtab %}

{% tab title="📗 參考" %}

* [ ] [HTML vs Body: How to Set Width and Height for Full Page Size](https://www.freecodecamp.org/news/html-page-width-height/)
  {% endtab %}

{% tab title="📘 手冊" %}

* [Element](/web/browser/dom/type/element.md) ⟩&#x20;
  * [.clientWidth](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth), [.clientHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight)
  * [.scrollLeft](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft), [.scrollTop](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop), [.scrollTo()](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTo), [.scrollWidth](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollWidth), [.scrollHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight)
* [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement) ⟩ [.offsetParent](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent)
* [Window](/web/browser/dom/type/window.md) ⟩&#x20;
  * .[scrollX](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollX), .[scrollY](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY)&#x20;
    {% endtab %}
    {% endtabs %}

## History

{% tabs %}
{% tab title="idx" %}

```
0: (?) first recorded
```

{% endtab %}

{% tab title="0" %}

```javascript
// ⭐️ viewport
const viewport = {
    // .size
    get size() {
        return vec(innerWidth, innerHeight);
    },
    // .positionInDocument
    get positionInDocument() {
        return vec(scrollX, scrollY);
    }
};

// ⭐️ extending `Element`
// 🔸 .paddingBox
// 🔸 .borderBox
// 🔸 .boundingBox ≈ .borderBox (integer-valued)
// 🔸 .scrollBox
Object.defineProperties(Element.prototype, {
    
    // key = "paddingBox"
    paddingBox: {        
        // access descriptor ()
        get() {
            // save element for future reference
            const elem = this;    
            // return an object
            return {
                // .paddingBox.size (Vector)
                get size() {
                    return vec(elem.clientWidth, elem.clientHeight);
                },
            };
        },
    },

    // key = "borderBox"
    borderBox: {
        // access descriptor
        get() {
            // save element for future reference
            const elem = this;
            // return an object
            return {
                // .borderBox.size (Vector)
                get size() {
                    return vec(elem.offsetWidth, elem.offsetHeight);
                },
                // .borderBox.position()
                position(coordSystem){
                    // #TODO <----------------------- 
                    switch(coordSystem){
                        default: return vec(elem.offsetLeft, elem.offsetTop)
                    }
                }
            };
        },
    },

    // key = "boundingBox"
    boundingBox: {
        // access descriptor
        get() {
            // save element for future reference
            const elem = this;
            // return an object
            return {
                // .boundingBox.size (Vector)
                get size() {
                    const {width, height} = elem.getBoundingClientRect();
                    return vec(width, height);
                },
            };
        },
    },

    // key = "scrollBox"
    scrollBox: {
        // access descriptor
        get() {
            // save element for future reference
            const elem = this;    
            //return an object
            return {
                // .scrollBox.size (Vector)
                get size() {
                    return vec(elem.scrollWidth, elem.scrollHeight);
                },
            };
        },
    },
    
});bo
```

{% endtab %}
{% endtabs %}
