├── .gitignore ├── LICENSE ├── README.md ├── dist └── box-model-inspector.js ├── docs ├── box-model.css └── index.html ├── lib └── index.js ├── package.json └── rollup.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | npm-debug.log 4 | tmp 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Andy Axton 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Box Model Inspector 2 | Devtools style dom node inspector. Highlights the CSS box model just like chrome devtools. Draws a box around a given element highlighting width, height, margin, border & padding. 3 | 4 | Demo: http://a-axton.github.io/box-model-inspector/ 5 | 6 | ##### Caveats 7 | - Expects box-sizing border-box 8 | - Doesn't work well with fixed position elements. It highlights properly but won't stay in the proper position when scrolling. 9 | 10 | ### Installation 11 | #### npm 12 | ```bash 13 | npm install box-model-inspector --save 14 | ``` 15 | #### inline 16 | ```html 17 | 18 | ``` 19 | ### Theming 20 | ```css 21 | * { box-sizing: border-box; } 22 | 23 | /* CONTENT */ 24 | .box-model .content { 25 | background: rgba(109, 238, 245, 0.5); 26 | } 27 | 28 | /* MARGIN */ 29 | .box-model .margin {} 30 | .box-model .marginTop {} 31 | .box-model .marginRight {} 32 | .box-model .marginBottom {} 33 | .box-model .marginLeft {} 34 | .box-model .margin div { 35 | background: rgba(251, 176, 91, 0.65); 36 | } 37 | 38 | /* PADDING */ 39 | .box-model .padding {} 40 | .box-model .paddingTop {} 41 | .box-model .paddingRight {} 42 | .box-model .paddingBottom {} 43 | .box-model .paddingLeft {} 44 | .box-model .padding div { 45 | background: rgba(139, 234, 127, 0.65); 46 | } 47 | 48 | /* BORDER */ 49 | .box-model .border {} 50 | .box-model .borderTop {} 51 | .box-model .borderRight {} 52 | .box-model .borderBottom {} 53 | .box-model .borderLeft {} 54 | .box-model .border div { 55 | background-color: rgba(234, 228, 105, .8); 56 | } 57 | ``` 58 | 59 | ### Sample Usage 60 | ```js 61 | var BoxModelInspector = require('box-model-inspector'); 62 | 63 | // all options are optional 64 | var boxModelInspector = new BoxModelInspector({ 65 | // initial element to highlight 66 | el: document.querySelectorAll('.example')[0], 67 | // custom class, defaults to 'box-model' 68 | className: 'box-model', 69 | // will append to element, uses body as default 70 | appendTo: document.body 71 | }); 72 | 73 | // set new element to be highlighted 74 | document.body.addEventListener('mousemove', function(e) { 75 | boxModelInspector.setElement(e.target); 76 | e.stopPropagation(); 77 | }); 78 | 79 | // refresh dimensions 80 | window.addEventListener('resize', function() { 81 | boxModelInspector.refresh(); 82 | }); 83 | ``` 84 | 85 | ### Methods 86 | #### setElement 87 | ___ 88 | Set new element to highlight 89 | ##### Example 90 | ```js 91 | var el = document.getElementById('el'); 92 | boxModelInspector.setElement(el); 93 | ``` 94 | #### refresh 95 | ___ 96 | Refresh current element's box model 97 | ##### Example 98 | ```js 99 | window.addEventListener('resize', function() { 100 | boxModelInspector.refresh(); 101 | }); 102 | ``` 103 | #### hide 104 | ___ 105 | Hide it 106 | ##### Example 107 | ```js 108 | boxModelInspector.hide(); 109 | ``` 110 | #### show 111 | ___ 112 | Show it 113 | ##### Example 114 | ```js 115 | boxModelInspector.show(); 116 | ``` 117 | 118 | -------------------------------------------------------------------------------- /dist/box-model-inspector.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.BoxModelInspector=e()}(this,function(){"use strict";function t(t){t=t||{},this.el=t.el,this._className=t.className,this._appendTo=t.appendTo,this.el?(this._elComputedStyles=window.getComputedStyle(this.el),this.boxModel=this._buildDomNodes(),this.refresh()):this.boxModel=this._buildDomNodes()}return t.prototype._buildDomNodes=function(){var t;this._parentElement=document.createElement("div");var e='
';return this._parentElement.classList.add(this._className||"box-model"),this._parentElement.innerHTML=e,this._appendTo?this._appendTo.appendChild(this._parentElement):document.body.appendChild(this._parentElement),t=this._buildNodeReferences(this._parentElement.childNodes),t.wrapper.setAttribute("style","position: absolute; pointer-events: none;"),t.content.wrapper.setAttribute("style","position: relative; width: 100%; height: 100%; z-index: 200;"),t.margin.wrapper.setAttribute("style","position: absolute; top: 0; left: 0; z-index: 190;"),t.padding.wrapper.setAttribute("style","position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 195;"),t.border.wrapper.setAttribute("style","position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 195;"),[t.padding,t.margin,t.border].forEach(function(t){for(var e in t)"wrapper"!==e&&t[e].setAttribute("style","position: absolute; background-attachment: fixed;")}),t},t.prototype._buildNodeReferences=function(t,e){for(var i={wrapper:this._parentElement},o=0;o 2 | 3 | 4 | 5 | Javascript Box Model Inspector 6 | 7 | 110 | 111 | 112 | 113 | Fork me on GitHub 114 | 115 |
116 |

Javascript Box Model Inspector

117 |

Chrome and Firefox style box model highlighter

118 |
119 |

Highlight any of these DOM Nodes

120 |
121 |

Highlights margin, padding, border, width & height.

122 |
123 |
124 |

Custom styles

125 |
126 |
127 |

Vanilla Javascript

128 |
129 |
130 | 131 | 132 | 133 |
134 | 135 |
136 | 137 | 138 | 139 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | function BoxModelInspector (options) { 2 | options = options || {}; 3 | this.el = options.el; 4 | this._className = options.className; 5 | this._appendTo = options.appendTo; 6 | 7 | if (this.el) { 8 | this._elComputedStyles = window.getComputedStyle(this.el); 9 | this.boxModel = this._buildDomNodes(); 10 | this.refresh(); 11 | } else { 12 | this.boxModel = this._buildDomNodes(); 13 | } 14 | } 15 | 16 | // renders all required dom objects and appends to body 17 | // returns a reference object containing all node objects 18 | BoxModelInspector.prototype._buildDomNodes = function () { 19 | var nodeReferences; 20 | 21 | this._parentElement = document.createElement('div'); 22 | 23 | var childElements = '
' + 24 | '
' + 25 | '
' + 26 | '
' + 27 | '
' + 28 | '
' + 29 | '
' + 30 | '
' + 31 | '
' + 32 | '
' + 33 | '
' + 34 | '
' + 35 | '
' + 36 | '
' + 37 | '
' + 38 | '
' + 39 | '
' + 40 | '
' + 41 | '
' + 42 | '
'; 43 | 44 | this._parentElement.classList.add(this._className || 'box-model'); 45 | this._parentElement.innerHTML = childElements; 46 | 47 | if (this._appendTo) { 48 | this._appendTo.appendChild(this._parentElement); 49 | } else { 50 | document.body.appendChild(this._parentElement); 51 | } 52 | 53 | nodeReferences = this._buildNodeReferences(this._parentElement.childNodes); 54 | nodeReferences.wrapper.setAttribute('style', 'position: absolute; pointer-events: none;'); 55 | nodeReferences.content.wrapper.setAttribute('style','position: relative; width: 100%; height: 100%; z-index: 200;'); 56 | nodeReferences.margin.wrapper.setAttribute('style','position: absolute; top: 0; left: 0; z-index: 190;'); 57 | nodeReferences.padding.wrapper.setAttribute('style','position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 195;'); 58 | nodeReferences.border.wrapper.setAttribute('style','position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 195;'); 59 | [nodeReferences.padding, nodeReferences.margin, nodeReferences.border].forEach(function(wrapper) { 60 | for (var node in wrapper) { 61 | if (node !== 'wrapper') { 62 | wrapper[node].setAttribute('style','position: absolute; background-attachment: fixed;'); 63 | } 64 | } 65 | }); 66 | 67 | return nodeReferences; 68 | }; 69 | 70 | BoxModelInspector.prototype._buildNodeReferences = function (nodes, parent) { 71 | var nodeRef = { 72 | wrapper: this._parentElement 73 | } 74 | 75 | // loop through dom nodes 76 | for (var i = 0; i < nodes.length; i++) { 77 | var node = nodes[i]; 78 | var children = node.childNodes; 79 | var refEntry; 80 | 81 | if (parent) { 82 | parent[node.classList[0]] = node; 83 | } else if (children) { 84 | refEntry = nodeRef[node.classList[0]] = {}; 85 | refEntry.wrapper = node; 86 | this._buildNodeReferences(children, refEntry); 87 | } 88 | } 89 | 90 | return nodeRef; 91 | }; 92 | 93 | BoxModelInspector.prototype._calculatePadding = function () { 94 | var padding = this.boxModel.padding, 95 | border = this.boxModel.border, 96 | content = this.boxModel.content, 97 | styles = this._elComputedStyles, 98 | elDimensions = this._elDimensions, 99 | borderLeft = parseFloat(styles.borderLeftWidth), 100 | borderRight = parseFloat(styles.borderRightWidth), 101 | borderTop = parseFloat(styles.borderTopWidth), 102 | borderBottom = parseFloat(styles.borderBottomWidth), 103 | paddingLeft = parseFloat(styles.paddingLeft), 104 | paddingRight = parseFloat(styles.paddingRight), 105 | paddingTop = parseFloat(styles.paddingTop), 106 | paddingBottom = parseFloat(styles.paddingBottom); 107 | 108 | content.wrapper.style.width = elDimensions.outerWidth - paddingLeft - paddingRight - borderLeft - borderRight + 'px'; 109 | content.wrapper.style.height = elDimensions.outerHeight - paddingTop - paddingBottom - borderTop - borderBottom + 'px'; 110 | content.wrapper.style.left = paddingLeft + borderLeft + 'px'; 111 | content.wrapper.style.top = paddingTop + borderTop + 'px'; 112 | content.wrapper.style['background-position'] = borderLeft + 'px ' + '0px'; 113 | 114 | border.wrapper.style.width = elDimensions.outerWidth + 'px'; 115 | border.wrapper.style.height = elDimensions.outerHeight + 'px'; 116 | border.wrapper.style.left = '0px'; 117 | border.wrapper.style.top = '0px'; 118 | border.wrapper.style['background-position'] = borderLeft + 'px ' + '0px'; 119 | 120 | padding.wrapper.style.width = elDimensions.outerWidth - borderLeft - borderRight + 'px'; 121 | padding.wrapper.style.height = elDimensions.outerHeight - borderTop - borderBottom + 'px'; 122 | padding.wrapper.style.left = borderLeft + 'px'; 123 | padding.wrapper.style.top = borderTop + 'px'; 124 | padding.wrapper.style['background-position'] = borderLeft + 'px ' + '0px'; 125 | 126 | border.borderTop.style.height = borderTop + 'px'; 127 | border.borderTop.style.width = elDimensions.outerWidth + 'px'; 128 | border.borderTop.style.top = '0px'; 129 | border.borderTop.style.left = '0px'; 130 | 131 | border.borderRight.style.height = elDimensions.outerHeight - borderTop - borderBottom + 'px'; 132 | border.borderRight.style.width = borderRight + 'px'; 133 | border.borderRight.style.top = borderTop + 'px'; 134 | border.borderRight.style.right = '0px'; 135 | 136 | border.borderBottom.style.height = borderBottom + 'px'; 137 | border.borderBottom.style.width = elDimensions.outerWidth + 'px'; 138 | border.borderBottom.style.left = '0px'; 139 | border.borderBottom.style.bottom = '0px'; 140 | 141 | border.borderLeft.style.height = elDimensions.outerHeight - borderTop - borderBottom + 'px'; 142 | border.borderLeft.style.width = borderLeft + 'px'; 143 | border.borderLeft.style.top = borderTop + 'px'; 144 | border.borderLeft.style.left = '0px'; 145 | 146 | padding.paddingTop.style.height = paddingTop + 'px'; 147 | padding.paddingTop.style.width = elDimensions.outerWidth - borderLeft - borderRight + 'px'; 148 | padding.paddingTop.style.top = '0px'; 149 | padding.paddingTop.style.left = '0px'; 150 | 151 | padding.paddingRight.style.height = elDimensions.outerHeight - paddingTop - paddingBottom - borderTop - borderBottom + 'px'; 152 | padding.paddingRight.style.width = paddingRight + 'px'; 153 | padding.paddingRight.style.top = paddingTop + 'px'; 154 | padding.paddingRight.style.right = '0px'; 155 | 156 | padding.paddingBottom.style.height = paddingBottom + 'px'; 157 | padding.paddingBottom.style.width = elDimensions.outerWidth - borderLeft - borderRight + 'px'; 158 | padding.paddingBottom.style.bottom = '0px'; 159 | padding.paddingBottom.style.left = '0px'; 160 | 161 | padding.paddingLeft.style.height = elDimensions.outerHeight - paddingTop - paddingBottom - borderTop - borderBottom + 'px'; 162 | padding.paddingLeft.style.width = paddingLeft + 'px'; 163 | padding.paddingLeft.style.top = paddingTop + 'px'; 164 | padding.paddingLeft.style.left = '0px'; 165 | }; 166 | 167 | BoxModelInspector.prototype._calculateMargin = function () { 168 | var margin = this.boxModel.margin, 169 | styles = this._elComputedStyles, 170 | elDimensions = this._elDimensions, 171 | marginLeft = parseFloat(styles.marginLeft), 172 | marginRight = parseFloat(styles.marginRight), 173 | marginTop = parseFloat(styles.marginTop), 174 | marginBottom = parseFloat(styles.marginBottom); 175 | 176 | margin.wrapper.style.width = elDimensions.outerWidth + marginLeft + marginRight + 'px'; 177 | margin.wrapper.style.height = elDimensions.outerHeight + marginTop + marginBottom + 'px'; 178 | margin.wrapper.style.left = (marginLeft * -1) + 'px'; 179 | margin.wrapper.style.top = (marginTop * -1) + 'px'; 180 | 181 | margin.marginTop.style.height = marginTop + 'px'; 182 | margin.marginTop.style.width = elDimensions.outerWidth + marginLeft + marginRight + 'px'; 183 | 184 | margin.marginRight.style.height = elDimensions.outerHeight + 'px'; 185 | margin.marginRight.style.width = marginRight + 'px'; 186 | margin.marginRight.style.top = marginTop + 'px'; 187 | margin.marginRight.style.right = 0 + 'px'; 188 | 189 | margin.marginBottom.style.height = marginBottom + 'px'; 190 | margin.marginBottom.style.width = elDimensions.outerWidth + marginLeft + marginRight + 'px'; 191 | margin.marginBottom.style.bottom = 0 + 'px'; 192 | 193 | margin.marginLeft.style.height = elDimensions.outerHeight + 'px'; 194 | margin.marginLeft.style.width = marginLeft + 'px'; 195 | margin.marginLeft.style.top = marginTop + 'px'; 196 | }; 197 | 198 | BoxModelInspector.prototype.setElement = function (el) { 199 | this.el = el; 200 | this._elComputedStyles = window.getComputedStyle(el); 201 | this.refresh(); 202 | return this; 203 | }; 204 | 205 | BoxModelInspector.prototype.hide = function () { 206 | this.boxModel.hidden = true; 207 | this.boxModel.wrapper.style.display = 'none'; 208 | return this; 209 | }; 210 | 211 | BoxModelInspector.prototype.show = function () { 212 | this.boxModel.hidden = false; 213 | this.refresh(); 214 | return this; 215 | }; 216 | 217 | BoxModelInspector.prototype.refresh = function () { 218 | if (this.boxModel.hidden) { return; } 219 | var el = this.el; 220 | var elDimensions = { 221 | offset: { 222 | left: el.offsetLeft, 223 | top: el.offsetTop 224 | }, 225 | width: el.clientWidth, 226 | height: el.clientHeight, 227 | outerHeight: el.offsetHeight, 228 | outerWidth: el.offsetWidth 229 | }; 230 | 231 | this._elDimensions = elDimensions; 232 | this.boxModel.wrapper.style.display = 'block'; 233 | this.boxModel.wrapper.style.left = elDimensions.offset.left + 'px'; 234 | this.boxModel.wrapper.style.top = elDimensions.offset.top + 'px'; 235 | this.boxModel.wrapper.style.height = elDimensions.outerHeight + 'px'; 236 | this.boxModel.wrapper.style.width = elDimensions.outerWidth + 'px'; 237 | 238 | this._calculatePadding(); 239 | this._calculateMargin(); 240 | 241 | return this; 242 | }; 243 | 244 | export default BoxModelInspector; 245 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "box-model-inspector", 3 | "version": "1.0.1", 4 | "description": "Devtools style css box model inspector in javascript", 5 | "homepage": "http://a-axton.github.io/box-model-inspector/", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/a-axton/box-model-inspector.git" 9 | }, 10 | "main": "dist/box-model-inspector.js", 11 | "jsnext:main": "lib/index.js", 12 | "scripts": { 13 | "build": "rollup -c" 14 | }, 15 | "keywords": [ 16 | "box model", 17 | "inspector", 18 | "chrome", 19 | "devtools" 20 | ], 21 | "author": "Andy Axton", 22 | "license": "MIT", 23 | "devDependencies": { 24 | "rollup": "^0.36.3", 25 | "rollup-plugin-uglify": "^1.0.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import uglify from 'rollup-plugin-uglify'; 2 | 3 | export default { 4 | entry: 'lib/index.js', 5 | dest: 'dist/box-model-inspector.js', 6 | format: 'umd', 7 | moduleName: 'BoxModelInspector', 8 | plugins: [ 9 | uglify() 10 | ] 11 | } 12 | --------------------------------------------------------------------------------