├── .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 |
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 |
--------------------------------------------------------------------------------