The implementation uses the three different style collection objects. Below is a short description of these and how they can be used.
This property directly reflects the inline style attribute as well as style changes set using scripting in the normal fashion.
<element style="width: 100px" /> element.style.width = "100px";
currentStyle
returns the current cascaded value for the CSS
property. If no inline style attribute is present then global style sheets
dictate the value for this. Properties in this collection are read only.
<style type="text/css"> #my-element { width: 100px; } </style> <script type="text/javascript"> // this will alert "100px" alert(document.getElementById("my-element").currentStyle.width); </script>
Setting the runtime style has the highest priority so this allows you to set the CSS value without changing the inline attribute or the global style sheet. This is very similar to the override style in the DOM Level 2 Style which allows you to override all the styles provided by the document and external style sheets.
The methods that set the width and height are pretty simple. We just add or subtract the padding and borders depending on the box model to use.
function setBorderBoxWidth(n) { element.runtimeStyle.width = Math.max(0, n - getBorderLeftWidth() - getPaddingLeft() - getPaddingRight() - getBorderRightWidth()) + "px"; } function setContentBoxWidth(n) { element.runtimeStyle.width = Math.max(0, n + getBorderLeftWidth() + getPaddingLeft() + getPaddingRight() + getBorderRightWidth()) + "px"; }
The getters for the padding and borders just return the numerical value of
the respective currentStyle
property.
function getBorderWidth(sSide) { if (element.currentStyle["border" + sSide + "Style"] == "none") return 0; var n = parseInt(element.currentStyle["border" + sSide + "Width"]); return n || 0; }
Notice here how we return 0
if the border style is set to
none
. Also notice how the ||
operator is used. The
value NaN
is treated as false
so the second
expression is returned whenever the parsInt
fails.
First we find the box model used by Internet Explorer by default. This can
be found by checking the document.compatMode
.
function getDocumentBoxSizing() { if (doc.compatMode == null || doc.compatMode == "BackCompat") return "border-box"; return "content-box" }
Once we start to setting the box-sizing
on the element it gets a bit
complicated to find the value for this. Internet Explorer allows custom CSS
properties but they are not treated exactly like built in properties. For example
if we use box-sizing
in a style block we need to use
currentStyle["box-sizing"]
but if the user has set the property
using script with style.boxSizing
we will have to use
boxSizing
instead. The next problem is that if we set the property
to ""
we expect the global value to be used instead. The next problem is
that the currenStyle
property is not updated fast enough. This
gives the following (ugly) code to find the box-sizing
.
function getBoxSizing() { var s = element.style; var cs = element.currentStyle if (typeof s.boxSizing != "undefined" && s.boxSizing != "") return s.boxSizing; if (typeof s["box-sizing"] != "undefined" && s["box-sizing"] != "") return s["box-sizing"]; if (typeof cs.boxSizing != "undefined" && cs.boxSizing != "") return cs.boxSizing; if (typeof cs["box-sizing"] != "undefined" && cs["box-sizing"] != "") return cs["box-sizing"]; return getDocumentBoxSizing(); }
The size needs to be updated at load as well as when the CSS changes. At
construction we just call updateBorderBoxWidth
and
updateBorderBoxHeight
but we also add an event listener to the
propertychange
event. This allows us to update the size when the
style
or className
changes.
function updateBorderBoxWidth() { element.runtimeStyle.width = ""; if (getDocumentBoxSizing() == getBoxSizing()) return; var csw = element.currentStyle.width; if (csw != "auto" && csw.indexOf("px") != -1) { if (getBoxSizing() == "border-box") setBorderBoxWidth(parseInt(csw)); else setContentBoxWidth(parseInt(csw)); } }
Notice here that we reset the runtimeStyle
. This is done so
that we can find the runtimeStyle
that the user has set.
function checkPropertyChange() { var pn = event.propertyName; var undef; if (pn == "style.boxSizing" && element.style.boxSizing == "") { element.style.removeAttribute("boxSizing"); element.runtimeStyle.boxSizing = undef; } switch (pn) { case "style.width": case "style.borderLeftWidth": case "style.borderLeftStyle": case "style.borderRightWidth": case "style.borderRightStyle": case "style.paddingLeft": case "style.paddingRight": updateBorderBoxWidth(); break; case "style.height": case "style.borderTopWidth": case "style.borderTopStyle": case "style.borderBottomWidth": case "style.borderBottomStyle": case "style.paddingTop": case "style.paddingBottom": updateBorderBoxHeight(); break; case "className": case "style.boxSizing": updateBorderBoxWidth(); updateBorderBoxHeight(); break; } }
Notice here that in case the boxSizing
is set to ""
we invalidate that property as good as possible.