Стили, getComputedStyle

Эта глава – о свойствах стиля, получении о них информации и изменении при помощи JavaScript.

Перед прочтением убедитесь, что хорошо знакомы с блочной моделью CSS и понимаете, что такое padding, margin, border.

Стили элемента: свойство style

Свойство element.style возвращает объект, который дает доступ к стилю элемента на чтение и запись.

С его помощью можно изменять большинство CSS-свойств, например element.style.width="100px" работает так, как будто у элемента в атрибуте прописано style="width:100px".

Единицы измерения обязательны в style

Об этом иногда забывают, но в style так же, как и в CSS, нужно указывать единицы измерения, например px.

Ни в коем случае не просто elem.style.width = 100 – работать не будет.

Для свойств, названия которых состоят из нескольких слов, используется вотТакаяЗапись:

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

Пример использования style:

document.body.style.backgroundColor = prompt('background color?', 'green');
style.cssFloat вместо style.float

Исключением является свойство float. В старом стандарте JavaScript слово "float" было зарезервировано и недоступно для использования в качестве свойства объекта. Поэтому используется не elem.style.float, а elem.style.cssFloat.

Свойства с префиксами

Специфические свойства браузеров, типа -moz-border-radius, -webkit-border-radius, записываются следующим способом:

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

То есть, каждый дефис даёт большую букву.

Чтобы сбросить поставленный стиль, присваивают в style пустую строку: elem.style.width="".

При сбросе свойства style стиль будет взят из CSS.

Например, для того, чтобы спрятать элемент, можно присвоить: elem.style.display = "none".

А вот чтобы показать его обратно – не обязательно явно указывать другой display, наподобие elem.style.display = "block". Можно просто снять поставленный стиль: elem.style.display = "".

// если запустить этот код, то <body> "мигнёт"
document.body.style.display = "none";

setTimeout(function() {
  document.body.style.display = "";
}, 1000);

Стиль в style находится в формате браузера, а не в том, в котором его присвоили.

Например:

<body>
  <script>
    document.body.style.margin = '20px';
    alert( document.body.style.marginTop ); // 20px!

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

Обратите внимание на то, как браузер «распаковал» свойство style.margin, предоставив для чтения style.marginTop. То же самое произойдет и для border, background и т.д.

Свойство style мы используем лишь там, где не работают классы

В большинстве случаев внешний вид элементов задаётся классами. А JavaScript добавляет или удаляет их. Такой код красив и гибок, дизайн можно легко изменять.

Свойство style нужно использовать лишь там, где классы не подходят, например если точное значение цвета/отступа/высоты вычисляется в JavaScript.

Строка стилей style.cssText

Свойство style является специальным объектом, ему нельзя присваивать строку.

Запись div.style="color:blue" работать не будет. Но как же, всё-таки, поставить свойство стиля, если хочется задать его строкой?

Можно попробовать использовать атрибут: elem.setAttribute("style", ...), но самым правильным и, главное, кросс-браузерным (с учётом старых IE) решением такой задачи будет использование свойства style.cssText.

Свойство style.cssText позволяет поставить стиль целиком в виде строки.

Например:

<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>

Браузер разбирает строку style.cssText и применяет известные ему свойства. Неизвестные, наподобие blabla, большинство браузеров просто проигнорируют.

При установке style.cssText все предыдущие свойства style удаляются.

Итак, style.cssText осуществляет полную перезапись style. Если же нужно заменить какое-то конкретно свойство стиля, то обращаются именно к нему: style.color, style.width и т.п, чтобы не затереть что-то важное по ошибке.

Свойство style.cssText используют, например, для новосозданных элементов, когда старых стилей точно нет.

Чтение стиля из style

Записать в стиль очень просто. А как прочитать?

Например, мы хотим узнать размер, отступы элемента, его цвет… Как это сделать?

Свойство style содержит лишь тот стиль, который указан в атрибуте элемента, без учёта каскада CSS.

Вот так style уже ничего не увидит:

<head>
  <style> body { color: red; margin: 5px } </style>
</head>
<body>

  Красный текст
  <script>
    alert(document.body.style.color); //в большинстве браузеров
    alert(document.body.style.marginTop); //  ничего не выведет
  </script>
</body>

Полный стиль из getComputedStyle

Итак, свойство style дает доступ только к той информации, которая хранится в elem.style.

Он не скажет ничего об отступе, если он появился в результате наложения CSS или встроенных стилей браузера:

А если мы хотим, например, сделать анимацию и плавно увеличивать marginTop от текущего значения? Как нам сделать это? Ведь для начала нам надо это текущее значение получить.

Для того, чтобы получить текущее используемое значение свойства, используется метод window.getComputedStyle, описанный в стандарте DOM Level 2.

Его синтаксис таков:

getComputedStyle(element[, pseudo])
element
Элемент, значения для которого нужно получить
pseudo
Указывается, если нужен стиль псевдо-элемента, например "::before". Пустая строка или отсутствие аргумента означают сам элемент.

Поддерживается всеми браузерами, кроме IE8-. Следующий код будет работать во всех не-IE браузерах и в IE9+:

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

<body>

  <script>
    var computedStyle = getComputedStyle(document.body);
    alert( computedStyle.marginTop ); // выведет отступ в пикселях
    alert( computedStyle.color ); // выведет цвет
  </script>

</body>
Вычисленное (computed) и окончательное (resolved) значения

В CSS есть две концепции:

  1. Вычисленное (computed) значение – это то, которое получено после применения всех правил CSS и CSS-наследования. Например, width: auto или font-size: 125%.
  2. Окончательное (resolved) значение – непосредственно применяемое к элементу. При этом все размеры приводятся к пикселям, например width: 212px или font-size: 16px. В некоторых браузерах пиксели могут быть дробными.

Когда-то getComputedStyle задумывалось для возврата вычисленного значения, но со временем оказалось, что окончательное гораздо удобнее.

Поэтому сейчас в целом все значения возвращаются именно окончательные, кроме некоторых небольших глюков в браузерах, которые постепенно вычищаются.

getComputedStyle требует полное свойство!

Для правильного получения значения нужно указать точное свойство. Например: paddingLeft, marginTop, borderLeftWidth.

При обращении к сокращенному: padding, margin, border – правильный результат не гарантируется.

Действительно, допустим свойства paddingLeft/paddingTop взяты из разных классов CSS. Браузер не обязан объединять их в одно свойство padding. Иногда, в простейших случаях, когда свойство задано сразу целиком, getComputedStyle сработает для сокращённого свойства, но не во всех браузерах.

Например, некоторые браузеры (Chrome) выведут 10px в документе ниже, а некоторые (Firefox) – нет:

<style>
  body {
    margin: 10px;
  }
</style>
<script>
  var style = getComputedStyle(document.body);
  alert( style.margin ); // в Firefox пустая строка
</script>
Стили посещенных ссылок – тайна!

У посещенных ссылок может быть другой цвет, фон, чем у обычных. Это можно поставить в CSS с помощью псевдокласса :visited.

Но getComputedStyle не дает доступ к этой информации, чтобы произвольная страница не могла определить, посещал ли пользователь ту или иную ссылку.

Кроме того, большинство браузеров запрещают применять к :visited CSS-стили, которые могут изменить геометрию элемента, чтобы даже окольным путем нельзя было это понять. В целях безопасности.

currentStyle для IE8-

В IE8- нет getComputedStyle, но у элементов есть свойство currentStyle, которое возвращает вычисленное (computed) значение: уже с учётом CSS-каскада, но не всегда в окончательном формате.

Чтобы код работал и в старых и новых браузерах, обычно пишут кросс-браузерный код, наподобие такого:

function getStyle(elem) {
  return window.getComputedStyle ? getComputedStyle(elem, "") : elem.currentStyle;
}

Если вы откроете такой документ в IE8-, то размеры будут в процентах, а в современных браузерах – в пикселях.

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

<body>
  <script>
    var elem = document.body;

    function getStyle(elem) {
      return window.getComputedStyle ? getComputedStyle(elem, "") : elem.currentStyle;
    }

    var marginTop = getStyle(elem).marginTop;
    alert( marginTop ); // IE8-: 10%, иначе пиксели
  </script>
</body>
IE8-: перевод pt,em,% из currentStyle в пиксели

Эта информация – дополнительная, она не обязательна для освоения.

В IE для того, чтобы получить из процентов реальное значение в пикселях существует метод «runtimeStyle+pixel», описанный Дином Эдвардсом.

Он основан на свойствах runtimeStyle и pixelLeft, работающих только в IE.

В песочнице вы можете найти функцию getIEComputedStyle(elem, prop), которая получает значение в пикселях для свойства prop, используя elem.currentStyle и метод Дина Эдвардса, и пример её применения.

Если вам интересно, как он работает, ознакомьтесь со свойствами с runtimeStyle и pixelLeft в MSDN и раскройте код.

Конечно, это актуально только для IE8- и полифиллов.

Итого

Все DOM-элементы предоставляют следующие свойства.

  • Свойство style – это объект, в котором CSS-свойства пишутся вотТакВот. Чтение и изменение его свойств – это, по сути, работа с компонентами атрибута style.

  • style.cssText – строка стилей для чтения или записи. Аналог полного атрибута style.

  • Свойство currentStyle(IE8-) и метод getComputedStyle (IE9+, стандарт) позволяют получить реальное, применённое сейчас к элементу свойство стиля с учётом CSS-каскада и браузерных стилей по умолчанию.

    При этом currentStyle возвращает значение из CSS, до окончательных вычислений, а getComputedStyle – окончательное, непосредственно применённое к элементу (как правило).

Более полная информация о свойстве style, включающая другие, реже используемые методы работы с ним, доступна в документации.

Задачи

важность: 3

Создайте кнопку в виде элемента <a> с заданным стилем, используя JavaScript.

В примере ниже такая кнопка создана при помощи HTML/CSS. В вашем решении кнопка должна создаваться, настраиваться и добавляться в документ при помощи только JavaScript, без тегов <style> и <a>.

<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>

<a class="button" href="/">Нажми меня</a>

Проверьте себя: вспомните, что означает каждое свойство. В чём состоит эффект его появления здесь?

Открыть песочницу для задачи.

Есть два варианта.

  1. Можно использовать свойство elem.style.cssText и присвоить стиль в текстовом виде. При этом все присвоенные ранее свойства elem.style будут удалены.
  2. Можно назначить подсвойства elem.style одно за другим. Этот способ более безопасен, т.к. меняет только явно присваемые свойства.

Мы выберем второй путь.

Описание CSS-свойств:

.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
Добавляет скругленные углы. Свойство присваивается в вариантах для Firefox -moz-..., Chrome/Safari -webkit-... и стандартное CSS3-свойство для тех, кто его поддерживает (Opera).
display
По умолчанию, у A это свойство имеет значение display: inline.
height, line-height
Устанавливает высоту и делает текст вертикально центрированным путем установки line-height в значение, равное высоте. Такой способ центрирования текста работает, если он состоит из одной строки.
text-align
Центрирует текст горизонтально.
color, font-weight
Делает текст красным и жирным.

Открыть решение в песочнице.

важность: 5

Напишите функцию showNotification(options), которая показывает уведомление, пропадающее через 1.5 сек.

Описание функции:

/**
 * Показывает уведомление, пропадающее через 1.5 сек
 *
 * @param options.top {number} вертикальный отступ, в px
 * @param options.right {number} правый отступ, в px
 * @param options.cssText {string} строка стиля
 * @param options.className {string} CSS-класс
 * @param options.html {string} HTML-текст для показа
 */
function showNotification(options) {
  // ваш код
}

Пример использования:

// покажет элемент с текстом "Привет" и классом welcome справа-сверху окна
showNotification({
  top: 10,
  right: 10,
  html: "Привет",
  className: "welcome"
});

Демо в новом окне

Элемент уведомления должен иметь CSS-класс notification, к которому добавляется класс из options.className, если есть. Исходный документ содержит готовые стили.

Открыть песочницу для задачи.

Карта учебника

Комментарии

перед тем как писать…
  • Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
  • Для одной строки кода используйте тег <code>, для нескольких строк кода — тег <pre>, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)
  • Если что-то непонятно в статье — пишите, что именно и с какого места.