You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					291 lines
				
				6.0 KiB
			
		
		
			
		
	
	
					291 lines
				
				6.0 KiB
			| 
											3 years ago
										 | # `css-box-model` 📦
 | ||
|  | 
 | ||
|  | Get accurate and well named [CSS Box Model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model) information about a [`Element`](https://developer.mozilla.org/en-US/docs/Web/API/Element). | ||
|  | 
 | ||
|  | [](https://travis-ci.org/alexreardon/css-box-model) | ||
|  | [](https://www.npmjs.com/package/css-box-model) | ||
|  | [](https://david-dm.org/alexreardon/css-box-model) | ||
|  | [](https://www.npmjs.com/package/css-box-model) | ||
|  | [](https://www.npmjs.com/package/css-box-model) | ||
|  | [](https://www.npmjs.com/package/css-box-model) | ||
|  | 
 | ||
|  | Any time you are using [`Element.getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) you might want to consider using `css-box-model` instead to get more detailed box model information. | ||
|  | 
 | ||
|  | ## Usage
 | ||
|  | 
 | ||
|  | ```js | ||
|  | // @flow | ||
|  | import { getBox } from 'css-box-model'; | ||
|  | 
 | ||
|  | const el: HTMLElement = document.getElementById('foo'); | ||
|  | const box: BoxModel = getBox(el); | ||
|  | 
 | ||
|  | // profit | ||
|  | ``` | ||
|  | 
 | ||
|  | ## Installation
 | ||
|  | 
 | ||
|  | ```bash | ||
|  | ## yarn
 | ||
|  | yarn add css-box-model | ||
|  | 
 | ||
|  | # npm
 | ||
|  | npm install css-box-model --save | ||
|  | ``` | ||
|  | 
 | ||
|  | ## The [CSS Box Model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model)
 | ||
|  | 
 | ||
|  |  | ||
|  | 
 | ||
|  | | Box type    | Composition                         | | ||
|  | | ----------- | ----------------------------------- | | ||
|  | | Margin box  | margin + border + padding + content | | ||
|  | | Border box  | border + padding + content          | | ||
|  | | Padding box | padding + content                   | | ||
|  | | Content box | content                             | | ||
|  | 
 | ||
|  | This our returned `BoxModel`: | ||
|  | 
 | ||
|  | ```js | ||
|  | export type BoxModel = {| | ||
|  |   // content + padding + border + margin | ||
|  |   marginBox: Rect, | ||
|  |   // content + padding + border | ||
|  |   borderBox: Rect, | ||
|  |   // content + padding | ||
|  |   paddingBox: Rect, | ||
|  |   // content | ||
|  |   contentBox: Rect, | ||
|  |   // for your own consumption | ||
|  |   border: Spacing, | ||
|  |   padding: Spacing, | ||
|  |   margin: Spacing, | ||
|  | |}; | ||
|  | 
 | ||
|  | // Supporting types | ||
|  | 
 | ||
|  | // This is an extension of DOMRect and ClientRect | ||
|  | export type Rect = {| | ||
|  |   // ClientRect | ||
|  |   top: number, | ||
|  |   right: number, | ||
|  |   bottom: number, | ||
|  |   left: number, | ||
|  |   width: number, | ||
|  |   height: number, | ||
|  |   // DOMRect | ||
|  |   x: number, | ||
|  |   y: number, | ||
|  |   // Rect | ||
|  |   center: Position, | ||
|  | |}; | ||
|  | 
 | ||
|  | export type Position = {| | ||
|  |   x: number, | ||
|  |   y: number, | ||
|  | |}; | ||
|  | 
 | ||
|  | export type Spacing = { | ||
|  |   top: number, | ||
|  |   right: number, | ||
|  |   bottom: number, | ||
|  |   left: number, | ||
|  | }; | ||
|  | ``` | ||
|  | 
 | ||
|  | ## API
 | ||
|  | 
 | ||
|  | ### `getBox`
 | ||
|  | 
 | ||
|  | > (el: HTMLElement) => BoxModel
 | ||
|  | 
 | ||
|  | Use `getBox` to return the box model for an element | ||
|  | 
 | ||
|  | ### `withScroll`
 | ||
|  | 
 | ||
|  | > `(original: BoxModel, scroll?: Position = getWindowScroll()) => BoxModel`
 | ||
|  | 
 | ||
|  | This is useful if you want to know the box model for an element relative to a page | ||
|  | 
 | ||
|  | ```js | ||
|  | const el: HTMLElement = document.getElementById('app'); | ||
|  | const box: BoxModel = getBox(el); | ||
|  | const withScroll: BoxModel = withScroll(box); | ||
|  | ``` | ||
|  | 
 | ||
|  | You are welcome to pass in your own `scroll`. By default we we use the window scroll: | ||
|  | 
 | ||
|  | ```js | ||
|  | const getWindowScroll = (): Position => ({ | ||
|  |   x: window.pageXOffset, | ||
|  |   y: window.pageYOffset, | ||
|  | }); | ||
|  | ``` | ||
|  | 
 | ||
|  | ### `calculateBox`
 | ||
|  | 
 | ||
|  | > `(borderBox: AnyRectType, styles: CSSStyleDeclaration) => BoxModel`
 | ||
|  | 
 | ||
|  | This will do the box model calculations without needing to read from the DOM. This is useful if you have already got a `ClientRect` / `DOMRect` and a `CSSStyleDeclaration` as then we can skip computing these values. | ||
|  | 
 | ||
|  | ```js | ||
|  | const el: HTMLElement = document.getElementById('app'); | ||
|  | const borderBox: ClientRect = el.getBoundingClientRect(); | ||
|  | const styles: CSSStyleDeclaration = window.getComputedStyles(el); | ||
|  | 
 | ||
|  | const box: BoxModel = calculateBox(borderBox, styles); | ||
|  | ``` | ||
|  | 
 | ||
|  | **`AnyRectType`** allows for simple interoperability with any rect type | ||
|  | 
 | ||
|  | ```js | ||
|  | type AnyRectType = ClientRect | DOMRect | Rect | Spacing; | ||
|  | ``` | ||
|  | 
 | ||
|  | ### `createBox`
 | ||
|  | 
 | ||
|  | > `({ borderBox, margin, border, padding }: CreateBoxArgs) => BoxModel`
 | ||
|  | 
 | ||
|  | Allows you to create a `BoxModel` by passing in a `Rect` like shape (`AnyRectType`) and optionally your own `margin`, `border` and or `padding`. | ||
|  | 
 | ||
|  | ```js | ||
|  | type CreateBoxArgs = {| | ||
|  |   borderBox: AnyRectType, | ||
|  |   margin?: Spacing, | ||
|  |   border?: Spacing, | ||
|  |   padding?: Spacing, | ||
|  | |}; | ||
|  | ``` | ||
|  | 
 | ||
|  | ```js | ||
|  | const borderBox: Spacing = { | ||
|  |   top: 10, | ||
|  |   right: 100, | ||
|  |   left: 20, | ||
|  |   bottom: 80, | ||
|  | }; | ||
|  | const padding: Spacing = { | ||
|  |   top: 10, | ||
|  |   right: 20, | ||
|  |   left: 20, | ||
|  |   bottom: 10, | ||
|  | }; | ||
|  | 
 | ||
|  | const box: BoxModel = createBox({ borderBox, padding }); | ||
|  | ``` | ||
|  | 
 | ||
|  | ## Utility API
 | ||
|  | 
 | ||
|  | > Functions to help you interact with the objects we provide
 | ||
|  | 
 | ||
|  | ### `getRect`
 | ||
|  | 
 | ||
|  | > `(spacing: AnyRectType) => Rect`
 | ||
|  | 
 | ||
|  | Given any `Rect` like shape, return a `Rect`. Accepts any object that has `top`, `right`, `bottom` and `right` (eg `ClientRect`, `DOMRect`); | ||
|  | 
 | ||
|  | ```js | ||
|  | const spacing: Spacing = { | ||
|  |   top: 0, | ||
|  |   right: 100, | ||
|  |   bottom: 50, | ||
|  |   left: 50, | ||
|  | }; | ||
|  | 
 | ||
|  | const rect: Rect = getRect(spacing); | ||
|  | 
 | ||
|  | console.log(rect); | ||
|  | 
 | ||
|  | /* | ||
|  | { | ||
|  |   top: 0, | ||
|  |   right: 100, | ||
|  |   bottom: 50, | ||
|  |   left: 50, | ||
|  |   width: 100, | ||
|  |   height: 50, | ||
|  |   x: 0, | ||
|  |   y: 0, | ||
|  |   center: { x: 50, y: 50 }, | ||
|  | } | ||
|  | */ | ||
|  | ``` | ||
|  | 
 | ||
|  | ### `expand`
 | ||
|  | 
 | ||
|  | Used to expand a `Spacing` | ||
|  | 
 | ||
|  | ```js | ||
|  | (target: Spacing, expandBy: Spacing) => Spacing; | ||
|  | ``` | ||
|  | 
 | ||
|  | ```js | ||
|  | const original: Spacing = { | ||
|  |   top: 10, | ||
|  |   left: 11, | ||
|  |   right: 21, | ||
|  |   bottom: 22, | ||
|  | }; | ||
|  | 
 | ||
|  | const expandBy: Spacing = { | ||
|  |   top: 1, | ||
|  |   left: 2, | ||
|  |   right: 3, | ||
|  |   bottom: 4, | ||
|  | }; | ||
|  | 
 | ||
|  | const expanded: Spacing = expand(original, expandBy); | ||
|  | 
 | ||
|  | console.log(expanded); | ||
|  | 
 | ||
|  | /* | ||
|  | { | ||
|  |   // pulled back | ||
|  |   top: 8, | ||
|  |   left: 8 | ||
|  |   // pushed forward | ||
|  |   bottom: 22, | ||
|  |   right: 22, | ||
|  | } | ||
|  | */ | ||
|  | ``` | ||
|  | 
 | ||
|  | ### `shrink`
 | ||
|  | 
 | ||
|  | Used to shrink a `Spacing` | ||
|  | 
 | ||
|  | ```js | ||
|  | (target: Spacing, shrinkBy: Spacing) => Spacing; | ||
|  | ``` | ||
|  | 
 | ||
|  | ```js | ||
|  | const original: Spacing = { | ||
|  |   top: 10, | ||
|  |   left: 10, | ||
|  |   right: 20, | ||
|  |   bottom: 20, | ||
|  | }; | ||
|  | 
 | ||
|  | const shrinkBy: Spacing = { | ||
|  |   top: 2, | ||
|  |   left: 2, | ||
|  |   right: 2, | ||
|  |   bottom: 2, | ||
|  | }; | ||
|  | 
 | ||
|  | const smaller: Spacing = shrink(original, shrinkBy); | ||
|  | 
 | ||
|  | console.log(smaller); | ||
|  | 
 | ||
|  | /* | ||
|  | { | ||
|  |   // pushed forward | ||
|  |   top: 12, | ||
|  |   left: 12 | ||
|  |   // pulled back | ||
|  |   bottom: 18, | ||
|  |   right: 18, | ||
|  | } | ||
|  | */ | ||
|  | ``` |