Styles and classes, getComputedStyle

  1. className
  2. style
    1. cssText
    2. Reading the style
  3. getComputedStyle and currentStyle
  4. Summary

This section is about reading and changing the view of an element.

Please make sure you are familiar with CSS Box Model before reading it. Knowing what is a padding, margins, a border is a prerequirement.

className

The className property is always synchronized with the class attribute.

The following example demonstrates it:

<body class="class1 class2">
<script>
  alert(document.body.className)
  document.body.className += ' class3'
</script>
</body>

To remove a single class, it is extracted from the string either by replace function or after splitting it by whitespaces and then joining back.

All JavaScript frameworks contain built-in functions for such job.

style

The style property gives a read-write access to the element style.

It is possible to change most CSS properties using it, e.g element.style.width='100px' will act as if element had a style="width:100px" attribute.

And, same as in CSS, you need to supply the measurements: ‘px’, ‘pt’, ‘%’ or ‘em’.

For a-multi-word-property, you need to camelCase it:

background-color  => backgroundColor
z-index           => zIndex
border-left-width => borderLeftWidth

The value of style always overrides CSS properties, so you can change it and then revert the change by assigning empty string: elem.style.width='' will remove width setting.

Using the style property is demonstrated in the example below:

// enter an empty value to reset the color
document.body.style.backgroundColor = prompt('background color?', 'green')

Browser-specific style properties like -moz-border-radius, -webkit-border-radius are assigned like this:

button.style.MozBorderRadius = '5px'
button.style.WebkitBorderRadius = '5px'

Of course, it is much better to leave them in classes and decorate elements by adding/removing them in elem.className.

cssText

The style.cssText property allows to read/write whole declaration:

<div>Button</div>

<script>
  var div = document.body.children[0]
 
  div.style.cssText='*!*color: red !important;*/!* \
    background-color: yellow; \
    width: 100px; \
    text-align: center; \
    *!*blabla: 5; \*/!*
  '

  alert(div.style.cssText)
</script>

Browser parses cssText and applies what it knows. There are no exceptions on writing unknown property blabla, so most browsers ignore it.

In the example above, reading cssText does not show property blabla in Firefox.

style.cssText is the only way to add !important.

Reading the style

The style gives access only to properties set through it, or with "style" attribute.

So, in the example below, an attempt to get marginTop will be unsuccessful:

<style>
  body { margin: 10px }
</style>
<body>
  <script> 
    alert(document.body.style.marginTop) 
  </script>
</body>

That’s because margin is a result of applying CSS cascade, not style.

If you’ve set it with style then reading it works:

<style>
  body { margin: 10px }
</style>
<body>
  <script> 
    document.body.style.margin = '20px'
    alert(document.body.style.marginTop) 
  </script>
</body>

Note from the example above how browser unpacks margin property, providing readable subproperties. Same happens with border, background etc.

In the example below, color is shown as rgb(...) in Firefox:

<body style="color:#abc">
  <script> 
    alert(document.body.style.color)  // rgb(170, 187, 204)
  </script>
</body>

The following tasks shows most often-used style properties.

Take the document at tutorial/browser/dom/roundedButton/source.html and create the <A> link with given style by pure JavaScript, without any HTML tags at all:

<!DOCTYPE HTML>
<html>
<head>
<style>
.button {
  -moz-border-radius: 8px;
  -webkit-border-radius: 8px;
  border-radius: 8px;
  border: 2px groove green;
  display: block;
  height: 30px;
  line-height: 30px;
  width: 100px;
  text-decoration: none;
  text-align: center;
  color: red;
  font-weight: bold;
}
</style>
</head>
<body>

<a class="button" href="/">Click me</a>

</body>
</html>
Open the code in new window

Also, check yourself: remember what each style property means, describe why it is here.

Open solution
Solution

There are two variants.

  1. Use elem.style.cssText property to assign the textual style. That will overwrite all existing style properties.
  2. Use elem.style subproperties to assign style items one-by-one. That changes only style properties which get assigned.

The solution follows the second way: tutorial/browser/dom/roundedButton/solution.html.

CSS properties:

.button {
  -moz-border-radius: 8px;
  -webkit-border-radius: 8px;
  border-radius: 8px;
  border: 2px groove green;
  display: block;
  height: 30px;
  line-height: 30px;
  width: 100px;
  text-decoration: none;
  text-align: center;
  color: red;
  font-weight: bold;
}

*-border-radius, border
Adds rounded corners for Mozilla, Chrome/Safari and other standard-compliant browsers (Opera).
display
By default, the A has display: inline.
height, line-height
Sets element height and makes the text vertical-centered. Vertical centering with line-height = height works for single line.
text-align
Centers the text horizontally.
color, font-weight
Makes the text red and bold.

Don’t assign style properties directly until you know that can’t be done with CSS classes, or classes are inconvenient (rarely, but happens).

In the example above, probably only few properties (depending on the application) are to be handled by JavaScript. Most of them should reside in a class, which JavaScript adds.

getComputedStyle and currentStyle

The style gives access only to information which is put into elem.style

In the example below, style doesn’t tell anything about the margin defined in CSS:

<style>
  body { margin: 10px }
</style>
<body>

  <script> 
    alert(document.body.style.marginTop) 
  </script>

</body>

For example, we want to introduce animation and smoothly increment the margin by 10px more. How to do it? First, we need to get the current value.

To read the actual property after CSS and styles are applied, the DOM Level 2 standard describes window.getComputedStyle method.

The syntax is:

getComputedStyle(element, pseudo)

element
The element to get a styling for
pseudo
A pseudo-selector like ‘hover’ or null if not needed.

All browsers excepts IE<9 support it. The following code will work as it should in all non-IE:

<style>
  body { margin: 10px }
</style>
<body>

  <script> 
    var computedStyle = getComputedStyle(document.body, null)
    alert(computedStyle.marginTop) 
  </script>

</body>

And for IE, there is a proprietary currentStyle property which is almost same.

The pitfall is that currentStyle returns value ‘as-is’, in measurements from CSS, not in pixels.
Let’s demonstrate this:

<style>
  body { margin: 10% }
</style>
<body>
  <script> 
    if (window.getComputedStyle) {
      var computedStyle = getComputedStyle(document.body, null)
    } else {
      computedStyle = document.body.currentStyle
    }
    alert(computedStyle.marginTop) 
  </script>
</body>

  1. In Firefox, pixels may be fractional.
  2. Other browsers round pixels.
  3. IE keeps the units. The example above gives percents.

If you have values in pixels, then IE behaves same as other browsers.

IE: converting `pt,em,%` to pixels

Sometimes the CSS is given in other units than pixels, like percents or em. And we need pixels to perform calculations, just because it is impossible to sum 10px and 10%.

To get a real pixel value out of percents, there exists a runtimeStyle+pixel, described by Dean Edwards here.

It is based on IE-only properties runtimeStyle and pixelLeft.

In the example below, the getCurrentPixelStyle(elem, prop) gets a pixel value for elem.currentStyle property prop.

If you are interested to know how it works, read the code carefully and check runtimeStyle and pixelLeft properties in MSDN.

function getCurrentPixelStyle(elem, prop) {
  var value = elem.currentStyle[prop] || 0

  // we use 'left' property as a place holder so backup values
  var leftCopy = elem.style.left
  var runtimeLeftCopy = elem.runtimeStyle.left

  // assign to runtimeStyle and get pixel value
  elem.runtimeStyle.left = elem.currentStyle.left
  elem.style.left = (prop === "fontSize") ? "1em" : value
  value = elem.style.pixelLeft + "px";

  // restore values for left
  elem.style.left = leftCopy 
  elem.runtimeStyle.left = runtimeLeftCopy 
 
  return value
}

The function is in action below (IE only):
<style> #margin-test { margin: 1% } </style>
<div id="margin-test">margin test</div>

<script>
  var elem = document.getElementById('margin-test')
  if (elem.currentStyle) // IE
    document.write(getCurrentPixelStyle(elem, 'marginTop')) 
  else 
    document.write('Open the page in IE please')
</script>
margin test

Modern JavaScript frameworks use it or it’s variant for IE and getComputedStyle for browsers which have it.

Summary

All DOM elements provide the following properties.

  • The className property is always synchronized with the class attribute.
  • The style property is an object with camelCased CSS properties. It works good for writing. It allows to read properties, set by style, but not the properties defined in CSS.
  • The cssText allows to get/set the full value for style in text form. You can’t add !important with style property. With cssText - you can.
  • The currentStyle property (IE) and getComputedStyle (standard) method allow to get the live value of the style property, after all styles are applied.

    Special notes:

    1. Firefox may return a fractional value.
    2. IE returns value in given units, not translates it to pixels. But there is a function which can do it.

Tutorial

Donate

Donate to this project