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
						
					
					
				| # `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,
 | |
| }
 | |
| */
 | |
| ```
 |