Инструкция как правильно мыть руки на пищевом производстве

Мы уже знаем, что CSS переводится как «Каскадные таблицы стилей». С таблицей стилей к этому моменту всё ясно, но что значит каскадные? Дело в том, что указать стили для элемента можно не только в одном месте.

Представьте каскад водопадов. Они перетекают друг в друга, накапливая всё больше и больше воды. В конечном итоге весь каскад окажется в общем бассейне. В CSS слово каскадность обозначает такое же действие, только вместо водопадов перетекают CSS свойства. Другими словами каскадность — возможность языка CSS накладывать свойства друг на друга, а также расширять свойства в селекторах.

Создадим блок с классами text-bold и text-dark и укажем несколько свойств в разных селекторах:

<p class="text-bold text-dark">Важный текст о вреде сложного CSS</p>
p {
  font-size: 20px;
}

.text-bold {
  font-weight: bold;
}

.text-dark {
  color: #333;
}

Если вставить этот пример в редактор, то выведется жирный текст размером 20 пикселей тёмного цвета. Произошло это благодаря каскадности — браузер объединил все стили из разных селекторов и получил следующие инструкции для стилизации элемента:

{
  font-size: 20px;
  font-weight: bold;
  color: #333;
}

Это и есть каскадность стилей в CSS. Хоть мы и использовали разные селекторы, но, в конечном итоге, браузер объединил их в единый набор правил для элемента

Задание

Добавьте в редактор p с классом cascade и установите следующие правила:

  • Для класса cascade установите размер шрифта 25 пикселей
  • Для тега p установите внутренний отступ в 15 пикселей со всех сторон. Это можно сделать с помощью правила padding: 15px;

Обратите внимание, как стили применятся одновременно. Стили запишите в теге <style>

Упражнение не проходит проверку — что делать? 😶

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

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

В моей среде код работает, а здесь нет 🤨

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя 🤔

Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно 🙄

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics

Полным руководством о том, что такое каскадные слои, какой у них синтаксис, зачем они могут понадобиться и как поддерживаются браузерами делимся к старту курса по Fullstack-разработке на Python.


Это полное руководство по каскадным слоям — функционалу CSS, позволяющему определять явные слои специфичности и полностью контролировать приоритет стилей в проекте, не применяя «костыли» специфичности или !important. 

Небольшой пример

/* establish a layer order up-front, from lowest to highest priority */
@layer reset, defaults, patterns, components, utilities, overrides;

/* import stylesheets into a layer (dot syntax represents nesting) */
@import url('framework.css') layer(components.framework);

/* add styles to layers */
@layer utilities {
  /* high layer priority, despite low specificity */
  [data-color='brand'] { 
    color: var(--brand, rebeccapurple);
  }
}

@layer defaults {
  /* higher specificity, but lower layer priority */
  a:any-link { color: maroon; }
}

/* un-layered styles have the highest priority */
a {
  color: mediumvioletred;
}

Введение. Что такое «каскадные слои»?

Каскадные слои созданы решать сложные проблемы CSS. Рассмотрим главную проблему её решение с помощью каскадных слоёв.

Проблема: разрастание конфликтов специфичности

Многие сталкивались с ситуациями, когда из-за конфликтующих селекторов нужно переопределить стили из других частей кода или из стороннего инструмента. И многие годы разрабатывались разные «методологии» и «лучшие практики», чтобы избежать подобных ситуаций, например «использования только одного класса» для всех селекторов. Эти правила обычно направлены скорее на уход от каскада, чем на его применение.

Управление каскадными конфликтами и специфичностью селекторов считалось одним из самых сложных (или по крайней мере наиболее запутанных) аспектов CSS. Отчасти это могло быть связано с тем, что мало в каких ещё языках каскад применяется как основной функционал.

Но так же верно и то, что исходный каскад сильно зависит скорее от эвристических подходов (обоснованных предположений и допущений, встроенных в код), чем от прямого и явного контроля веб-авторам.

Например, специфичность селекторов — первичное взаимодействие с каскадом — основывается на предположении, что узкоспециализированные стили (такие как идентификаторы, которые используются только один раз), вероятно, важнее более общих и повторно используемых (таких как классы и атрибуты).

Иными словами, это то, насколько специфичен селектор. И это хорошее предположение, но правило не абсолютно надёжное, что чревато проблемами:

  • Выбор элементов сочетается с определением приоритета наборов правил.

  • Самый простой способ «исправить» конфликт со специфичностью — усугубить проблему, добавив ненужные в иных случаях селекторы, или написать !important:

.overly#powerful .framework.widget {
  color: maroon;
}

.my-single_class { /* add some IDs to this ??? */
  color: rebeccapurple; /* add !important ??? */
}

Решение: каскадные слои обеспечивают контроль

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

С @layer и многослойными @import можно задавать собственные слои каскада, формируя стили от низкоприоритетных, например resets и defaults через themes, frameworks и design systems, до высокоприоритетных, таких как components, utilities и overrides.

При этом специфичность применяется к конфликтам внутри каждого слоя, но конфликты слоёв всегда разрешаются в пользу слоя с приоритетом выше:

@layer framework {
  .overly#powerful .framework.widget {
    color: maroon;
  }
}

@layer site {
  .my-single_class {
    color: rebeccapurple;
  }
}

Эти слои упорядочены и сгруппированы так, чтобы они не разрастались подобно специфичности и важности. Каскадные слои не столь кумулятивны, как селекторы. Важности от добавления слоёв не прибавляется.

И, в отличие от важности, слои не двоичны: они переходят сразу на вершину стека или имеют нумерацию, подобную z-index, где нужно угадывать большое число (z-index: 9999999?). На самом деле многослойные стили по умолчанию менее важны, чем стили без слоёв:

@layer defaults {
  a:any-link { color: maroon; }
}

/* un-layered styles have the highest priority */
a {
  color: mediumvioletred;
}

Где слои располагаются в каскаде?

Каскад — это алгоритм разрешения конфликтов стилей:

html { --button: teal; }
button { background: rebeccapurple !important; }
.warning { background: maroon; }
<button class="warning" style="background: var(--button);">
  what color background?
</button>

Вот этапы алгоритма с учётом каскадных слоёв:

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

Можно сказать, что флаг !important или атрибут style «добавляют специфичности»: это быстрый способ обозначить, что приоритет стиля в каскаде повышается. Каскадные слои добавлены прямо над специфичностью, поэтому разумно считать их более приоритетными, чем селекторы идентификаторов.

Каскадные слои повышают значимость полного понимания роли !important в каскаде — не только как инструмента для «повышения специфичности», но и как системы балансировки задач.

Источники, контекст и слои !important располагаются в противоположном порядке

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

Важность нужна не для того, чтобы просто увеличить приоритет, а чтобы сбалансировать приоритет конкурирующих задач.

Источники важности

Всё начинается с источников, откуда в веб-экосистеме берётся стиль. В CSS основных источника три. Это:

  • браузер (или пользовательский агент);

  • пользователь (часто через настройки браузера);

  • вебавторы (это мы!).

В браузерах для всех элементов предоставляются читаемые значения по умолчанию, затем пользователи устанавливают свои предпочтения, и уже мы (авторы) предоставляем дизайн веб-страниц. Итак, изначально у браузеров самый низкий приоритет, значения по умолчанию в них переопределяются пользовательскими предпочтениями, а мы можем переопределить их все. Но создатели CSS очень чётко дали понять, что на самом деле последнее слово не должно оставаться за нами:

«При возникновении конфликтов последнее слово должно быть за пользователем, но и автору должно быть позволено прикреплять стилевые подсказки».

— Хокон Ли (выделено мной)

Таким образом, важность даёт браузеру и пользователям возможность вернуть свой приоритет, когда это наиболее важно. Когда к стилю добавляется флаг !important, создаются три новых слоя, а порядок становится обратным!

1) стили браузера !important (самые приоритетные);

2) пользовательские предпочтения !important;

3) авторские стили !important;

4) обычные авторские стили;

5) обычные пользовательские предпочтения;

6) обычные стили браузера (наименее приоритетные).

Для нас добавление !important мало что меняет: важные стили довольно близки к обычным; но это очень мощный инструмент для восстановления контроля для браузера и пользователя. Таблицы значений стилей по умолчанию в браузерах содержат ряд важных стилей, переопределить которые мы не смогли бы, например:

iframe:fullscreen {
  /* iframes in full-screen mode don't show a border. */
  border: none !important;
  padding: unset !important;
}

Хотя в большинстве популярных браузеров загрузка первоначальных пользовательских таблиц стилей затруднена, настройки пользователя и графический интерфейс для установки конкретных пользовательских стилей предлагаются во всех.

В этом интерфейсе всегда есть флажок, чтобы пользователи выбирали, разрешить сайту переопределять их предпочтения. Это то же, что настройка !important в таблице стилей пользователя:

Важный контекст

Та же базовая логика применяется к контексту в каскаде. По умолчанию стили встроенного контекста (теневой DOM) переопределяются стилями главного документа (обычный DOM). Но при добавлении !important порядок меняется на противоположный:

  1. Теневой контекст !important (самый приоритетный).

  2. Главный контекст !important.

  3. Обычный главный контекст.

  4. Обычный теневой контекст (наименее приоритетный).

Определённые в главном документе важные стили переопределяются важными стилями теневого контекста.

Вот пользовательский элемент odd-bird. Одни его стили написаны в шаблоне элемента (теневой DOM), другие — в таблице стилей главной страницы (обычный DOM):

У обоих объявлений color важность обычная, поэтому главная страница mediumvioletred обладает приоритетом. Но объявления font-family помечены как !important, что даёт преимущество теневому контексту, где определяется fantasy.

Важные слои

Принцип работы каскадных слоёв тот же, что у источников и контекста, причём важные слои располагаются в обратном порядке. Единственная разница заключается в том, что это поведение гораздо более заметно из-за слоёв.

При использовании каскадных слоёв в отношении !important нужны намного более осторожные и продуманные действия. Это не только быстрый способ забраться на вершину приоритетов, но и неотъемлемая часть каскадного наложения слоёв, способ подчеркнуть необходимость тех или иных стилей нижних слоёв.

Каскадные слои настраиваются, поэтому предопределённого порядка нет. Но начать можно с трёх слоёв:

1) utilities (самый приоритетный);

2) components (среднего приоритета);

3) defaults (наименее приоритетный).

Когда стили в этих слоях отмечаются как важные, в них создаются три новых слоя, отмеченных !important, в обратном порядке:

  1. !important defaults (самый приоритетный).

  2. !important components.

  3. !important utilities.

  4. Обычные utilities.

  5. Обычные components.

  6. Обычные defaults (наименее приоритетный).

В этом примере цвет определяется во всех трёх обычных слоях; за счёт применения цвета maroon конфликт разрешается в пользу utilities: именно у него приоритет в @layer выше. Обратите внимание: text-decoration отмечено как !important в слоях defaults и components, где приоритетом обладают важные defaults, которые применяют объявленное в слое defaults подчёркивание:

Установление порядка слоёв

Можно создать любое количество слоёв и называть или группировать их различными способами. Но самое важное — убедиться, что слои применяются в правильном порядке.

Один слой в кодовой базе может использоваться несколько раз (в стеке каскадных слоёв) в том порядке первого появления. Первый встретившийся слой находится внизу, он наименее приоритетный, а последний — вверху, он самый приоритетный. Но тогда высшим приоритетом обладают стили без слоёв:

@layer layer-1 { a { color: red; } }
@layer layer-2 { a { color: orange; } }
@layer layer-3 { a { color: yellow; } }
/* un-layered */ a { color: green; }
  1. Стили без слоёв (самые приоритетные).

  2. layer-3.

  3. layer-2.

  4. layer-1 (наименее приоритетный).

И, как говорилось выше, любые важные стили применяются в обратном порядке:

@layer layer-1 { a { color: red !important; } }
@layer layer-2 { a { color: orange !important; } }
@layer layer-3 { a { color: yellow !important; } }
/* un-layered */ a { color: green !important; }
  1. layer-1 !important (самый приоритетный).

  2. layer-2 !important.

  3. layer-3!important.

  4. Стили без слоёв !important.

  5. Обычные стили без слоёв.

  6. Обычный layer-3.

  7. Обычный layer-2.

  8. Обычный layer-1 (наименее приоритетный).

Слои можно группировать. Это позволяет выполнять сложную сортировку слоёв верхнего уровня и вложенных слоёв:

@layer layer-1 { a { color: red; } }
@layer layer-2 { a { color: orange; } }
@layer layer-3 {
  @layer sub-layer-1 { a { color: yellow; } }
  @layer sub-layer-2 { a { color: green; } }
  /* un-nested */ a { color: blue; }
}
/* un-layered */ a { color: indigo; }
  1. Стили без слоёв (самые приоритетные).

  2. layer-3:

  1. layer-3 невложенный.

  2. layer-3, sub-layer-2.

  3. layer-3, sub-layer-1.

  1. layer-2.

  2. layer-1 (наименее приоритетный).

Сгруппированные слои в окончательном порядке слоёв всегда остаются вместе (например, все подслои layer-3 окажутся рядом друг с другом). Но в остальном здесь поведение такое же, как если бы список был «упрощённым», т. е. единым списком из шести пунктов. Когда меняется порядок слоёв !important, порядок всего упрощённого списка становится обратным.

Но слои не должны определяться единожды в одном месте. Мы называем слои, чтобы их можно было определять в одном месте для установления их порядка, а затем добавлять к ним стили из любого места:

/* describe the layer in one place */
@layer my-layer;

/* append styles to it from anywhere */
@layer my-layer { a { color: red; } }

В одном объявлении мы даже можем определять целый упорядоченный список слоёв:

@layer one, two, three, four, five, etc;

Это позволяет автору сайта в отношении порядка слоёв оставлять последнее слово за собой. Можно указать порядок слоёв заранее, то есть до импорта любого стороннего кода, установить и изменить порядок в одном месте, не беспокоясь об использовании слоёв в стороннем инструменте.

Синтаксис: работа с каскадными слоями

Перейдём к синтаксису.

Инструкции, чтобы задать порядок @layer

Слои располагаются в порядке их определения. Поэтому важно иметь инструмент, задающий порядок в одном месте. Здесь можно воспользоваться инструкцией @layer:

@layer <layer-name>#;

Решётка означает, что в список со значениями мы можем добавить столько угодно разделёнными запятыми имён слоёв:

@layer reset, defaults, framework, components, utilities;

Их порядок станет таким:

  1. стили без слоёв (самые приоритетные);

  2. utilities;

  3. components;

  4. framework;

  5. defaults;

  6. reset (наименее приоритетный).

Можно добавлять сколько угодно имён, не забывая, что важен порядок их первого появления. Результат будет тем же:

@layer reset, defaults, framework, components, utilities;

В логике упорядочения порядок reset, defaults и framework во втором @layer будет проигнорирован, ведь эти слои уже установлены. С этим синтаксисом списка @layer в логику упорядочения слоёв не добавляется никакой особой магии: слои располагаются согласно порядку появления в коде.

Первым здесь появляется reset первого списка @layer. Все следующие @layer могут лишь добавлять имена слоёв в список — уже имеющиеся слои с их помощью не переместятся. Это гарантия, что вы всегда сможете контролировать окончательный общий порядок слоёв из одного места, то есть в самом начале стилей.

Инструкции упорядочивания слоёв разрешены наверху таблицы стилей, перед правилом @import, но не между импортами. Мы очень рекомендуем использовать этот функционал, чтобы заранее устанавливать все слои в одном месте: так вы всегда будете знать, где искать или вносить изменения.

Блочный @layer

В блочной версии правила @layer принимается только одно имя слоя, но затем к этому слою можно добавлять стили:

@layer <layer-name> {
  /* styles added to the layer */
}

Поместить в блок @layer можно многое — это мультимедийные запросы, селекторы, стили, запросы @support и т. д. Нельзя поместить туда набор символов, импорты и пространства имён. Зато есть синтаксис импортирования стилей в слой.

Если имя слоя не установлено, оно будет добавлено в порядок слоёв благодаря этому правилу. Но, если имя установлено, можно добавлять стили к имеющимся слоям из любого места документа без изменения приоритета каждого слоя.

Если заранее установить порядок слоёв с помощью выражения @layer, то беспокоиться о порядке блоков слоёв больше не нужно:

/* establish the order up-front */
@layer defaults, components, utilities;

/* add styles to layers in any order */
@layer utilities {
  [hidden] { display: none; }
}

/* utilities will override defaults, based on established order */
@layer defaults {
  * { box-sizing: border-box; }
  img { display: block; }
}

Группировка (вложенных) слоёв

Слои можно группировать по правилам их вложенности:

@layer one {
  /* sorting the sub-layers */
  @layer two, three;

  /* styles ... */
  @layer three { /* styles ... */ }
  @layer two { /* styles ... */ }
}

Так генерируются сгруппированные слои, которые можно представить как объединение родительского и дочернего имён с точкой. Это означает, что прямой доступ к подслоям можно получить за пределами группы:

/* sorting nested layers directly */
@layer one.two, one.three;

/* adding to nested layers directly */
@layer one.three { /* ... */ }
@layer one.two { /* ... */ }

Правила упорядочения слоёв применяются на каждом уровне вложенности. Любые стили, которые не вложены глубже, в этом контексте считаются «стилями без слоёв», а значит, обладают приоритетом над более глубокими слоями:

@layer defaults {
  /* un-layered defaults (higher priority) */
  :any-link { color: rebeccapurple; }

  /* layered defaults (lower priority) */
  @layer reset {
    a[href] { color: blue; }
  }
}

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

@layer reset.type, default.type, reset.media, default.media;

В результате получается следующий порядок слоёв:

  • без слоёв (самый приоритетный);

  • группа default:

  • default без слоёв;

  • default.media;

  • default.type;

  • группа reset:

  • reset без слоёв;

  • reset.media;

  • reset.type.

Обратите внимание: имена слоёв тоже в области видимости, чтобы они не взаимодействовали и не конфликтовали с одноимёнными слоями вне контекста вложенности. Обе группы могут иметь различные подслои media.

Такая группировка приобретает особую важность в применении @import или <link> к целым таблицам стилей слоёв. В сторонних инструментах типа Bootstrap внутри могут использоваться слои. Но эти слои можно вложить в импорте в общую группу слоёв bootstrap, чтобы избежать потенциальных конфликтов их именования.

Наложение слоёв целых таблиц стилей через @import или <link>

Целые таблицы стилей к слою можно добавить с помощью нового синтаксиса функции layer() с правилами @import:

/* styles imported into to the <layer-name> layer */
@import url('example.css') layer(<layer-name>);

Есть предложение добавить атрибут layer в элемент HTML <link>, хотя оно дорабатывается и пока нигде не поддерживается. Использовать его можно для импорта сторонних инструментов или библиотек компонентов, объединяя любые внутренние слои под именем одного слоя, или как способ организации слоёв в отдельные файлы.

Анонимные (безымянные) слои

Имена слоёв позволяют получить доступ к конкретному слою из нескольких мест, чтобы сортировать или комбинировать блоки слоёв, но они необязательны. Блочное @layer позволяет создавать безымянные (анонимные) слои.

@layer { /* ... */ }
@layer { /* ... */ }

Ещё вариант — это синтаксис импорта с ключевым словом layer вместо функции layer():

/* styles imported into to a new anonymous layer */
@import url('../example.css') layer;

Каждый анонимный слой уникален и добавляется к тому порядку слоёв, в котором он встречается. Нельзя ссылаться на анонимные слои из других правил слоёв для сортировки или добавления стилей. Вероятно, их следует применять нечасто. Вот возможные варианты:

  • Проекты могли бы гарантировать, что все стили данного слоя должны располагаться в одном месте.

  • Сторонние инструменты могли бы «скрывать» своё внутреннее наложение слоёв внутри анонимных слоёв, чтобы внутреннее наложение не становились частью открытого API.

Возврат значений к предыдущему слою

Есть несколько способов «вернуть» стиль в каскаде к предыдущему значению, определяемому источником или слоем с более низким приоритетом, включая ряд глобальных значений CSS и новое ключевое слово revert-layer, тоже глобальное, то есть работающее в любом свойстве.

Контекст: имеющиеся глобальные ключевые слова каскада

В CSS есть несколько глобальных ключевых слов, которые можно использовать в любом свойстве, чтобы по-разному помочь каскаду откатиться.

  • С initial свойство устанавливается в указанное значение до применения любых стилей, включая браузерные значения по умолчанию. Это может удивить, ведь исходными значениями часто считают стили браузера. Но значение initial, например, в display является inline (встроенным), в каком бы элементе оно ни использовалось.

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

  • С unset все предыдущие значения как будто просто удаляются: наследуемые свойства снова применяют inherit (наследуются), а ненаследуемые возвращаются к initial (первоначальному) значению.

  • С revert удаляются только значения, применяемые в источнике автора, то есть стили сайта, оставляя браузер и пользовательские стили неизменными. Это то, что нужно в большинстве случаев.

Новое ключевое слово revert-layer

В каскадные слои добавляется новое глобальное ключевое слово revert-layer. Оно отличается от revert тем, что с его помощью удаляются только те значения, применяемые в текущем каскадном слое. Использовать его можно для отката каскада, применимо любое определённое в предыдущих слоях значение.

Ниже с помощью класса .no-theme удаляются любые значения, установленные в @layer theme:

@layer default {
  a { color: maroon; }
}

@layer theme {
  a { color: var(--brand-primary, purple); }

  .no-theme {
    color: revert-layer;
  }
}

Тег link с классом .no-theme вернётся к применению значения, установленного в слое default. В стилях без слоёв поведение revert-layer будет таким же, как revert: откат к предыдущему источнику.

Возврат важных слоёв

Самое интересное начинается при добавлении !important к revert-layer. У каждого слоя есть два различных положения в каскаде: «обычное» и «важное». Поэтому меняется не просто приоритет объявления, но и то, какие слои возвращаются.

Допустим, в стеке слоёв есть три определённых слоя:

  1. utilities (самый приоритетный);

  2. components;

  3. defaults (наименее приоритетный).

Включим в него обычные и важные положения каждого слоя, а также анимацию и стили без слоёв:

  1. !important defaults (самый приоритетный).

  2. !important components.

  3. !important utilities.

  4. Стили без слоёв !important.

  5. CSS-анимация.

  6. Обычные стили без слоёв.

  7. Обычные utilities.

  8. Обычные components.

  9. Обычные defaults (наименее приоритетный).

При использовании revert-layer в обычном слое (например, utilities) результат довольно простой. Возвращается только этот слой, а всё остальное будет как обычно:

  1. ✅ !important defaults (самый приоритетный).

  2. ✅ !important components.

  3. ✅ !important utilities.

  4. ✅ Стили без слоёв !important.

  5. ✅ CSS-анимация.

  6. ✅ Обычные стили без слоёв.

  7. ❌ Обычные utilities.

  8. ✅ Обычные components.

  9. ✅ Обычные defaults (наименее приоритетный).

Когда этот revert-layer перемещается в важное положение, возвращаются обе версии (обычная и важная) и всё, что между ними:

  1. ✅ !important defaults (самый приоритетный).

  2. ✅ !important components.

  3. ❌ !important utilities.

  4. ❌ Стили без слоёв !important.

  5. ❌ CSS-анимация.

  6. ❌ Обычные стили без слоёв.

  7. ❌ Обычные utilities.

  8. ✅ Обычные components.

  9. ✅ Обычные defaults (наименее приоритетный).

Когда (не) применять каскадные слои?

Приведём примеры того, когда каскадные слои кстати, а когда большого смысла в них нет.

Не такие надоедливые resets и defaults

Один из самых очевидных вариантов использования — написать легко переопределяемые, низкоприоритетные defaults. В некоторых resets это уже делается за счёт применения псевдокласса :when() вокруг каждого селектора. С его помощью из селекторов удаляется вся применяемая к ним специфичность. Основное необходимое воздействие достигается, но есть недостатки:

  • его нужно применять к каждому селектору отдельно;

  • конфликты внутри reset должны разрешаться без специфичности.

Слои позволяют проще оборачивать всю таблицу стилей reset с помощью блочного @layer:

/* reset.css */
@layer reset {
  /* all reset styles in here */
}

Или импорта reset:

/* reset.css */
@import url(reset.css) layer(reset);

Или того и другого. Слои могут быть вложены без изменения их приоритета. Так, можно использовать сторонний reset и гарантировать, что он добавляется к нужному слою, независимо от того, записана сама таблица стилей reset с применением внутренних слоёв или без них.

Приоритет многослойных стилей ниже, чем стилей по умолчанию «без слоёв». А значит, можно начать использовать каскадные слои, не переписывая всю кодовую базу CSS.

Селекторы reset по-прежнему содержат информацию о специфичности, которая помогает разрешать внутренние конфликты без обёртывания каждого отдельного селектора. Кроме того, вы получаете нужный результат: легко переопределяемые таблицы стилей reset.

Управление CSS сложной архитектуры

По мере роста и усложнения проектов бывает полезно определить более чёткие границы для именования и организации кода CSS. Но, чем больше CSS, тем больше возможностей для конфликтов, особенно из разных частей системы, таких как тема, библиотека компонентов или набор вспомогательных классов.

Организовать их нужно не только по функциям, но и, может быть, по приоритету частей системы на случай конфликта. Гарри Роберт на примере CSS с перевёрнутым треугольником хорошо показывает, что могут содержать эти слои:

Фактически первым шагом для добавления слоёв в каскад CSS была методология ITCSS как основной пример и руководство по разработке функции.

Для неё не требуется какого-то конкретного метода, но проекты, вероятно, лучше ограничить заранее определённым набором слоёв верхнего уровня, а затем при необходимости расширить его вложенными слоями.

Например:

  1. Низкоуровневый сброс и стили нормализации.

  2. Значения элементов по умолчанию для базовой типографики и удобочитаемости.

  3. Темы, светлый и тёмный режимы.

  4. Повторно используемые шаблоны, которые могут появляться в нескольких компонентах.

  5. Макеты и большие структуры страниц.

  6. Отдельные компоненты.

  7. Переопределения и утилиты.

Этот стек слоёв верхнего уровня можно написать в самом начале CSS одним @layer:

@layer
  reset,
  default,
  themes,
  patterns,
  layouts,
  components,
  utilities;

Нужны взыскательные слои: их названия могут меняться от проекта к проекту. Создадим ещё более подробные разбивки слоёв. Возможно, внутри самих components есть defaults, structures, themes и utilities:

@layer components {
  @layer defaults, structures, themes, utilities;
}

Теперь можно дальше разделять стили на слои внутри каждого компонента, не меняя структуру верхнего уровня, .

Использование сторонних инструментов и фреймворков

Интеграция стороннего CSS с проектом — одно из мест, где с проблемами каскада сталкиваются чаще всего. Не всегда возможно контролировать специфичность селекторов или важность всего CSS, используемого на сайтах.

Не важно, что применяется: общий сброс (Normalizer или CSS Remedy), универсальная дизайн-система вроде Material Design, фреймворк типа Bootstrap или набор служебных инструментов Tailwind. Иногда это верно даже для внутренних библиотек, дизайн-систем и инструментов других частей организации.

В итоге часто приходится структурировать внутренний CSS вокруг стороннего кода или расширять появляющиеся конфликты, искусственно повышая специфичность или применяя флаги !important. Эти «костыли» нужно поддерживать, адаптируя к изменениям.

Каскадные слои дают возможность встроить сторонний код в каскад любого проекта именно там, где он нужен, — не важно, как селекторы написаны внутри. Сделать это можно разными способами в зависимости от типа используемой библиотеки. Продвигаясь от resets к utilities, начнём с базового стека слоёв:

@layer reset, type, theme, components, utilities;

Затем можно подключить инструменты…

Использование сброса

Можно включить собственные стили сброса инструментом типа CSS Remedy, для этого импортируем CSS Remedy в подслой reset:

@import url('remedy.css') layer(reset.remedy);

Теперь собственные стили сброса можно добавить в слой reset без какой-либо дополнительной вложенности, если она не нужна. Любые вложенные стили переопределяются прямо в reset, поэтому мы можем быть уверены, что в случае конфликта наши стили всегда будут иметь приоритет, какими бы ни были изменения в новой версии CSS Remedy:

@import url('remedy.css') layer(reset.remedy);

@layer reset {
  :is(ol, ul)[role='list'] {
    list-style: none;
    padding-inline-start: 0;
  }
}

А поскольку слой reset находится внизу стека, в остальной части CSS нашей системы будут переопределены и Remedy, и собственные локальные дополнения reset.

Использование служебных классов

«Служебные классы» в CSS на другом конце стека позволяют широко применяемым способом воспроизводить общие шаблоны (например, дополнительный контекст для программ чтения с экрана).

Эти классы имеют свойство нарушать эвристические подходы специфичности, ведь нам нужно, чтобы они определялись широко, что ведёт к низкой специфичности. А ещё обычно нужно, чтобы служебные классы «выигрывали» конфликты. Такое возможно благодаря слою utilities вверху стека. Мы загружаем в подслой внешние и собственные utilities, как в примере с reset:

@import url('tailwind.css') layer(utilities.tailwind);

@layer utilities {
  /* from https://kittygiraudel.com/snippets/sr-only-class/ */
  /* but with !important removed from the properties */
  .sr-only {
    border: 0;
    clip: rect(1px, 1px, 1px, 1px);
    -webkit-clip-path: inset(50%);
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    margin: -1px;
    padding: 0;
    position: absolute;
    width: 1px;
    white-space: nowrap;
  }
}

Использование дизайн-систем и библиотек компонентов

Много инструментов CSS находится где-то в середине стека слоёв, объединяя типографские настройки по умолчанию, темы, компоненты и другие аспекты системы.

В зависимости от конкретного инструмента мы могли бы сделать что-то похожее на приведённые выше примеры с reset и utility, но есть другие варианты. Инструмент с тесной интеграцией может заслуживать отдельного слоя верхнего уровня:

@layer reset, bootstrap, utilities;
@import url('bootstrap.css') layer(bootstrap);

Если в этих инструментах слои начнут предоставлять как часть их общедоступного API, этот API также можно разбить на части, что позволит чередовать код с библиотекой:

@import url('bootstrap/reset.css') layer(reset.bootstrap);
@import url('bootstrap/theme.css') layer(theme.bootstrap);
@import url('bootstrap/components.css') layer(components.bootstrap);
@layer theme.local {
/* styles here will override theme.bootstrap /
/ but not interfere with styles from components.bootstrap */
}

Использование слоёв с фреймворками

Как при любом серьёзном изменении языка, наступит период адаптации, когда каскадные слои CSS получат широкое применение. Что, если ваша команда готова начать использовать слои уже в следующем месяце, а любимому фреймворку для перехода на многослойные стили нужно ещё три года? Скорее всего, во многих фреймворках !important по-прежнему будут использоваться чаще, чем хотелось бы! А с обратным порядком слоёв !important это неидеально.

Но слои всё равно могут помочь решить эту проблему. Нужно просто подойти к решению с умом. То, какие слои нужны для проекта, определяем мы. Можно добавлять слои выше и ниже созданных нами слоёв фреймворка. А пока можно использовать слой ниже для переопределения !important стилей из фреймворка, а слой выше — для переопределения обычных стилей. Что-то вроде этого:

@layer framework.important, framework.bootstrap, framework.local;
@import url('bootstrap.css') layer(framework.bootstrap);

@layer framework.local {
  /* most of our normal framework overrides can live here */
}

@layer framework.important {
  /* add !important styles in a lower layer */
  /* to override any !important framework styles */
}

Всё ещё похоже на «костыли», но они помогают двигаться в правильном направлении, к более структурированному каскаду. Надеюсь, это временное решение.

Разработка инструмента или фреймворка CSS

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

Например, в Bootstrap могут предоставляться слои для reboot, grid и utilities; вероятно, в таком порядке. Пользователь сможет решить, нужно ли ему загружать эти слои Bootstrap в разные локальные слои:

@import url(bootstrap/reboot.css) layer(reset); /* reboot » reset.reboot */
@import url(bootstrap/grid.css) layer(layout); /* grid » layout.grid */
@import url(bootstrap/utils.css) layer(override); /* utils » override.utils */

Или загрузить их в слой Bootstrap с чередованием локальных слоёв:

@layer bs.reboot, bs.grid, bs.grid-overrides, bs.utils, bs.util-overrides;
@import url('bootstrap-all.css') layer(bs);

При желании можно скрыть от пользователей внутреннее наложение слоёв, сгруппировав любые закрытые/внутренние слои внутри анонимного слоя. Анонимные слои будут добавляться к тому порядку слоёв, в котором встречаются, но не будут предоставляться пользователям, которые переставляют или добавляют стили.

Мне просто нужно свойство, чтобы стать более !important (важным)

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

Если большинство стилей не имеют слоёв, то любой новый слой по отношению к слою по умолчанию будет иметь пониженный приоритет. Мы могли бы сделать так с отдельными блоками стилей, но это бы сразу стало трудно отслеживать.

Слои должны быть более фундаментальными, устанавливающими в проекте последовательные шаблоны, а не стиль за стилем. Если мы всё настроили правильно, то в идеале получим подходящий результат, переместив стиль в соответствующий, заранее определённый слой.

Если большинство стилей уже попадают в чётко определённые слои, всегда можно рассмотреть возможность добавить новый слой с наивысшим приоритетом в верхней части стека слоёв или использовать обычные стили для переопределения слоёв. Для исследований вне продакшена можно даже подумать о создании слоя debug в верхней части стека.

Но при добавлении новых слоёв «на лету» организационная полезность этой функции можно свести на нет, использовать её следует осторожно. Лучше спросить: «Почему этим стилем должен переопределяться другой стиль?»

Если ответ связан с тем, что одним типом стиля всегда переопределяется другой тип, вероятно, слои будут правильным решением. Ведь мы переопределяем стили, источник которых не контролируем, или пишем утилиту, которая должна переместиться в слой utilities.

Если же ответ связан с тем, что менее специализированные стили переопределяются более специализированными, мы могли бы подумать об отражении этой специфики селекторами. Или в редких случаях могли бы даже создать стили, которые действительно important (важны), — данный функционал просто не работает, если вы переопределяете именно такой стиль. 

Мы могли бы сказать, что добавление display: none к атрибуту [hidden] подходит в reset с самым низким приоритетом, но всё равно этот стиль должно быть трудно переопределить. В данном случае !important — действительно правильный инструмент для такой работы:

@layer reset {
  [hidden] { display: none !important; }
}

Стили области видимости и пространств имён? Нет!

Безусловно, каскадные слои — это организационный инструмент, который «улавливает» влияние селекторов, особенно когда они конфликтуют. Поэтому сначала может возникнуть соблазн посчитать их решением для управления областью видимости или пространством имён и создать слой для каждого компонента в проекте в надежде, что это обеспечит, например, применение .post-title только внутри .post.

Но каскадные конфликты — это не то же самое, что конфликты именования, а слои не очень хорошо подходят для такого типа организации в области видимости. Каскадные слои не ограничивают то, как селекторы соответствуют HTML или применяются к нему. Они ограничивают только то, как они вместе располагаются каскадом.

Поэтому, пока мы не сможем быть уверены, что компонент Y всегда переопределяется компонентом X, отдельные слои компонентов мало чем будут полезны. Вместо этого нужно будет следить за предлагаемой спецификацией @scope, которая сейчас разрабатывается.

Может быть полезно думать о слоях и областях видимости компонентов как о перекрывающихся проблемах:

В областях видимости описывается, что мы стилизуем, а в слоях — почему. Кроме того, слои дают представление о том, откуда берётся стиль, а области видимости — о том, к чему он будет привязан.

Проверьте свои знания: какой стиль в приоритете?

В каждой ситуации рассматривается абзац:

<p id="intro">Hello, World!</p>

Вопрос 1

@layer ultra-high-priority {
  #intro {
    color: red;
  }
}

p {
  color: green;
}

Какого цвета абзац?

Несмотря на имя, которое выглядит довольно важным, выше приоритет стилей без слоя. Абзац будет зелёным.

Вопрос 2

@layer ren, stimpy;

@layer ren {
  p { color: red !important; }
}

p { color: green; }

@layer stimpy {
  p { color: blue !important; }
}

Какого цвета абзац?

Вначале устанавливается нормальный порядок: внизу ren, затем stimpy и в верхней части (как всегда) стили без слоёв. Но не все эти стили нормальные, некоторые из них имеют !important. Сразу можно отфильтровать только !important, а также игнорировать green. Помните, что «источник и важность» — первые шаги каскада, они учитываются до работы со слоями.

Останется два стиля c !important, оба в слоях. Поскольку слои с !important разворачиваются, ren движется к вершине, а stimuli — вниз. Абзац будет красным.

Вопрос 3

@layer Montagues, Capulets, Verona;

@layer Montagues.Romeo { #intro { color: red; } }
@layer Montagues.Benvolio { p { color: orange; } }

@layer Capulets.Juliet { p { color: yellow; } }
@layer Verona { * { color: blue; } }
@layer Capulets.Tybalt { #intro { color: green; } }

Какого цвета абзац

Все в пределах одного источника и контекста, !important не помечен ни один, нет и встроенных стилей. Есть много разных селекторов, от самого специфичного ID #intro до универсального селектора. Но слои разрешаются до учёта специфики, поэтому сейчас селекторы можно игнорировать.

Есть первичный слой, а в нём подслои, которые сортируются вместе с родительским слоем, а значит, все Montagues будут обладать самым низким приоритетом, затем идут все Capulets. Последнее слово за Verona. Можно сразу отфильтровать только стили Verona, которые имеют приоритет. И хотя специфичность селектора * нулевая, в конфликте он одержит верх.

Универсальные селекторы в приоритетных слоях располагайте осторожно!

Отладка конфликтов слоёв в инструментах разработчика

В браузерах Chrome, Safari, Firefox и Edge есть инструменты разработчика, позволяющие просматривать стили элемента страницы. В палитре стилей этого инспектора элементов показываются применяемые селекторы, отсортированные по их каскадному приоритету (наивысший — вверху), а ниже — унаследованные стили. Стили, которые по какой-то причине не применяются, обычно выделяются серым цветом или даже перечёркиваются — иногда с дополнительной информацией о том, почему стиль не применяется. Это первое, куда нужно смотреть при отладке любого аспекта каскада, включая конфликты слоёв.

С помощью Safari Technology Preview и Firefox Nightly в данной палитре уже показываются и сортируются каскадные слои. Ожидается, что этот инструментарий выкатят в стабильных версиях одновременно с каскадными слоями. Слой каждого селектора указан прямо над ним:

В Safari:

Firefox, Chrome/Edge работают над аналогичными инструментами, появление которых ожидается в nightly-версиях Canary к тому времени, когда каскадные слои будут в стабильной версии. Мы будем обновлять статью по мере изменений в инструментах.

Поддержка @layer браузерами и резервные варианты

Каскадные слои доступны или скоро будут доступны по умолчанию во всех трёх основных движках браузеров:

  • Chrome/Edge 99+;

  • Firefox 97+;

  • Safari (сейчас Safari Technology Preview).

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

В резервных вариантах, скорее всего, будет дублирование больших разделов кода с использованием разных селекторов для управления каскадным наложением слоёв или гораздо более простая резервная таблица стилей.

Поддержка функции запроса с помощью @supports

Функция @supports в CSS позволяет авторам проверять поддержку @layer и других правил с @:

@supports at-rule(@layer) {
  /* code applied for browsers with layer support */
}

@supports not at-rule(@layer) {
  /* fallback applied for browsers without layer support */
}

Однако неясно, когда сам этот запрос будет поддерживаться в браузерах.

Назначение слоёв в HTML с помощью тега <link>

Официальной спецификации синтаксиса целых таблиц стилей слоёв в теге <link> пока нет, но предложение уже разрабатывается. В него включён новый атрибут layer, который можно использовать для присвоения стилей именованному или анонимному слою:

<!-- styles imported into to the <layer-name> layer -->
<link rel="stylesheet" href="example.css" layer="<layer-name>">

<!-- styles imported into to a new anonymous layer -->
<link rel="stylesheet" href="example.css" layer>

Но в старых браузерах без поддержки атрибута layer он будет полностью игнорироваться: таблица стилей продолжит загружаться без наложения слоёв и результаты могут оказаться довольно неожиданными.

В предложении также расширяется атрибут media, он будет выполнять запросы поддержки функционала в support(). Это позволило бы делать многослойные ссылки условными, основываясь на поддержке @layer:

<link rel="stylesheet" layer="bootstrap" media="supports(at-rule(@layer))" href="bootstrap.css">

Потенциальные полифиллы и обходные решения

Все основные браузеры перешли на «вечнозелёную» модель с обновлениями, предоставляемыми пользователям в довольно коротком цикле выпуска. Даже для Safari регулярно выпускаются новые функции в «запатченных» обновлениях между их основными версиями, которые кажутся более редкими.

Значит, можно ожидать, что поддержка этих функций будет расширяться очень быстро. Для многих из нас может быть разумно начать использовать слои уже через несколько месяцев, не особо переживая о старых браузерах. А для кого-то может потребоваться больше времени, чтобы освоиться со встроенной поддержкой браузера.

Есть много других способов управления каскадом: с помощью селекторов, пользовательских свойств и других инструментов. Кроме того, теоретически возможно имитировать базовое поведение или написать его полифилл. Есть люди, работающие над этим полифиллом, но неясно, когда он будет готов.

Ещё материалы

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

А мы поможем вам прокачать навыки или освоить профессию, востребованную в любое время:

  • Профессия Fullstack-разработчик на Python

  • Профессия Data Scientist

Выбрать другую востребованную профессию.

Ссылки из статьи

Краткий каталог курсов и профессий

Использование каскадных таблиц стилей

CSS – Cascading Style Sheets

CSS представляет собой язык, с помощью которого описывается внешний вид документа, созданного с помощью HTML или XHTML. Расшифровывается эта аббревиатура как Cascading Style Sheet, что в переводе на русский означает «каскадные таблицы стилей». Само это понятие было впервые предложено еще в 1994 году, и основной смысл его состоит в том, чтобы разделить содержание и представление web-документа. Структура CSS, выделяется в отдельный блок и может быть применена как ко всему документу, так и к какой-либо его части. При этом сам блок может, как включаться в компоновку самого документа, так и быть отдельным от него. Во втором случае он представляет собой текстовый файл с расширением «*.css».

Первая версия CSS (CSS1) вышла в свет в 1996 году, однако она имела целый ряд существенных недостатков. Поэтому Консорциум Всемирной паутины (W3C) в 1997 году создал специальную рабочую группу, результатом деятельности которой стало появление годом спустя CSS2, которые действует до сих пор. Сейчас ведется разработка CSS3, причем ее авторы обещают создать поистине революционный продукт.

Разработчиками CSS была реализована концепция наследования от родителя к потомку, благодаря чему появилась возможность определять те или иные стили на основании элементов созданных ранее. Это значительно ускоряет и упрощает создание готового документа и предоставляет большую свободу действий при быстрой его модификации в соответствии с изменившимися требованиями. Кроме того, с помощью CSS можно сделать так, чтобы один и тот же документ имел различные стили в зависимости от конкретного метода его вывода (экранного, печатного представления или же вывода голосом).

CSS каскадные таблицы стилей подробное руководство

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

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

Элементам HTML могут присваиваться идентификаторы «id» или классы «class». Различие между ними состоит в том, что идентификатор допускается соотносить только с одним элементом, а класс – с несколькими. Существуют также и так называемые «псевдоклассы», с помощью которых описывается вид гиперссылок в документе. Что касается псевдоэлементов, то их в CSS четыре: первая строка, первая буква, применение специальных стилей до и после элемента.

Наследование в CSS заключается в том, что свойства, которые объявлены в предках, наследуются потомками, однако не все (имеется определенное количество исключений из этого правила). Если в HTML какому-либо элементу поставлено в соответствие несколько правил CSS, то используются каскадирование и правила приоритета, среди которых наиболее высокий имеет стиль, заданный автором страницы, а самый низкий – стиль браузера.

Каскадирование

Аббревиатура CSS расшифровывается как Cascading Style Sheets (каскадные таблицы стилей), где одним из ключевых слов выступает «каскад». Под каскадом в данном случае понимается одновременное применение разных стилевых правил к элементам документа — с помощью подключения нескольких стилевых файлов, наследования свойств и других методов. Чтобы в подобной ситуации браузер понимал, какое в итоге правило применять к элементу, и не возникало конфликтов в поведении разных браузеров, введены некоторые приоритеты.

Ниже приведены приоритеты браузеров, которыми они руководствуются при обработке стилевых правил. Чем выше в списке находится пункт, тем ниже его приоритет, и наоборот.

  1. Стиль браузера.
  2. Стиль автора.
  3. Стиль пользователя.
  4. Стиль автора с добавлением !important.
  5. Стиль пользователя с добавлением !important.

Самым низким приоритетом обладает стиль браузера — оформление, которое по умолчанию применяется к элементам веб-страницы браузером. Это оформление можно увидеть в случае «голого» HTML, когда к документу не добавляется никаких стилей.

Как задавать пользовательский стиль рассказывалось в главе 1 (см. рис. 1.3 и 1.4).

!important

Ключевое слово !important играет роль в том случае, когда пользователи подключают свою собственную таблицу стилей. Если возникает противоречие, когда стиль автора страницы и пользователя для одного и того же элемента не совпадает, то !important позволяет повысить приоритет стиля или его важность, иными словами.

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

  • !important добавлен в авторский стиль — будет применяться стиль автора.
  • !important добавлен в пользовательский стиль — будет применяться стиль пользователя.
  • !important нет как в авторском стиле, так и стиле пользователя — будет применяться стиль пользователя.
  • !important содержится в авторском стиле и стиле пользователя — будет применяться стиль пользователя.

Синтаксис применения !important следующий.

Свойство: значение !important

Вначале пишется желаемое стилевое свойство, затем через двоеточие его значение и в конце после пробела указывается ключевое слово !important.

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

Специфичность

Если к одному элементу одновременно применяются противоречивые стилевые правила, то более высокий приоритет имеет правило, у которого значение специфичности селектора больше. Специфичность это некоторая условная величина, вычисляемая следующим образом. За каждый идентификатор (в дальнейшем будем обозначать их количество через a) начисляется 100, за каждый класс и псевдокласс (b) начисляется 10, за каждый селектор тега и псевдоэлемент (c) начисляется 1. Складывая указанные значения в определённом порядке, получим значение специфичности для данного селектора.

*              {} /* a=0 b=0 c=0 -> специфичность = 0   */
li             {} /* a=0 b=0 c=1 -> специфичность = 1   */
li:first-line  {} /* a=0 b=0 c=2 -> специфичность = 2   */
ul li          {} /* a=0 b=0 c=2 -> специфичность = 2   */
ul ol+li       {} /* a=0 b=0 c=3 -> специфичность = 3   */
ul li.red      {} /* a=0 b=1 c=2 -> специфичность = 12  */
li.red.level   {} /* a=0 b=2 c=1 -> специфичность = 21  */
#t34           {} /* a=1 b=0 c=0 -> специфичность = 100 */
#content #wrap {} /* a=2 b=0 c=0 -> специфичность = 200 */

Встроенный стиль, добавляемый к тегу через атрибут style, имеет специфичность 1000, поэтому всегда перекрывает связанные и глобальные стили. Однако добавление !important перекрывает в том числе и встроенные стили.

Если два селектора имеют одинаковую специфичность, то применяться будет тот стиль, что указан в коде ниже.

В примере 19.1 показано, как влияет специфичность на стиль элементов списка.

Пример 19.1. Цвет списка

HTML5CSS 2.1IECrOpSaFx

<!DOCTYPE HTML>
<html>
 <head>
  <meta charset="utf-8">
  <title>Список</title>
  <style>
   #menu ul li {
    color: green;
   }
   .two {
    color: red;
   }
  </style>
 </head>
 <body>
  <div id="menu">
   <ul>
    <li>Первый</li>
    <li class="two">Второй</li>
    <li>Третий</li>
   </ul>
  </div>
 </body> 
</html>

В данном примере цвет текста списка задан зелёным, а второй пункт списка с помощью класса two выделен красным цветом. Вычисляем специфичность селектора #menu ul li — один идентификатор (100) и два тега (2) в сумме дают значение 102, а селектор .two будет иметь значение специфичности 10, что явно меньше. Поэтому текст окрашиваться красным цветом не будет. Чтобы исправить ситуацию, необходимо либо понизить специфичность первого селектора, либо повысить специфичность второго (пример 19.2).

Пример 19.2. Изменение специфичности

/* Понижаем специфичность первого селектора */
 ul li {...} /* Убираем идентификатор */
 .two  {...}

/* Повышаем специфичность второго селектора */
 #menu ul li {...}
 #menu  .two {...} /* Добавляем  идентификатор */

 #menu ul li {...}
 .two { color:  red !important; } /* Добавляем !important */

Добавление идентификатора используется не только для изменения специфичности селектора, но и для применения стиля только к указанному списку. Поэтому понижение специфичности за счёт убирания идентификатора применяется редко, в основном, повышается специфичность нужного селектора.

Вопросы для проверки

1. Какая специфичность будет у селектора table.forum tr:hover p?

  1. 14
  2. 22
  3. 23
  4. 32
  5. 41

2. Какая специфичность будет у селектора #catalog .col3 .height div?

  1. 301
  2. 203
  3. 121
  4. 40
  5. 31

Ответы

1. 23

2. 121

Каскадные таблицы стилей (Cascading Style Sheets, CSS) – это стандарт
визуального представления HTML-документов. Каскадные таблицы стилей
предназначены для использования дизайнерами: они позволяют точно определить шрифты,
цвета, величину полей, выравнивание, параметры рамок и даже координаты
элементов в документе. Но они также представляют интерес и для программистов,
пишущих на клиентском языке JavaScript, потому что позволяют
воспроизводить анимационные эффекты, такие как плавное появление содержимого
документа из-за правого края, например, или сворачивание и разворачивание списков,
благодаря чему пользователь получает возможность управлять объемом
отображаемой информации. Когда подобные визуальные эффекты только появились,
они казались революционными. Совместное применение технологий CSS и
JavaScript, обеспечивающее получение разнообразных визуальных эффектов,
получило не совсем удачное название «динамический язык HTML» (Dynamic HTML,
DHTML), которое уже вышло из употребления.

CSS – достаточно сложный стандарт, который на момент написания этих строк
продолжал активно развиваться. Тема CSS настолько объемная, что для полного
ее охвата потребовалось бы написать отдельную книгу, и ее детальное
обсуждение выходит далеко за рамки этой книги. Однако чтобы освоить принципы
работы с каскадными таблицами стилей, совершенно необходимо знать хотя бы
основы CSS и наиболее часто используемые стили. Поэтому эта глава начинается
с обзора CSS, за которым следует описание ключевых стилей, наиболее часто
используемых в сценариях. Вслед за этими двумя вводными разделами глава
переходит к описанию принципов работы с CSS. В разделе 16.3 описываются
наиболее общие и важные приемы: изменение стилей, применяемых к отдельным
элементам документа с помощью HTML-атрибута style. Атрибут style элемента
можно использовать для задания стилей, но с его помощью нельзя узнать текущие
настройки стилей элементов. В разделе 16.4 рассказывается, как можно получить
вычисленные стили любого элемента. В разделе 16.5 вы узнаете, как можно
изменить сразу несколько стилей путем изменения атрибута style элемента.
Имеется также возможность непосредственно управлять таблицами стилей, хотя это
и редко используется на практике. В разделе 16.6 будет показано, как включать
и отключать таблицы стилей, изменять правила в существующих таблицах и
добавлять новые таблицы.

Рекомендуемое издание: Эрик Мейер «CSS – каскадные таблицы стилей. Подробное
руководство», 3-е издание — Пер. с англ. — СПб.: Символ-Плюс, 2008. 16.1. Обзор CSS
445

содержание 16.1. Обзор CSS содержание

Визуальное представление HTML-документов определяется множеством
параметров: шрифты, цвета, отступы и т. д. Все эти параметры перечислены в
стандарте CSS, где они называются свойствами стиля (style properties). Стандарт
CSS определяет свойства, которые задают шрифты, цвета, величину полей,
параметры рамок, фоновые изображения, выравнивание текста, размеры элементов
и их позиции. Чтобы задать визуальное представление HTML-элементов, мы
определяем соответствующие значения CSS-свойств. Для этого необходимо
записать имя свойства и его значение через двоеточие:

font-weight: bold

Чтобы полностью описать визуальное представление элемента, обычно бывает
необходимо указать значения нескольких свойств. Когда требуется записать
несколько пар имя/значение, они отделяются друг от друга точками с запятой:


margin-left: 10%;  /* левое поле 10% от ширины страницы */
text-indent: .5in; /* отступ 1/2 дюйма */
font-size: 12pt:   /* размер шрифта 12 пунктов */

Как видите, в каскадные таблицы стилей можно помещать комментарии,
заключая их в пары символов /* и */. Однако здесь не поддерживаются комментарии,
начинающиеся с символов //.

Существует два способа связать набор значений CSS-свойств с
HTML-элементами, чье визуальное представление они определяют. Первый заключается в
установке атрибута style отдельного HTML-элемента. Такие стили называются
встроенными:

<p style="margin: 20px; border: solid red 2px;">
Зтот абзац имеет увеличенные поля и окружен прямоугольной рамкой красного цвета.
</p>

Однако намного эффективнее отделять стили CSS от отдельных HTML-элементов
и определять их в таблицах стилей. Таблица стилей связывает наборы свойств
стилей с группами HTML-элементов, которые описываются с помощью
селекторов. Селектор определяет, или «выбирает», один или более элементов документа,
опираясь на атрибут id или class, имя тега или на другие более
специализированные критерии. Селекторы были представлены в разделе 15.2.5, где также было
показано, как с помощью querySelectorAll() выбрать группу элементов,
соответствующих селектору.

Основным элементом таблицы стилей CSS является правило стиля, состоящее из
селектора и набора свойств стиля с их значениями, заключенного в фигурные
скобки. Таблица стилей может содержать любое количество правил:

p {                  /* селектору "p" соответствуют все элементы <p> */
  text-indent: .5in; /* первая строка с отступом 0,5 дюйма */
}
.warning {                  /* Любой элемент с атрибутом class="warning" */
  background-color: yellow: /* будет иметь желтый фон */
  border: solid black 5px;  /* и толстую черную рамку */
}

Таблицу стилей CSS можно добавить в HTML-документ, заключив ее в теги <sty1е>
и </sty1е> внутри тега <head>. Подобно элементам <script>, синтаксический
анализ содержимого элементов <sty1е> выполняется отдельно и не
интерпретируется как разметка HTML:

<html>
<head><title>Текстовый документ</title>
<style>
  body { margin-left: ЗОрх; margin-right: 15px; background-color: #fffffff }
  p { font-size: 24px; }
</style>
</head>
<body><p>Проверка, проверка</р>
</html>

Если таблица стилей используется более чем в одной странице веб-сайта, ее
обычно лучше сохранить в отдельном файле, без использования объемлющих HTML-
тегов. Затем этот файл CSS можно будет подключить к HTML-странице. В
отличие от элемента <script>, элемент <style> не имеет атрибута src. Чтобы
подключить таблицу стилей к HTML-странице, следует использовать элемент <link> в
теге <head> документа:

<head>
  <title>Текстовый документ</title>
  <link rel="stylesheet" href="mystyles.css" type="text/css">
</head>

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

содержание 16.1.1. Каскад правил

Напомню, что буква «C» в аббревиатуре CSS обозначает «cascade» (каскадная).
Этот термин указывает, что правила стилей, применяемые к конкретному
элементу документа, могут быть получены из «каскада» различных источников:

  • Таблицы стилей по умолчанию веб-браузера
  • Таблицы стилей документа
  • Атрибуты style отдельных HTML-элементов

Стили, определяемые в атрибуте style, переопределяют стили из таблицы стилей,
а стили из таблицы стилей переопределяют таблицу стилей браузера,
применяемую по умолчанию. Визуальное представление любого элемента может
определяться комбинацией свойств стилей из всех трех источников. Более того, элемент
может соответствовать сразу нескольким селекторам в таблице стилей. В этом
случае к элементу применяются все правила стилей, ассоциированные с такими
селекторами. (Если различные селекторы определяют различные значения для
одних и тех же свойств стилей, значение, ассоциированное с более конкретным
селектором, переопределяет значение, ассоциированное с менее конкретным
селектором, однако более подробное обсуждение выходит за рамки этой книги.)

Для отображения любого элемента документа веб-браузер должен объединить
атрибут style элемента со стилями из всех совпавших селекторов таблицах стилей
документа. Результатом этого объединения является фактический набор свойств
стилей и значений, которые используются для отображения элемента. Этот набор
значений называется вычисленным стилем элемента.

содержание 16.1.2. История развития CSS

CSS – это довольно старый стандарт. В декабре 1996 года был принят стандарт
CSS1 и определены атрибуты для задания цвета, шрифта, полей, рамок и других
базовых стилей. Такие старые браузеры, как Netscape 4 и Internet Explorer 4,
в значительной степени поддерживают CSS1. Вторая редакция стандарта, CSS2,
была принята в мае 1998 года; она определяет более развитые возможности,
наиболее важной из которых является возможность абсолютного позиционирования
элементов. Версия CSS2.1 дополняет и уточняет положения стандарта CSS2. Из
нее были исключены возможности, которые не были реализованы в браузерах.
Текущие браузеры практически полностью реализуют поддержку стандарта CSS2.1,
хотя в версиях IE, предшествовавших IE8, имеются существенные пробелы.

Работа над CSS продолжается и в настоящее время. Третья версия CSS разделена
на специализированные модули, работа по стандартизации которых ведется по
отдельности. Спецификации и рабочие проекты CSS можно найти по адресу
http://www.wS.org/Style/CSS/current-work.

содержание 16.1.3. Сокращенная форма определения свойств

Свойства стиля, которые часто используются совместно, допускается объединять
вместе, используя сокращенную форму записи. Например, свойства font-family,
font-size, font-style
и font-weight можно определить в виде единственного
свойства font с составным значением:

font: bold italic 24pt helvetica;

Аналогично свойства border, margin и padding являются сокращенными именами
для свойств, определяющих параметры рамок, полей и отступов (пространство
между рамкой и содержимым элемента) для каждой из сторон элемента.
Например, чтобы определить параметры рамки для каждой из сторон в отдельности,
вместо свойства border можно использовать свойства border-left, border-right,
border-top и border-bottom. Каждое из этих свойств также является сокращенной
формой записи. Вместо свойства border-top можно определить свойства
border-top-color, border-top-style и border-top-width.

содержание 16.1.4. Нестандартные свойства

Когда производители браузеров реализуют нестандартные свойства CSS, они
добавляют префикс к именам свойств. В браузере Firefox используется префикс
moz-, в Chrome используется -webkit-, а в IE используется -ms-. Производители браузеров добавляют
префиксы, даже когда реализуют свойства, которые в будущем, как предполагается,
будут включены в стандарт. В качестве примера можно назвать свойство
border-radius, которое определяет закругленные углы. Это свойство впервые было
реализовано как экспериментальное в Firefox 3 и Safari 4, и к его имени были
добавлены соответствующие префиксы. Когда стандарт устоялся в достаточной степени,
в версиях Firefox 4 и Safari 5 префикс был убран, и теперь они поддерживают
свойство border-radius без префикса. (Chrome и Opera уже давно поддерживают
это свойства без префикса. IE9 также поддерживает его без префикса, но IE8 не
поддерживает его, даже с префиксом.)

При работе со свойствами CSS, которые в разных браузерах имеют
отличающиеся имена, можно определять для таких свойств классы:

.radius10 {   
  border-radius: 10px; /* для текущих браузеров */
  -moz-border-radius: 10px; /* для Firefox 3.x */
  -webkit-border-radius: 10px; /* для Safari 3.2 и 4 */
}   

Определив такой класс, можно просто добавить значение «radiuslO» в атрибут
class любого элемента, чтобы дать элементу рамку с закругленными углами.

содержание 16.1.5. Пример CSS-таблицы

Пример 16.1 представляет собой HTML-файл, определяющий и использующий
таблицу стилей. Он иллюстрирует селекторы, базирующиеся на имени тега,
атрибутах class и id, а также содержит встроенный стиль, определяемый
атрибутом style. На рис. 16.1 показано, как этот пример отображается в браузере.

cheme

Рис. 16.1. Веб-страница, оформленная с помощью CSS

Пример 16.1. Определение и использование каскадных таблиц стилей

Example 16-1. Defining and using Cascading Style Sheets
<head>
<style type="text/css">
/* Указывает, что заголовки отображаются курсивом синего цвета. */
h1, h2 { color: blue; font-style: italic }
/*
* Любой элемент с атрибутом class="WARNING" отображается крупными жирными
* символами, имеет большие поля и желтый фон с жирной красной рамкой.
*/
.WARNING {
          font-weight: bold;
          font-size: 150%;
          margin: 0 1in 0 1in; /* сверху справа, снизу слева */
          background-color: yellow;
          border: solid red 8px;
          padding: 10px; /* 10 пикселов со всех 4 сторон */
}
/*
* Текст заголовков h1 и h2 внутри элементов с атрибутом class="WARNING"
* должен быть выровнен по центру, в дополнение к выделению синим курсивом.
*/
.WARNING h1, .WARNING h2 { text-align: center }
/* Отдельный элемент с атрибутом id="special" отображается прописными буквами по центру. */
#special {
          text-align: center;
          text-transform: uppercase;
}
</style>
</head>
<body>
<h1>Cascading Style Sheets Demo</h1>
<div class="WARNING">
<h2>Warning</h2>
This is a warning!
Notice how it grabs your attention with its bold text and bright colors.
Also notice that the heading is centered and in blue italics.
</div>
<p id="special">
This paragraph is centered<br>
and appears in uppercase letters.<br>
<span style="text-transform: none">
Here we explicitly use an inline style to override the uppercase letters.
</span>

Ультрасовременные свойства CSS

Когда я работал над этой главой, CSS находился в процессе революционных
изменений: производители браузеров реализовали поддержку новых
мощных свойств стиля, таких как border-radius, text-shadow, box-shadow и
column-count. Другой качественно новой возможностью CSS стали веб-шрифты:
новое CSS-правило @font-face позволяет загружать и использовать
нестандартные шрифты (подробнее о шрифтах, которые свободно могут
использоваться в веб-страницах, и о простом механизме их загрузки с серверов
компании Google можно прочитать на странице
http://code.google.com/webfonts).

Еще одной революционной разработкой в области каскадных таблиц
стилей стал модуль «CSS Transitions». Этот проект стандарта определяет
возможности, позволяющие преобразовать в анимационные эффекты любые
динамические изменения стилей CSS в документе (когда поддержка этого
стандарта будет реализована достаточно широко, это позволит избавиться
от программного кода, воспроизводящего анимационные эффекты,
связанные со сменой стилей CSS, как показано в разделе 16.3.1). Положения
модуля «CSS Transitions» реализованы во всех текущих браузерах, кроме IE, но
в именах свойств стиля присутствуют префиксы производителей. Проект
родственного стандарта «CSS Animations», использующий модуль «CSS
Transitions» в качестве основы, определяет более сложные анимационные
последовательности. В настоящее время «CSS Animations» реализован
только в веб-браузерах, основанных на механизме Webkit. Ни один из этих
стандартов не описывается в данной главе, но вам, как веб-разработчикам,
нужно знать о существовании этих технологий.

Другим проектом, касающимся CSS, и о котором должны знать
веб-разработчики, является стандарт «CSS Transforms», позволяющий определять
двухмерные преобразования (вращение, масштабирование, перемещение,
а также их комбинации, определяемые в матричном виде), применяемые
к любым элементам. Все текущие браузеры (включая версии IE9 и выше)
поддерживают этот проект с добавлением приставок, соответствующих
производителям. Более того, в Safari реализована поддержка расширения,
позволяющего выполнять трехмерные преобразования, но пока неясно,
последуют ли этому другие браузеры.

содержание 16.2. Наиболее важные CSS-свойства содержание

Для разработчиков клиентских сценариев на языке JavaScript наиболее
важными являются CSS-свойства, которые позволяют задавать режим видимости,
размер и точную позицию отдельных элементов документа. Другие CSS-свойства
дают возможность определять порядок наложения слоев, степень прозрачности,
вырезанные области, поля, отступы, рамки и цвета. При работе с CSS-свойства-
ми важно понимать, как работают свойства стиля. Они перечислены в табл. 16.1
и более подробно описываются в последующих разделах.

Таблица 16.1. Наиболее важные CSS-свойства

Свойство Описание
position Определяет тип позиционирования, применяемый к элементу
top. left Позиция верхнего и левого краев элемента
bottom, right Позиция нижнего и правого краев элемента
width, height Размер элемента
z-index «Порядок в стеке» относительно любых перерывающих его элементов (третье измерение в позиционировании элемента)
display Режим отображения элемента
visibility Режим видимости элемента
clip «Область отсечения» элемента (отображаются только те части документа, которые находятся внутри этой области)
overflow Определяет, что следует делать, если размер элемента больше, чем предоставленное ему место
margin, border, padding Границы и рамки элемента
background Цвет фона или фоновый рисунок для элемента
opacity Степень непрозрачности (или прозрачности) элемента. Это свойство относится к стандарту CSS3 и поддерживается не всеми браузерами. Работающая альтернатива имеется для IE

содержание 16.2.1. Позиционирование элементов с помощью CSS

CSS-свойство position задает тип позиционирования, применяемый к элементу.
Это свойство может иметь четыре возможных значения:

static

Это значение, применяемое по умолчанию. Оно указывает, что элемент
позиционируется статически в соответствии с нормальным порядком вывода
содержимого документа (для большинства западных языков – слева направо
и сверху вниз). Статически позиционированные элементы не могут
позиционироваться с помощью свойств top, left и других. Для позиционирования
элемента документа с применением приемов CSS сначала нужно установить его
свойство position равным одному из трех других значений.

absolute

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

fixed

Это значение позволяет зафиксировать положение элемента относительно
окна браузера. Элементы с фиксированным позиционированием не
прокручиваются с остальной частью документа. Как и абсолютно позиционированные,
фиксировано позиционированные элементы не зависят от всех остальных
элементов и не являются частью потока вывода документа. Фиксированное
позиционирование поддерживается большинством современных браузеров, ис;
ключая IE6.

relative

Если свойство position имеет значение relative, элемент располагается в
соответствии с нормальным потоком вывода, а затем его положение смещается
относительно его обычного положения в потоке. Пространство, выделенное для
элемента в нормальном потоке вывода документа, остается выделенным для
него, и элементы, расположенные со всех сторон от него, не смыкаются для
заполнения этого пространства и не «выталкиваются» с новой позиции
элемента.

Присвоив свойству position элемента значение, отличное от static, можно задать
положение элемента с помощью произвольной комбинации свойств left, top, right
и bottom. Чаще всего для позиционирования используются свойства left и top,
задающие расстояние от левого края элемента-контейнера (обычно самого
документа) до левого края позиционируемого элемента и расстояние от верхнего края
контейнера до верхнего края элемента. Так, чтобы поместить элемент на расстоянии
100 пикселов от левого края и 100 пикселов от верхнего края документа, можно
задать CSS-стили в атрибуте style, как показано ниже:

<div style="position: absolute; left: 100px; top: 100px;">

Если для элемента задана абсолютная позиция, значения его свойств top и left
интерпретируются как расстояния до ближайшего родительского элемента,
свойство position которого имеет любое значение, кроме static. Если абсолютно
позиционируемый элемент не имеет позиционируемого предка, его свойства top и left
будут определять координаты относительно начала документа – левого верхнего
его угла. Если вам потребуется позиционировать элемент относительно
контейнера, который является частью обычного потока вывода документа, определите
в контейнере свойство position:relative и укажите значение 0px в свойствах top
и left контейнера. В этом случае контейнер будет позиционироваться
динамически и останется при этом на обычном месте в потоке вывода документа. Любые
абсолютно позиционируемые вложенные элементы будут позиционироваться
относительно контейнера.

При позиционировании элементов чаще всего задается положение верхнего
левого угла элемента с помощью атрибутов left и top, но точно так же можно задать
положение нижнего и правого краев элемента относительно нижнего и правого
краев элемента-контейнера с помощью атрибутов right и bottom. Например, при
помощи следующих стилей можно указать, что правый нижний угол элемента
должен находиться в правом нижнем углу документа (предполагается, что он не
вложен в другой динамический элемент):

position: absolute; right: 0px; bottom: 0px;

Чтобы верхний край элемента располагался в 10 пикселах от верхнего края окна,
а правый – в 10 пикселах от правого края окна и при этом не прокручивался
вместе с документом, можно использовать такие стили:

position: fixed; right: 10px; top: 10px;

Помимо позиций элементов CSS позволяет указывать их размеры. Чаще всего это
делается путем задания значений свойств стиля width и height. Например,
следующая разметка HTML создаст абсолютно позиционированный элемент без
содержимого. Его свойствам width, height и background-color присвоены такие значения,
что он будет отображаться в виде маленького синего квадрата:

<div style="position: absolute; top: 10px; left: 10px;
            width: 10px; height: 10px; background-color: blue">
</div>

Другой способ задать ширину элемента состоит в одновременном задании
значений обоих свойств, left и right. Аналогично можно задать высоту элемента,
одновременно указав оба свойства, top и bottom. Однако если задать значения для
свойств left, right и width, то свойство width переопределит свойство right, а если
ограничивается высота элемента, то более высоким приоритетом будет
пользоваться свойство height.

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

Стандарт CSS требует, чтобы в значениях свойств, определяющих позицию
и размер, указывались единицы измерения. В предыдущих примерах значения
свойств позиционирования и размера задавались с суффиксом «px», означающим
«pixels» (пикселы). Можно также использовать другие единицы измерения:
дюймы («in»), сантиметры («cm»), пункты («pt») и «em» (размер высоты строки
текущего шрифта).

Помимо единиц измерения, представленных выше, CSS позволяет задавать
положение и размер элемента в процентах от размера элемента-контейнера.
Например, следующая разметка HTML создаст пустой элемент с черной рамкой,
имеющий ширину и высоту в половину элемента-контейнера (или окна браузера) и
расположенный в этом элементе по центру:

<div style="position: absolute; left: 25%; top: 25%; width: 50%; height: 50%;
            border: 2px solid black">
</div>

содержание 16.2.1.1. Третье измерение: z-index

Мы видели, что свойства left, top, right и bottom позволяют указывать
координаты X и Y элемента в двухмерной плоскости элемента-контейнера. Свойство z-index
определяет что-то вроде третьего измерения: оно позволяет определить порядок
наложения элементов и указать, какой из двух или более перекрывающихся
элементов должен располагаться поверх других. Атрибут z-index представляет собой
целое число. По умолчанию его значение равно нулю, но можно задавать
положительные и отрицательные значения. Когда два или более элементов
перекрываются, они отображаются в порядке от меньших значений z-index к большим, т. е.
элемент с большим значением z-index отображается поверх всех остальных. Если
перекрывающиеся элементы имеют одинаковые значения z-index, они отображаются
в порядке следования в документе, поэтому наверху оказывается последний
из перекрывающихся элементов.

Обратите внимание, что порядок наложения определяется свойством z-index только
для смежных элементов (т. е. для дочерних элементов одного контейнера).
Если перекрываются два несмежных элемента, то на основе индивидуальных
значений свойств z-index нельзя указать, какой из них должен находиться сверху.
Вместо этого надо задать атрибут z-index для двух смежных контейнеров
перекрывающихся элементов.

Способ размещения непозиционируемых элементов (элементов со значением по
умолчанию режима позиционирования position:static) исключает возможность
перекрытия, поэтому к ним свойство z-index не применяется. Тем не менее они
получают значение z-index, по умолчанию равное нулю, т. е. позиционируемые
элементы с положительным значением z-index отображаются поверх обычного
потока вывода документа, а позиционируемые элементы с отрицательным
значением z-index оказываются ниже обычного потока вывода документа.

содержание 16.2.1.2. Пример позиционирования средствами CSS:

Спецификация CSS3 включает свойство text-shadow, позволяющее добиться
эффекта отбрасывания тени текстовыми элементами. Данное свойство
поддерживается многими текущими браузерами, однако добиться эффекта тени можно
и с помощью CSS-свойств позиционирования, для чего достаточно
продублировать, сместив, выводимый текст:

<!-- Свойство text-shadow производит тень автоматически -->
<span style="text-shadow: 3px 3px 1px #888">Shadowed</span>
<!-- Ниже показано, как добиться похожего эффекта с помощью механизма позиционирования. -->
<span style="position:relative;">
  С тенью <!-- Это основной текст, отбрасывающий тень. -->
  <span style="position:absolute; top:3px; left:3px; z-index:-1; color: #888">
    С тенью <!-- Это тень -->
  </span>
</span>

Текст, отбрасывающий тень, заключается в относительно позиционируемый
элемент <span>. Для него не определяются свойства, задающие позицию, поэтому
текст отображается в обычной позиции в потоке. Тень заключается в абсолютно
позиционируемый элемент <span>, помещенный в относительно позиционируемый
элемент <span> (и поэтому позиционируется относительно него). Свойство z-index
обеспечивает отображение тени под текстом.

содержание 16.2.2. Рамки, поля и отступы

Стандарт CSS позволяет задавать поля, рамки и отступы для любого элемента.
Рамка элемента – это прямоугольник, обрисованный вокруг (полностью или
частично) этого элемента. CSS-свойства позволяют задать стиль, цвет и толщину
рамки:

border: solid black 1px; /* рамка рисуется черной сплошной линей, толщиной 1 пиксел */
border: 3px dotted red;  /* рамка рисуется красной пунктирной линией толщиной 3 пиксела */

Толщину, стиль и цвет рамки можно задать с помощью отдельных CSS-свойств,
а также отдельно для каждой из сторон элемента. Например, чтобы нарисовать
линию под элементом, достаточно просто определить свойство border-bottom.
Можно даже задать толщину, стиль и цвет рамки только для одной стороны элемента
с помощью таких свойств, как border-top-width и border-left-color.

В CSS3 можно закруглить все углы рамки, определив свойство border-radius, или
отдельные углы, задействовав более конкретные свойства. Например:

border-top-right-radius: 50px;

Свойства margin и padding задают ширину пустого пространства вокруг элемента.
Отличие (очень важное) заключается в том, что свойство margin задает ширину
пустого пространства снаружи от рамки, между рамкой и окружающими
элементами, а свойство padding – внутри рамки, между рамкой и содержимым элемента.
Поля (margin) позволяют визуально отделить элемент (возможно, окруженный
рамкой) от соседних элементов в нормальном потоке вывода документа. Отступы
(padding) позволяют визуально отделить содержимое элемента от его рамки.
Если элемент не имеет рамки, определять ширину отступов обычно не требуется.
Если элемент позиционируется динамически, он выпадает из нормального
потока вывода документа, и для него не имеет смысла определять ширину полей.

Поля и отступы элемента задаются с помощью свойств margin и padding:

margin: 5px; padding: 5px;

Можно также определить поля и отступы для каждой из сторон элемента в
отдельности:

margin-left: 25px;
padding-bottom: 5px;

Также можно задать величины полей и отступов для каждой из четырех сторон
элемента с помощью свойств margin и padding, указав первым значение для
верхней стороны и далее по часовой стрелке: сверху, справа, снизу и слева. Например,
в следующем фрагменте приводятся два эквивалентных способа задания
различных значений отступов для каждой из четырех сторон элемента:

padding: 1px 2px 3px 4px;
/* Предыдущая строка эквивалентна четырем следующим. */
padding-top: 1px;
padding-right: 2px;
padding-bottom: 3px;
padding-left: 4px;

Порядок работы с атрибутом margin ничем не отличается.

содержание 16.2.3. Блочная модель и детали позиционирования в CSS

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

Рис. 16.2 иллюстрирует блочную модель CSS и наглядно показывает, какой смысл
имеют свойства top, left, width и height для элементов с рамками и отступами.

cheme

Рис. 16.2. Блочная модель в CSS: рамки, отступы и свойства позиционирования

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

Рис. 16.2 содержит также другую важную информацию. Во-первых, свойства width
и height задают только размеры области содержимого элемента – они не включают
дополнительное пространство, занимаемое отступами или рамками (и полями)
элементов. Чтобы определить полный размер, занимаемый на экране элементом
с рамкой, необходимо прибавить к ширине элемента ширину левого и правого
отступов и толщину левой и правой рамок, а к высоте элемента необходимо
прибавить ширину верхнего и нижнего отступов и толщину верхней и нижней рамок.

Во-вторых, свойства left и top задают расстояние от внутреннего края рамки
контейнера до внешнего края рамки позиционируемого элемента. Эти свойства
определяют расстояние не от левого верхнего угла области содержимого контейнера,
а от левого верхнего угла области, занимаемой отступами контейнера.
Аналогично свойства right и bottom определяют расстояние от правого нижнего угла
области, занимаемой отступами.

Для полной ясности рассмотрим несложный пример. Предположим, что у вас
есть динамически позиционируемый элемент, вокруг содержимого которого имеются
отступы размером 10 пикселов, а вокруг них – рамка толщиной 5 пикселов.
Теперь предположим, что вы динамически позиционируете дочерний элемент
внутри этого контейнера. Если установить свойство left дочернего элемента
равным «0px», обнаружится, что левый край дочернего элемента будет находиться
непосредственно у внутреннего края рамки контейнера. При этом значении свойства left
дочерний элемент перекроет отступы контейнера, хотя предполагается, что
они остаются пустыми (т. к. для этого и предназначены отступы). Чтобы
поместить дочерний элемент в левый верхний угол области содержимого контейнера,
необходимо присвоить свойствам left и top значение «10px».

содержание 16.2.3.1. Модель border-box и свойство box-sizing

Стандартная блочная модель CSS определяет, что свойства стиля width и height
задают размер области содержимого элемента и не учитывают ширину отступов
и толщину рамки. Эту модель можно было бы назвать «content-box». Эта модель
имеет исключения, наблюдаемые в старых версиях IE и в новых версиях CSS.
При отображении страниц в IE версии ниже 6 или в IE6, 7 или 8 в «режиме
совместимости» (когда страница не имеет объявления <!DOCTYPE> или это
объявление недостаточно строгое), свойства width и height включают ширину отступов
и толщину рамок.

Поведение IE ошибочно, но нестандартная блочная модель, реализованная в IE,
иногда бывает весьма удобна. Учитывая это, в стандарт CSS3 было добавлено
свойство box-sizing. По умолчанию оно имеет значение content-box, которое
указывает, что используется стандартная блочная модель, описанная выше. Если
вместо него указать значение box-sizing: border-box, браузер будет использовать
блочную модель IE и свойства width и height будут включать рамки и отступы.
Модель border-box особенно удобно использовать, когда желательно задать общий
размер элемента в процентах, а ширину отступов и толщину рамки – в пикселах:

<div style="box-sizing:border-box; width: 50%;
            padding: 10px; border: solid black 2px;">

Свойство box-sizing поддерживается всеми текущими браузерами, но пока не во
всех оно реализовано без префикса. В Chrome и Safari свойство имеет имя
-webkit-box-sizing. В Firefox используется -moz-box-sizing. В Opera и IE8 (и выше) свойство имеет имя
box-sizing без префикса.

Будущей альтернативой модели border-box, предусматриваемой стандартом CSS3,
являются вычисляемые значения свойств:

<div style="width: calc(50%-12px); padding: 10px; border: solid black 2px;"&пt;

Возможность вычисления значений CSS-свойств с применением calc()
поддерживается в IE9 и в Firefox 4 (как -moz-calc()).

содержание 16.2.4. Отображение и видимость элементов

Управлять видимостью элемента документа позволяют два CSS-свойства:
visibility и display. Пользоваться свойством visibility очень просто: если оно имеет
значение hidden, то элемент не отображается, если visible, – отображается.
Свойство display является более универсальным и служит для задания варианта
отображения элемента, определяя, блочный это элемент, встраиваемый, списочный
или какой-нибудь другой. Если же свойство display имеет значение none, то
элемент вообще не отображается и для него даже не выделяется место на странице.

Различие между свойствами стиля visibility и display имеет отношение к их
воздействию на статически или относительно позиционируемые элементы. Для
элемента, расположенного в нормальном потоке вывода документа, установка
свойства visibility в значение hidden делает элемент невидимым, но резервирует для
него место в документе. Такой элемент может повторно скрываться и
отображаться без изменения компоновки документа. Однако если свойство display элемента
установлено в значение none, то место в документе для него не выделяется;
элементы с обеих сторон от него смыкаются, как будто его вообще не существует.
Свойство display может пригодиться, например, при создании
разворачивающихся и сворачивающихся списков.

Обратите внимание, что нет особого смысла использовать атрибуты visibility
и display, чтобы сделать элемент невидимым, если вы не собираетесь
динамически устанавливать их в сценарии на языке JavaScript, чтобы в какой-то момент
сделать его снова видимым! Как это делается, будет показано далее в этой главе.

содержание 16.2.5. Цвет, прозрачность и полупрозрачность

Цвет текста, содержащегося в элементе документа, можно задать с помощью
CSS-свойства color. Цвет фона любого элемента – с помощью свойства
background-color. Выше мы видели, что цвет рамки элемента можно задать с помощью
свойства border-color или сокращенной формы его написания border.

При обсуждении рамок мы рассматривали пример, в котором цвет рамки
задавался указанием названий наиболее распространенных цветов, таких как «red»
(красный) и «black» (черный). Стандарт CSS поддерживает множество таких
обозначений цветов на английском языке, но имеется более универсальный способ
определения цветов, который заключается в использовании шестнадцатеричных
цифр, определяющих красную, зеленую и синюю составляющие цвета. Значения
каждой из составляющих могут задаваться одной или двумя цифрами. Например:

#000000 /* black, черный */
#fff /* white, белый */
#f00 /* bright red, ярко-красный */
#404080 /* dark unsaturated blue, ненасыщенный темно-синий */
#ccc /* light gray, светло-серый */

Стандарт CSS3 дополнительно определяет возможность определения цвета в
формате RGBA (значения красной, зеленой и синей составляющих плюс
альфа-значение, определяющее степень прозрачности). Формат RGBA поддерживается всеми
современными браузерами, кроме IE; ожидается, однако, что его поддержка
будет включена в IE9. CSS3 также определяет поддержку форматов HSL
(hue-saturation-value – тон-насыщенность-яркость) и HSLA. И снова эти форматы
поддерживаются браузерами Firefox, Safari и Chrome, но не поддерживаются IE.

Таблицы CSS позволяют точно указать позицию, размеры, цвета фона и рамки
элемента, что обеспечивает элементарные графические средства рисования
прямоугольников и (если до предела уменьшить высоту или ширину)
горизонтальных или вертикальных линий. В предыдущее издание книги был включен
пример рисования столбчатых диаграмм средствами CSS, но в этом издании он был
заменен расширенным описанием элемента <canvas> (подробнее о работе с
графикой на стороне клиента рассказывается в главе 21).

В дополнение к атрибуту background-color можно также указать изображение,
которое должно использоваться в качестве фоновой картинки элемента. Свойство
background-image определяет фоновое изображение, а свойства
background-attachment, background-position и background-repeat уточняют некоторые параметры
рисования изображения. Сокращенная форма записи – свойство background,
позволяющее указывать все эти атрибуты вместе. Свойства, определяющие фоновый
рисунок, могут применяться для создания довольно интересных визуальных
эффектов, но это уже выходит за рамки темы данной книги.

Очень важно понимать, что если цвет фона или фоновый рисунок элемента не
задан, то фон элемента обычно прозрачный. Например, если поверх некоторого
текста в обычном потоке вывода документа расположить элемент <div> с абсолютным
позиционированием, то по умолчанию текст будет виден через элемент <div>.
Если же элемент <div> содержит собственный текст, символы окажутся
наложенными друг на друга, образуя трудную для чтения мешанину. Однако не все
элементы по умолчанию прозрачны. Например, элементы форм выглядели бы нелепо
с прозрачным фоном, и такие элементы, как <button>, имеют цвет фона по
умолчанию. Переопределить значение цвета по умолчанию можно с помощью свойства
background-color; при необходимости можно явно установить цвет фона
прозрачным («transparent»).

Прозрачность, о которой мы до сих пор говорили, может быть либо полной, либо
нулевой: элемент имеет либо прозрачный, либо непрозрачный фон. Однако
существует возможность получить полупрозрачный элемент (для содержимого как
заднего, так и переднего плана). (Пример полупрозрачного элемента приведен на
рис. 16.3.) Делается это с помощью свойства opacity, определяемого стандартом
CSS3. Значением этого свойства является число в диапазоне от 0 до 1, где 1
означает 100-процентную непрозрачность (значение по умолчанию), а 0 –
100-процентную прозрачность. Свойство opacity поддерживается всеми текущими
браузерами, кроме IE. В IE аналогичная функциональность реализуется с помощью
специфичного свойства filter. Чтобы сделать элемент непрозрачным на 75%,
можно воспользоваться следующими CSS-стилями:

opacity: .75;              /* стандартный стиль прозрачности в CSS3 */
filter: alpha(opacity=75); /* прозрачность в IE; обратите внимание на отсутствие десятичной точки */

содержание 16.2.6. Частичная видимость: свойства overflow и clip

Свойство visibility позволяет полностью скрыть элемент документа. С помощью
свойств overflow и clip можно отобразить только часть элемента. Свойство overflow
определяет, что происходит, когда содержимое документа превышает размер,
указанный для элемента (например, в свойствах стиля width и height). Далее
перечислены допустимые значения этого свойства и указано их назначение:

visible

Содержимое может выходить за пределы и по необходимости
прорисовываться вне прямоугольника элемента. Это значение по умолчанию.

hidden

Содержимое, вышедшее за пределы элемента, обрезается и скрывается, так
что никакая часть содержимого никогда не прорисовывается вне области,
определяемой свойствами размера и позиционирования.

scroll

Область элемента имеет постоянные горизонтальную и вертикальную полосы
прокрутки. Если содержимое превышает размеры области, полосы прокрутки
позволяют увидеть остальное содержимое. Это значение учитывается, только
когда документ отображается на экране компьютера; когда документ
выводится, например, на бумагу, полосы прокрутки, очевидно, не имеют смысла.

auto

Полосы прокрутки отображаются не постоянно, а только когда содержимое
превышает размер элемента.

Если свойство overflow определяет, что должно происходить, когда содержимое
элемента превысит область элемента, то с помощью свойства clip можно точно
указать, какая часть элемента должна отображаться независимо от того,
выходит ли содержимое за пределы элемента. Это свойство особенно полезно для
создания эффектов, когда элемент открывается или проявляется постепенно.

Значение свойства clip задает область отсечения элемента. В CSS2 области
отсечения прямоугольные, но синтаксис атрибута clip обеспечивает возможность
в следующих версиях стандарта задавать области отсечения, отличные от
прямоугольных. Синтаксис свойства clip:

rect(top right bottom left)

Значения top, right, bottom и left задают границы прямоугольника отсечения
относительно левого верхнего угла области элемента. Чтобы, например, вывести
только часть элемента в области 100 х 100 пикселов, можно задать для этого
элемента следующий атрибут style:

style="clip: rect(0px 100px 100px 0px);"

Обратите внимание, что между значениями нет запятых, и края области
отсечения задаются по часовой стрелке, начиная с верхнего края.

содержание 16.2.7. Пример: перекрытие полупрозрачных окон

Данный раздел завершается примером, который демонстрирует порядок работы
с большинством обсуждавшихся CSS-свойств. В примере 16.2 CSS-стили используются
для создания визуального эффекта наложения полупрозрачного окна на
другое окно, обладающее полосой прокрутки. Результат приводится на рис. 16.3.

cheme

Рис. 16.3. Окна, созданные с помощью CSS

Пример не содержит JavaScript-код и в нем нет никаких обработчиков событий,
поэтому возможность взаимодействия с окнами отсутствует (иначе как через
полосу прокрутки), но это очень интересная демонстрация эффектов, которые
можно получить средствами CSS.

Пример 16.2. Отображение окон с использованием CSS-стилей

Example 16-2. Displaying windows with CSS
<!DOCTYPE html>
<head>
<style type="text/css">
/**
 * Эта таблица CSS-стилей определяет три правила стилей, которые используются
 * в теле документа для создания визуального эффекта "окна". В правилах использованы
 * свойства позиционирования для установки общего размера окна и расположения
 * его компонентов. Изменение размеров окна требует аккуратного
 * изменения атрибутов позиционирования во всех трех правилах.
**/
div.window { /* Определяет размер и рамку окна */
    position: absolute; /* Положение задается в другом месте */
    width: 300px; height: 200px;/* Размер окна без учета рамок */
    border: 3px outset gray; /* Обратите внимание на ЗР-эффект рамки */
}
div.titlebar { /* Задает положение, размер и стиль заголовка */
    position: absolute; /* Это позиционируемый элемент */
    top: 0px; height: 18px; /* Высота заголовка 18рх + отступ и рамка */
    width: 290px; /* 290 + 5рх отступы слева и справа = 300 */
    background-color: #aaa; /* Цвет заголовка */
    border-bottom: groove gray 2px; /* Заголовок имеет рамку только снизу */
    padding: 3px 5px 2px 5px; /* Значения по часовой стрелке: сверху, справа, снизу, слева */
    font: bold 11pt sans-serif; /* Шрифт заголовка */
}
div.content { /* Задает размер, положение и прокрутку содержимого окна */
    position: absolute; /* Это позиционируемый элемент*/
    top: 25px; /* 18рх заголовок+2рх рамка+3рх+2рх отступ */
    height: 165px; /* 200px всего - 25px заголовок - 10px отступ */
    width: 290px; /* 300px ширина - 10px отступ */
    padding: 5px; /* Отступы со всех четырех сторон */
    overflow: auto; /* Разрешить появление полос прокрутки */
    background-color: #fff; /* По умолчанию белый фон */
}
div.translucent { /* Этот класс делает окно частично прозрачным */
    opacity: .75; /* Стандартный стиль прозрачности */
    filter: alpha(opacity=75); /* Прозрачность для IE */
}
</style>
</head>
<body>
<!-- Порядок определения окна: элемент div "окна" с заголовком и элемент div -->
<!-- с содержимым, вложенный между ними. Обратите внимание, как задается -->
<!-- позиционирование с помощью атрибута style, дополняющего -->
<!-- стили из таблицы стилей -->
<div class="window" style="left: 10px; top: 10px; z-index: 10;">
<div class="titlebar">Test Window</div>
<div class="content">
1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>0<br><!-- Множество строк для -->
1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>0<br><!-- демонстрации прокрутки -->
</div>
</div>
<!-- Это еще одно окно с другими позицией, цветом и шрифтом -->
<div class="window" style="left: 75px; top: 110px; z-index: 20;">
<div class="titlebar">Another Window</div>
<div class="content translucent"
     style="background-color:#ccc; font-weight:bold;">
Это еще одно окно. Значение атрибута <tt>z-index</tt> этого окна заставляет
его расположиться поверх другого. За счет CSS-стилей содержимое этого окна
будет выглядеть полупрозрачным в браузерах, поддерживающих такую возможность.
</div>
</div>

Основной недостаток этого примера в том, что таблица стилей задает
фиксированный размер всех окон. Так как заголовок и содержимое окна должны точно
позиционироваться внутри окна, изменение размера окна требует изменения
значений различных свойств позиционирования во всех трех правилах,
определенных в таблице стилей. Это трудно сделать в статическом HTML-документе, но все
становится проще, если использовать сценарий, устанавливающий все
необходимые свойства. Эта возможность рассматривается в следующем разделе.

содержание 16.3. Управление встроенными стилями содержание

Самый простой способ управления стилями CSS – это манипулирование
атрибутом style отдельных элементов документа. Как и для большинства
HTML-атрибутов, атрибуту style соответствует одноименное свойство объекта Element, и им
можно манипулировать в сценариях на языке JavaScript. Однако свойство style
имеет одну отличительную особенность: его значением является не строка, а
объект CSSStyleDeclaration. Свойства этого объекта представляют CSS-свойства,
определенные в HTML-атрибуте style. Например, чтобы вывести содержимое
текстового элемента e крупным, полужирным шрифтом синего цвета, можно
выполнить следующие операции для записи желаемых значений в свойства, которые
соответствуют свойствам стиля font-size, font-weight и color:

e.style.fontSize = "24pt";
e.style.fontWeight = "bold";
e.style.color = "blue";

Соглашения об именах: CSS-свойства в JavaScript

Многие CSS-свойства стиля, такие как font-size, содержат в своих именах
дефис. В языке JavaScript дефис интерпретируется как знак минус,
поэтому нельзя записать выражение, приведенное ниже:

e.style.font-size = "24pt"; // Syntax error!

Таким образом, имена свойств объекта CSSStyleDeclaration слегка
отличаются от имен реальных CSS-свойств. Если имя CSS-свойства содержит
дефисы, имя свойства объекта CSSStyleDeclaration образуется путем удаления
дефисов и перевода в верхний регистр буквы, непосредственно следующей
за каждым из них. Другими словами, CSS-свойство border-left-width
доступно через свойство borderLeftWidth, а к CSS-свойству font-family можно
обратиться следующим образом:

e.style.fontFamily = "sans-serif";

Кроме того, когда CSS-свойство, такое как float, имеет имя, совпадающее
с зарезервированным словом языка JavaScript, к этому имени добавляется
префикс «ess», чтобы создать допустимое имя свойства объекта
CSSStyleDeclaration. То есть, чтобы прочитать или изменить значение CSS-свойства
float элемента, следует использовать свойство cssFloat объекта
CSSStyleDeclaration.

При работе со свойствами стиля объекта CSSStyleDeclaration не забывайте, что все
значения должны задаваться в виде строк. В таблице стилей или атрибуте style
можно написать:


position: absolute; font-family: sans-serif; background-color: tfffffff;

Чтобы сделать то же самое для элемента e в JavaScript, необходимо заключить
все значения в кавычки:


e.style.position = "absolute";
e.style.fontFamily = "sans-serif";
e.style.backgroundColor = "tfffffff";

Обратите внимание, что точки с запятыми не входят в строковые значения. Это
точки с запятой, употребляемые в синтаксисе языка JavaScript. Точки с запятой,
используемые в таблицах стилей CSS, не нужны в строковых значениях,
устанавливаемых с помощью JavaScript.

Кроме того, помните, что во всех свойствах позиционирования должны быть
указаны единицы измерения. То есть нельзя устанавливать свойство left подобным
образом:

e.style.left = 300; // Неправильно: это число, а не строка
e.style.left = "300"; // Неправильно: отсутствуют единицы измерения

Единицы измерения обязательны при установке свойств стиля в JavaScript – так
же, как при установке свойств стиля в таблицах стилей. Ниже приводится
правильный способ установки значения свойства left элемента e, равным 300
пикселам:

e.style.left = "ЗООрх";

Чтобы установить свойство left равным вычисляемому значению, обязательно
добавьте единицы измерения в конце вычислений:

e.style.left = (х0 + left_margin + left_border + left_padding) + "px";

Как побочный эффект, добавление строки с единицами измерения преобразует
вычисленное значение из числа в строку.

Напомню, что некоторые CSS-свойства, такие как margin, представляют собой
сокращенную форму записи других свойств, таких как margin-top, margin-right,
margin-bottom и margin-left. Объект CSSStyleDeclaration имеет свойства,
соответствующие этим сокращенным формам записи свойств. Например, свойство margin
можно установить следующим образом:


e.style.margin = topMargin + "рх " + rightMargin + "рх " +
bottomMargin + "рх " + leftMargin + "рх";

Хотя, возможно, кому-то будет проще установить четыре свойства полей по
отдельности:


e.style.marginTop = topMargin + "рх";
e.style.marginRight = rightMargin + "рх";
e.style.marginBottom = bottomMargin + "рх";
e.style.marginLeft = leftMargin + "рх";

Атрибут style HTML-элемента – это его встроенный стиль, и он переопределяет
любые правила стилей в таблице CSS. Встроенные стили в целом удобно
использовать для установки значений стиля, и именно такой подход использовался во
всех приведенных выше примерах. Сценарии могут читать свойства объекта CSSStyleDeclaration,
представляющего встроенные стили, но они возвращают осмысленные значения,
только если были ранее установлены сценарием на языке JavaScript или если
HTML-элемент имеет встроенный атрибут style, установивший нужные свойства.
Например, документ может включать таблицу стилей, устанавливающую левое
поле для всех абзацев равным 30 пикселам, но если прочитать свойство leftMargin
одного из этих элементов, будет получена пустая строка, если только этот абзац
не имеет атрибут style, переопределяющий значение, установленное таблицей
стилей.

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

Иногда бывает проще прочитать или записать единственную строку во
встроенный стиль элемента, чем обращаться к объекту CSSStyleDeclaration. Для этого
можно использовать методы getAttribute() и setAttribute() объекта Element или
свойство cssText объекта
CSSStyleDeclaration:

// Обе инструкции, следующие ниже, записывают в атрибут style
// элемента e строку s:
e.setAttribute("style", s);
e.style.cssText = s;
// Обе инструкции, следующие ниже, получают значение атрибута style
// элемента e в виде строки:
s = e.getAttribute("style");
s = e.style.cssText;

содержание 16.3.1. Создание анимационных эффектов средствами CSS

Одной из наиболее типичных областей применения CSS является
воспроизведение визуальных анимационных эффектов. Реализовать их можно с помощью
метода setTimeout() или setInterval() (раздел 14.1), используя их для организации
многократных вызовов функции, изменяющей встроенный стиль элемента.
Пример 16.3 демонстрирует две такие функции, shake() и fadeOut(). Функция shake()
перемещает, или «встряхивает» (shakes), элемент из стороны в сторону. Бе можно
использовать, например, для привлечения внимания пользователя в случае
ввода некорректных данных. Функция fadeOut() уменьшает непрозрачность
элемента в течение указанного периода времени (по умолчанию 500 миллисекунд),
вызывая эффект его растворения до полного исчезновения.

Пример 16.3. Воспроизведение анимационных эффектов средствами CSS


// Делает элемент e относительно позиционируемым и перемещает его влево и вправо.

// Первым аргументом может быть объект элемента или значение атрибута id требуемого

// элемента. Если во втором аргументе передать функцию, она будет вызвана с элементом e

// в виде аргумента по завершении воспроизведения анимации. Третий аргумент определяет

// величину смещения элемента e. По умолчанию принимает значение 5 пикселов.

// Четвертый аргумент определяет, как долго должен воспроизводиться эффект.

// По умолчанию эффект длится 500 мсек.

function shake(e, oncomplete, distance, time) {

  // Обработка аргументов

  if (typeof e === "string") e = document.getElementByld(e);

  if (!time) time = 500;

  if (!distance) distance = 5;

  var originalStyle = e.style.cssText;     // Сохранить оригинальный стиль e

  e.style.position = "relative";           // Сделать относит, позиционируемым

  var start = (new Date()).getTime();      // Запомнить момент начала анимации

  animate();                         
     // Запустить анимацию

  // Эта функция проверяет прошедшее время и изменяет координаты e.

  // Если анимацию пора завершать, восстанавливает первоначальное состояние

  // элемента e. Иначе изменяет координаты e и планирует следующий свой вызов.

  function animate() {

    var now = (new Date()).getTime();      // Получить текущее время

    var elapsed = now-start;               // Сколько прошло времени с начала?

    var fraction = elapsed/time;           // Доля от требуемого времени?

    if (fraction < 1) {                    // Если рано завершать анимацию

      // Вычислить координату x элемента e как функцию от доли общего

      // времени анимации. Здесь используется синусоидальная функция,

      // а доля общего времени воспроизведения умножается на 4pi,

      // поэтому перемещение взад и вперед выполняется дважды,

      var x = distance * Math.sin(fraction*4*Math.PI);

      e.style.left = x + "px";

      // Попробовать вызвать себя через 25 мсек или в конце запланированного

      // отрезка общего времени воспроизведения. Мы стремимся сделать

      // анимацию гладкой, воспроизводя ее со скоростью 40 кадров/сек.

      setTimeout(animate, Math.min(25, time-elapsed));

    }

    else { // Иначе анимацию пора завершать

      e.style.cssText = originalStyle // Восстановить первонач. стиль

      if (oncomplete) oncomplete(e); // Вызвать ф-цию обратного вызова

    }

  }
}

// Растворяет e от состояния полной непрозрачности до состояния полной прозрачности

// за указанное количество миллисекунд. Предполагается, что. когда вызывается

// эта функция, e полностью непрозрачен, oncomplete - необязательная функция.

// которая будет вызвана с элементом e в виде аргумента по завершении анимации.

// Если аргумент time не задан, устанавливается интервал 500 мсек.

// Эта функция не работает в IE, но ее можно модифицировать так, чтобы

// в дополнение к свойству opacity она использовала нестандартное

// свойство filter, реализованное в IE.

function fadeOut(e, oncomplete, time) {

if (typeof e === "string") e = document.getElementById(e);

if (!time) time = 500;

// В качестве простой "функции перехода", чтобы сделать анимацию немного

// нелинейной, используется Math.sqrt: сначала растворение идет быстро,

// а затем несколько замедляется,

  var ease = Math.sqrt;

  var start = (new Date()).getTime(); // Запомнить момент начала анимации

  animate(); // И запустить анимацию
  function animate() {
    var elapsed = (new Date()).getTime()-start; // Прошедшее время
    var fraction = elapsed/time; // Доля от общего времени
    if (fraction < 1) { // Если не пора завершать
      var opacity = 1 - ease(fraction); // Вычислить непрозрачн.
      e.style.opacity = String(opacity); // Установить ее в e
      setTimeout(animate, // Запланировать очередной
      Math.min(25, time-elapsed)); // кадр
    }
    else { // Иначе завершить
      e.style.opacity = "0"; // Сделать e полностью прозрачным
      if (oncomplete) oncomplete(e); // Вызвать ф-цию обратного вызова
    }
  }
}

Обе функции, shake() и fadeOut(), принимают необязательную функцию
обратного вызова во втором аргументе. Если эта функция указана, она будет вызвана по
завершении воспроизведения анимационного эффекта. Элемент, к которому
применялся анимационный эффект, будет передан функции обратного вызова в виде
аргумента. Следующая разметка HTML создает кнопку, для которой после
щелчка на ней воспроизводится эффект встряхивания, а затем эффект растворения:


Обратите внимание, насколько функции shake() и fadeOut() похожи друг на друга.
Они обе могут служить шаблонами для реализации похожих анимационных
эффектов с использованием CSS-свойств. Однако клиентские библиотеки, такие как
jQuery, обычно поддерживают набор предопределенных визуальных эффектов,
поэтому вам вообще может никогда не потребоваться писать собственные
функции воспроизведения анимационных эффектов, такие как shake(), если только
вам не понадобится создать какой-нибудь сложный визуальный эффект. Одной
из первых и наиболее примечательных библиотек визуальных эффектов
является библиотека Scriptaculous, которая предназначалась для работы в составе
фреймворка Prototype. За дополнительной информацией обращайтесь по адресу
http://script.aculo.us/ и http://scripty2.com/.
Модуль «CSS3 Transitions» определяет еще один способ реализации
анимационных эффектов с помощью таблиц стилей, полностью устраняющий
необходимость писать программный код. Например, вместо функции fadeOutQ можно
было бы определить правило CSS, как показано ниже:


.fadeable { transition: opacity .5s ease-in }

Это правило говорит, что всякий раз, когда изменяется непрозрачность элемента
с классом «fadeable», это изменение должно протекать плавно (от текущего до
нового значения) в течение половины секунды с использованием нелинейной
функции перехода. Модуль «CSS Transitions» еще не был стандартизован, но его
положения уже реализованы в браузерах Safari и Chrome в виде свойства
-webkit-transition. На момент написания этих строк в Firefox 4 также была добавлена
поддержка свойства -moz-transition.

содержание 16.4. Вычисленные стили содержание

Свойство style элемента определяет встроенный стиль элемента. Оно имеет
преимущество перед всеми таблицами стилей и с успехом может применяться для
установки CSS-свойств для изменения визуального представления элемента.
Однако в общем случае к нему нет смысла обращаться, когда требуется узнать
фактически примененные к элементу стили. То, что требуется в этом случае,
называется вычисленным стилем. Вычисленный стиль элемента – это набор значений
свойств, которые браузер получил (или вычислил) из встроенного стиля и всех
правил из всех таблиц стилей, которые применяются к элементу: это набор
свойств, фактически используемый при отображении элемента. Подобно
встроенным стилям, вычисленные стили представлены объектом CSSStyleDeclaration.
Однако в отличие от встроенных стилей вычисленные стили доступны только для
чтения. Эти стили нельзя изменить, но вычисленный объект CSSStyleDeclaration
позволяет точно узнать значения свойств стилей, которые браузер использовал
при отображении соответствующего элемента.

Получить вычисленный стиль элемента можно с помощью метода
getComputedStyle() объекта Window. Первым аргументом этому методу передается элемент,
вычисленный стиль которого требуется вернуть. Второй аргумент является
обязательным, и в нем обычно передается значение null или пустая строка, но в нем
также может передаваться строка с именем псевдоэлемента CSS, таким как
«:before», «:after», «:first-line» или «:first-letter»:


var title = document.getElementById("section1title");
var titlestyles = window.getComputedStyle(element, null);

Возвращаемым значением метода getComputedStyle() является объект
CSSStyleDeclaration, представляющий все стили, применяемые к указанному элементу (или
псевдоэлементу). Между объектами CSSStyleDeclaration, представляющими
встроенные стили и вычисленные стили, существует множество существенных
отличий:

  • Свойства вычисленного стиля доступны только для чтения.
  • Свойства вычисленных стилей имеют абсолютные значения: относительные
    единицы измерения, такие как проценты и пункты, преобразуются в
    абсолютные значения. Любое свойство, которое определяет размер (например, ширина
    поля или размер шрифта), будет иметь значение, выраженное в пикселах. То
    есть его значением будет строка с суффиксом «px», поэтому вам необходимо
    будет реализовать ее синтаксический анализ, зато не придется беспокоиться об
    определении и преобразовании единиц измерений. Значения свойств,
    определяющих цвет, будут возвращаться в формате «rgb(#,#,#)» или «rgba(#,#,#,#)».
  • Свойства, являющиеся краткой формой записи, не вычисляются – только
    фундаментальные свойства, на которых они основаны. Например, не следует
    пытаться получить значение свойства margin, вместо этого нужно обращаться
    к свойствам marginLeft, marginTop и т.д.
  • Свойство cssText вычисленного стиля не определено.

Вычисленные и встроенные стили можно использовать совместно. В примере 16.4
определяются функции scale() и scaleColor(). Первая читает и анализирует
вычисленный размер текста указанного элемента; вторая читает и анализирует
вычисленный цвет фона элемента. Затем обе функции умножают полученное
значение на заданное число и устанавливают результат как встроенный стиль
элемента. (Эти функции не работают в IE8 и в более ранних версиях: как вы узнаете
далее, эти версии IE не поддерживают метод getComputedStyle().)

Пример 16.4. Определение вычисленных стилей и установка встроенных стилей

  //Умножает размер текста элемента e на указанное число factor
  function scale(e, factor) {
    // Определить текущий размер текста, получив вычисленный стиль
    var size = parseInt(window.getComputedStyle(e,""). fontSize);
    // И использовать встроенный стиль, чтобы увеличить этот размер
    e.style.fontSize = factor*size + "рх";
  }
  // Изменяет цвет фона элемента e, умножая компоненты цвета на указанное число.
  // Значение factor > 1 осветляет цвет элемента, a factor < 1 затемняет его.
  function scaleColor(e, factor) {
    var color = window.getComputedStyle(e, ""').backgroundColor; // Получить
    var components = color.match(/[\d\.]+/g); // Выбрать компоненты r.g.b и а
    for(var i = 0; i < 3; i++) { // Цикл по г, g и b
    var x = Number(components[i]) * factor;// Умножить каждый из них
    х = Math.round(Math.min(Math.max(x, 0). 255)); // Округлить и установить границы
    components[i] = String(x);
  }
  if (components.length == 3) // Цвет rgb()
    e.style.backgroundColor = "rgb(" + components.join() + ")";
  else // Цвет rgba()
    e.style.backgroundColor = "rgba(" + components.join() + ")";
}

Работа с вычисленными стилями может оказаться весьма непростым делом, и
обращение к ним не всегда возвращает ожидаемую информацию. Рассмотрим в
качестве примера свойство font-family: оно принимает список разделенных
запятыми имен семейств шрифтов для совместимости. При чтении свойства fontFamily
вычисленного стиля вы ждете значение наиболее конкретного стиля font-family,
применяемого к элементу. А в этом случае может вернуться такое значение, как
«arial,helvetica,sans-serif», которое ничего не говорит о гарнитуре фактически
используемого шрифта. Аналогично, если элемент не является абсолютно
позиционируемым, при попытке определить его размеры или положение через свойства
top и left вычисленного стиля часто возвращается значение «auto». Это вполне
допустимое в CSS значение, но наверняка совсем не то, что вы ожидали бы получить.

Метод getComputedStyle() не поддерживается в IE8 и в более ранних версиях, но,
как ожидается, он будет реализован в IE9. В IE все HTML-элементы имеют
свойство currentStyle, значением которого является объект CSSStyleDeclaration.
Свойство currentStyle в IE объединяет встроенные стили с таблицами стилей, но оно не
является по-настоящему вычисленным стилем, потому что не преобразует
относительные значения в абсолютные. При чтении свойств текущего стиля в IE
могут возвращаться размеры в относительных единицах измерения, таких как «%»
или «em», а цвета в виде неточных названий, таких как «red».

Стили CSS можно использовать, чтобы точно задать позицию и размер элемента
документа, но чтение вычисленного стиля элемента является не самым лучшим
способом узнать его размер и положение в документе. Более простые,
переносимые решения приводятся в разделе 15.8.2.

содержание 16.5. CSS-классы содержание

Альтернативой использованию отдельных CSS-стилей через свойство style
является управление значением HTML-атрибута class. Изменение класса элемента
изменяет набор селекторов стилей, применяемых к элементу, что может приводить
к изменениям значений сразу нескольких CSS-свойств. Предположим,
например, что вам требуется привлечь внимание пользователя к отдельным абзацам
(или другим элементам) в документе. В этом случае можно было бы сначала
определить особый стиль оформления для любых элементов с классом «attention»:


.attention { /* Стили для элементов, требующих внимания пользователя */
background-color: yellow; /* Желтый фон */
font-weight: bold: /* Полужирный шрифт */
border: solid black 2px; /* Черная рамка */
}

Идентификатор class в языке JavaScript является зарезервированным словом,
поэтому HTML-атрибут class в JavaScript-сценариях доступен в виде свойства
с именем className. Ниже приводится пример, который устанавливает и очищает
свойство className элемента, добавляя и убирая класс «attention»:


function grabAttention(e) { е.className = "attention"; }
function releaseAttention(e) { e.className = ""; }

HTML-элементы могут быть членами более чем одного CSS-класса – атрибут class
может содержать целый список имен классов, разделенных пробелами. Имя
className не совсем точно отражает смысл свойства: правильнее было бы дать ему
имя classNames . Функции выше предполагают, что свойство className будет
определять ноль или одно имя класса, и они непригодны в случаях, когда может
использоваться более одного имени класса. Если элемент уже принадлежит
некоторому классу, вызов функции grabAttention() для этого элемента затрет имя
класса, присутствующее в свойстве className .

Стандарт HTML5 решает эту проблему, определяя свойство classList во всех
элементах. Значением этого свойства является объект DOMTokenList: подобный массиву
объект (раздел 7.11),
доступный только для чтения, элементы которого содержат
отдельные имена классов, присвоенных элементу. Однако самыми важными в нем
являются не элементы массива, а методы add() и remove(), добавляющие и
удаляющие отдельные имена классов из атрибута class элемента. Метод toggle()
добавляет имя класса, если оно отсутствует, и удаляет в противном случае. Наконец,
метод contains() проверяет присутствие указанного имени класса в атрибуте class.

Подобно другим классам коллекций в модели DOM, объект DOMTokenList является
«живым» представлением множества классов в элементе, а не статическим
слепком, который был действителен только в момент обращения к свойству classList.
Если сценарий получит объект DOMTokenList, обратившись к свойству classList
элемента, и затем изменит свойство className этого элемента, то выполненные
изменения немедленно отразятся на полученном объекте DOMTokenList. Аналогично
любые изменения, выполненные в объекте DOMTokenList, немедленно отразятся на
значении свойства className.

На момент написания этих строк свойство classList не поддерживалось ни одним
из текущих браузеров. Однако эту удобную функциональность легко можно
реализовать самому, как показано в примере 16.5. Подобная реализация,
позволяющая интерпретировать атрибут class элемента как множество имен классов,
существенно упрощает выполнение многих задач, связанных с обработкой CSS.

Пример 16.5. classList(): интерпретирует className, как множество CSS-классов


/*
* Возвращает свойство classList элемента e. если оно содержит один класс.
* Иначе возвращает объект, имитирующий интерфейс DOMTokenList.
* Возвращаемый объект имеет методы contains(), add(), remove(), toggle() и toString(),
* позволяющие проверять и изменять набор классов элемента e. Если свойство classList
* имеет встроенную поддержку в браузере, функция возвращает объект, подобный массиву,
* который имеет свойство length и поддерживает возможность индексирования массива.
* Имитация объекта DOMTokenList не подобна массиву, но имеет метод toArray().
* который возвращает истинный массив имен классов элемента.
•/
function classList(e) {
  if (e.classList) return e.classList; // Вернуть e.classList, если имеется
  else return new CSSClassList(e);     // Иначе попытаться подделать его
}

// CSSClassList - класс JavaScript, имитирующий объект DOMTokenList
function CSSClassList(e) { this.e = e; }

// Возвращает true, если e.className содержит класс c, иначе - false
CSSClassList.prototype.contains = function(c) {
  // Проверить, является ли c допустимым именем класса
  if (c.length ===0 || cindexOff ") != -1)
    throw new Error("Недопустимое имя класса: '" + c + );
  // Сначала проверить общие случаи
  var classes = this.e.className;
  if (!classes) return false;          // e вообще не имеет классов
  if (classes === c) return true;      // e имеет единственный класс,
                      
                // имя которого точно совпадает c искомым

  // Иначе использовать RegExp для поиска c как отдельного слова
  // \b - в регулярных выражениях соответствует границе слова,
  return classes.search("\\b" + c + "\\b") != -1;
};

// Добавляет имя класса c в e.className. если оно отсутствует в списке
CSSClassList.prototype.add = function(c) {
  if (this.contains(c)) return;         // Ничего не делать, если имя уже в списке
  var classes = this.e.className;
  if (classes && classes[classes.length-1] != " ")
  c = " "' + c;                         // Добавить пробел, если необходим
  this.e.className += c;                // Добавить имя c в className
};

// Удаляет все вхождения c из e.className
CSSClassList.prototype.remove = function(c) {
  // Убедиться, что c - допустимое имя класса
  if (c.length ===0 || c.indexOfC ") != -1)
  throw new Error("Недопустимое имя класса: '" + c + );

  // Удалить все вхождения имени c как слова и все завершающие пробелы
  var pattern = new RegExp("\\b" + c + "\\b\\s*", "g");
  this.e.className = this.e.className.replace(pattern, "");
};

// Добавляет имя c в e.className. если оно отсутствует в списке, и возвращает true.
// Иначе удаляет все вхождения имени c из e.className и возвращает false.
CSSClassList.prototype.toggle = function(c) {
  if (this.contains(c)) { // Если e.className содержит c
    this.remove(c);       // удалить его.
    return false;
  }
  else {                  // Иначе:
    this.add(c);          // добавить его.
    return true;
  }
};

// Возвращает само значение e.className
CSSClassList.prototype.toString = function() { return this.e.className; };
// Возвращает имена из e.className
CSSClassList.prototype.toArray = function() {
  return this.e.className.match(/\b\w+\b/g) 11 [];
}

содержание 16.6. Управление таблицами стилей содержание

До сих пор мы видели, как устанавливать и получать значения CSS-свойств
стиля и классы отдельных элементов. Однако существует еще возможность
управления самими таблицами стилей CSS. Обычно в этом не возникает необходимости,
тем не менее такая возможность иногда бывает полезной, и в этом разделе
коротко будут представленные возможные приемы.

При работе с самими таблицами стилей вам придется столкнуться с двумя типами
объектов. Первый тип – это объекты Element, представляющие элементы <style>
и <link>, которые содержат или ссылаются на таблицы стилей. Это обычные
элементы документа, и если в них определить атрибут id, вы сможете выбирать их
с помощью метода document.getElementById(). Второй тип объектов – объекты
CSSStyleSheet, представляющие сами таблицы стилей. Свойство document.stylesheets
возвращает доступный только для чтения объект, подобный массиву,
содержащий объекты CSSStyleSheet, представляющие таблицы стилей документа. Если
в элементе <style> или <link>, определяющем или ссылающемся на таблицу
стилей, определить атрибут title, этот объект будет доступен как свойство объекта
CSSStyleSheet с именем, указанным в атрибуте title.

Следующие разделы описывают, какие операции могут выполняться с этими
элементами <style> и <link> и объектами таблиц стилей.

содержание 16.6.1. Включение и выключение таблиц стилей

Простейший прием работы с таблицами стилей является к тому же самым
переносимым и надежным. Элементы <style> и <link>
и объекты CSSStyleSheet определяют
свойство disabled, доступное сценариям на языке JavaScript для чтения и
записи. Как следует из его имени, если свойство disabled принимает значение true,
таблица стилей оказывается отключенной и будет игнорироваться браузером. *
Это наглядно демонстрирует функция document.styleSheets(), представленная ниже.
Если передать ей число, она будет интерпретировать его как индекс в массиве
document.styleSheets. Если передать ей строку, она будет интерпретировать ее как
селектор CSS, передаст ее методу document.querySelectorAll()
(раздел 15.2.5) и
установит в значение true свойство disabled всех полученных элементов:

function disableStylesheet(ss) {
  if (typeof ss === "number")
    document.styleSheets[ss].disabled = true;
  else {
    var sheets = document.querySelectorAll(ss);
    for(var i = 0; i < sheets.length; i++)
    sheets[i].disabled = true;

  }
}

содержание 16.6.2. Получение, вставка и удаление правил из таблиц стиле

В дополнение к возможности включения и отключения таблиц стилей объект
CSSStyleSheet также определяет API для получения, вставки и удаления правил
стиля из таблиц стилей. IE8 и более ранние версии реализуют несколько иной
API, отличный от стандартного, реализуемого другими браузерами.
Как правило, непосредственное манипулирование таблицами стилей редко
бывает полезным. Вместо того чтобы добавлять новые правила в таблицы стилей,
обычно лучше оставить их статичными и работать со свойством className
элемента. В то же время, если необходимо предоставить пользователю возможность
полного управления таблицами стилей веб-страницы, может потребоваться
организовать динамическое манипулирование таблицами.
Объекты CSSStyleSheet хранятся в массиве document.styleSheets[]. Объект
CSSStyleSheet имеет свойство cssRules[], хранящее массив правил стилей:

var firstRule = document.styleSheets[0].cssRules[0];

В IE это свойство носит имя rules, а не cssRules.
Элементами массива cssRules[] или rules[] являются объекты
CSSRule. В
стандартном API объект CSSRule может представлять CSS-правила любого типа,
включая @-правила, такие как директивы @import и @раде.
Однако в IE массив rules[]
может содержать только фактические правила таблицы стилей.
Объект CSSRule имеет два свойства, которые могут использоваться переносимым
способом. (В стандартном API правила, не относящиеся к правилам стилей, не
имеют этих свойств, и потому, возможно, вам потребуется пропускать их при
обходе таблицы стилей.) Свойство selectorText – это CSS-селектор для данного
правила, а свойство style – это ссылка на доступный для записи объект
CSSStyleDeclaration, который описывает стили, связанные с этим селектором. Напомню, что
CSSStyleDeclaration – это тот же самый тип, который используется для
представления встроенных и вычисленных стилей. Объект CSSStyleDeclaration может
применяться для чтения существующих или создания новых стилей в правилах.
Нередко при обходе таблицы стилей интерес представляет сам текст правила, а не,
разобранное его представление. В этом случае можно использовать свойство
cssText объекта CSSStyleDeclarationn, в котором
содержатся правила в текстовом представлении.
В дополнение к возможности получения и изменения существующих правил
таблиц стилей имеется возможность добавлять правила в таблицу стилей и удалять
их из таблицы. Стандартный прикладной интерфейс определяет методы
insertRule() и deleteRule(), позволяющие добавлять и удалять правила:


document.styleSheets[0].insertRule("H1 { text-weight: bold; }", 0);

Браузер IE не поддерживает методы insertRule() и deleteRule(), но определяет
практически эквивалентные им функции addRule() и removeRule(). Единственное
существенное отличие (помимо имен функций) состоит в том, что addRule()
ожидает получить селектор и стиль в текстовом виде в двух отдельных аргументах.
Следующий пример реализует обход правил в таблице стилей и демонстрирует
API, внося несколько сомнительных изменений в таблицу:


var ss = document.styleSheets[0];             // Извлечь первую таблицу стилей
var rules = ss.cssRules?ss.cssRules:ss.rules; // Извлечь правила

for(var i = 0; i < rules.length; i++) {       // Цикл по этим правилам

  var rule = rules[i];
  if (!rule.selectorText) continue;           // Пропустить ©import и др. директивы
  var selector = rule.selectorText;           //Селектор
  var ruleText = rule.style.cssText;          // Стили в текстовом виде
  // Если правило применяется к элементам h1, применить его и к элементам h2
  // Учтите, что этот прием сработает, только если селектор
  // в точности будет иметь вид "h1"
  if (selector == "h1") {
    if (ss.insertRule) ss.insertRule("h2 {" + ruleText + "}", rules.length);
  else if (ss.addRule) ss.addRule("h2", ruleText, rules.length);
  }
  // Если правило устанавливает свойство text-decoration, удалить его.
  if (rule.style.textDecoration) {
    if (ss.deleteRule) ss.deleteRule(i);
    else if (ss.removeRule) ss.removeRule(i);
    i--; // Скорректировать переменную цикла, поскольку прежнее правило с
    //индексом i+1 теперь стало правилом с индексом i
  }
}

содержание 16.6.3. Создание новых таблиц стилей

Наконец, имеется возможность создавать совершенно новые таблицы стилей и
добавлять их в документ. В большинстве браузеров эта операция выполняется с
помощью стандартных приемов, реализованных в модели DOM: создается новый
элемент <style> и вставляется в документ в раздел <head>, затем с помощью
свойства innerHTML добавляется содержимое таблицы стилей. Однако в IE8 и в более
ранних версиях новый объект CSSStyleSheet необходимо создавать с помощью
нестандартного метода document.createStyleSheet(), а текст таблицы стилей добавлять
с помощью свойства cssText. Пример 16.6 демонстрирует создание новых таблиц.

Пример 16.6. Создание новой таблицы стилей


// Добавляет таблицу стилей в документ и заполняет ее указанными стилями.

// Аргумент styles может быть строкой или объектом. Если это строка.

// она интерпретируется как текст таблицы стилей. Если это объект, то каждое

// его свойство должно определять правило стиля, добавляемое в таблицу.

// Именами свойств являются селекторы, а их значениями - соответствующие стили

function addStyles(styles) {
  // Сначала необходимо создать новую таблицу стилей
  var styleElt, styleSheet;
  if (document.createStyleSheet) { // Если определен IE API, использовать его
    styleSheet = document.createStyleSheet();
  }
  else {
    var head = document.getElementsByTagName("head")[0]
    styleElt = document.createElement("style"); // Новый элемент <style>
    head.appendChild(styleElt); // Вставить в <head>
    // Теперь новая таблица находится в конце массива
    styleSheet = document.styleSheets[document.styleSheets.length-1]
  }
  // Вставить стили в таблицу
  if (typeof styles === "string") {
    // Аргумент содержит текстовое определение таблицы стилей
    if (styleElt) styleElt.innerHTML = styles;
    else styleSheet.cssText = styles; // The IE API
  }
    else {
    // Аргумент - объект с правилами для вставки
    var i = 0;
    for(selector in styles) {
      if (styleSheet.insertRule) {
        var rule = selector + " {" + styles[selector] + "}";
        styleSheet.insertRule(rule, i++);
      }
      else {
        styleSheet.addRule(selector, styles[selector], i++);
      }
    }
  }
}

Понравилась статья? Поделить с друзьями:
  • Руководство венчурного фонда
  • Кетотифен инструкция по применению детям дозировка
  • Теопэк таблетки инструкция к применению показания к применению взрослым
  • Keep talking and nobody explodes инструкция на русском pdf
  • Коса рыбий хвост на длинные волосы как плести пошаговая инструкция