CSS-свойство display и контексты форматирования

Я давно собирался написать эту статью, но на прошлой неделе W3C дал замечательный повод… впрочем, обо всём по порядку. Кстати, спецификации W3C зря считают скучными: порой они могут дать фору любому детективу. В хорошем детективе всё выясняется лишь на последней странице. Но бывало ли, чтобы ключевая деталь детектива ― например, что злодеев было не двое, а трое ― раскрывалась вообще не в тексте, а… в списке найденных опечаток, на отдельном листке, вклеенном в книгу?

Так вот, в спецификациях W3C бывает еще и не такое. Например, всем нам знакомая спецификация CSS2.1: уже три года как она в статусе рекомендации, по идее, никаких изменений в ней быть не должно. Как вы думаете, сколько в этой спецификации описано наших любимых контекстов форматирования: два ― инлайновый и блочный? А вот и нет: три! Через год после «совсем-совсем-окончательного» утверждения спецификации ее авторы внезапно поняли, что на самом деле в ней описан еще один, ни на что не похожий, контекст форматирования ― табличный. Но поскольку менять окончательно утвержденную спецификацию по правилам игры нельзя, то единственное, куда можно было внести изменение ― список замеченных ошибок (errata). Так что внимательно читайте спецификации, и не только основной текст, но и добавочные ссылки! Кстати, кто пройдет квест на внимательность в оглавлении этой самой спецификации и найдет ее «секретный уровень» с одной загадочной фразой?

Но хватит вступлений, пора переходить к нашей первой теме, и это…

Контексты форматирования в CSS

Итак, какие они вообще бывают, по состоянию на середину-конец 2014 года?

Из старых:

Инлайновый

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

Блочный

На первый взгляд еще проще инлайнового. Тоже самый важный, т.к. ведает размещением и оформлением блоков контента. В нем же «плавают» float-ы.

Табличный

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

И из новых:

Флексбоксовый

О флексбоксах и их непростой судьбе мы говорили уже давно, с тех пор появилось много хороших руководств по ним (1, 2, 3, 4) и многие успели опробовать их прелести. Одни особенности роднят их с блоками, другие (пропорциональное растягивание) ― с таблицами, третьи (многострочность) ― с инлайн-боксами. У флексбоксового контекста есть еще одна особенность, но о ней чуть позже.

Гридовый (сеточный)

Гриды (сеточная раскладка) ― еще один CSS-модуль, предназначенный специально для создания макетов, тоже с запутанной родословной и противоречивой репутацией. На момент написания статьи был не так популярен, как флексбоксы, поскольку был готов к использованию лишь в одном браузере (на удивленIE), но всё меняется. Одна особенность роднит его с предыдущим.

Контекст форматирования Ruby

Что такое «Ruby-аннотации», вы можете узнать из статьи о соотв. элементах HTML5. В CSS для них тоже есть свой модуль… и больше знать о нем пока нам, пожалуй, незачем (шутка: знания лишними не бывают).

Еще?

Есть ли еще контексты форматирования? Беглый поиск по разделу со спецификациями их не находит. Но, судя по детективно-табличной истории, даже сами авторы спецификаций могут до поры этого не знать!:) Возможно, именно вы сможете найти в какой-нибудь из затерянных спецификаций диковинного «зверя», о котором не знали сами члены W3C, так что удачной вам «охоты»!

Всё сразу одной таблицей (для наглядности)

КФ Для чего нужен «Участники» Важные особенности Ссылки на стандарт
Инлайновый Форматирование текста и всего, что находится прямо в нем Элементы строки (текст, картинки, кнопки, инлайн-блоки, инлайн-таблицы и т.д.) Всё «воспринимается как текст», напр., пробелы в коде часто отображаются как символы. Сложные правила вертикального выравнивания. CSS1
CSS2.1
CSS Text 3
Блочный Оформление блоков текста (с отступами и врезками) Блочные боксы (в т.ч. анонимные), float-ы «Схлопывание» margin-ов, «проваливание» float-ов через верхние и нижние границы блоков, влияние float-ов в пределах контекста друг на друга. Не-блочные элементы неявно оборачиваются в анонимные блоки. Мало средств для выравнивания/центрирования по вертикали. CSS1
CSS2.1
Табличный Представление табличных и «таблицеподобных» данных, изредка полезен и для раскладки блоков Ячейки, строки, группы строк (как thead/tbody/etc.) и всё такое, в т.ч. анонимные Иерархия табличной структуры (в строке могут быть только ячейки и т.п.), для недостающих элементов иерархии создаются анонимные обертки соотв. типа. Сложные и плохо документированные алгоритмы расчета размеров Список ошибок (errata) к CSS2.1
CSS Tables 3 (работа идет, но еле-еле)
Флексовый «Гибкая» раскладка и взаимное выравнивание блоков с контентом, в т.ч. для динамичных и адаптивных макетов и их частей «Гибкие блоки» (flexible items) Меняет поведение непосредственных потомков элемента, задающего этот контекст. В частности, свойство float игнорируется. Создает анонимные флекс-обертки для текста, оказавшегося непосредственно в контейнере. CSS Flexbox 1
Для истории:
Flexbox 2011
Flexbox 2009
Гридовый (сеточный) Расположение блоков в соответствии с заданным «каркасом» страницы или интерфейса Элементы сетки (ячейки, области, разграничительные линии) и привязанные к ним блоки контента Практически полная независимость порядка отображения элементов от порядка в коде. Элементы могут влиять друг на друга сразу по двум направлениям. CSS Grid 1
Ruby Подсказки для чтения текста иероглифами Иероглифы основного текста и ruby-подсказки к нему Вряд ли встретится вам, если вы не будете верстать учебники китайского или японского… но кто знает! CSS Ruby 1

Контексты, но не форматирования

Слово «контекст» вообще часто звучит в веб-фронтендных разговорах, напр., про JS или Canvas. Но и в контексте (простите за каламбур) CSS его применение не ограничено контекстом (ой, опять…) контекстов форматирования, так что у многих с этим словом возникает путаница ― совсем как у меня в этой фразе. Например, контекст наложения (stacking context) ― ключевое понятие для понимания свойства z-index. У него много неочевидных нюансов, о которых написаны целые статьи (1, 2). Но к контекстам форматирования он отношения не имеет. Поэтому, услышав фразу типа «такое-то свойство создает контекст», на всякий случай уточняйте, о контексте чего идет речь!

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

Display, наш старый знакомый

Уж что-что, а это свойство знакомо каждому новичку! Мы каждый день используем его, чтобы показывать и скрывать элементы. Мы играючи меняем одно значение на другое, как по волшебству превращая вертикальные меню в горизонтальные и наоборот. Мы знаем, что смена display не влияет на парсинг элемента в DOM и не превращает один элемент в другой на самом деле, не скрывает контент от поисковиков, не влияет на семантику элемента (за редкими исключениями) ― словом, делает ровно то, что вытекает из его названия: меняет отображение.

А теперь померяемся эрудициями: сколько значений этого свойства вы можете назвать сходу? Хотя бы штук 16 (именно столько их было в CSS2.1) вспомнили?

А теперь запишем то, что вспомнили и нагуглили, вот в таком виде:

«Периодическая таблица» значений display

    none
inline    
inline-block block  
inline-table table table-row-group
table-header-group
table-footer-group
table-row
table-cell
table-column-group
table-column
table-caption
inline-flex flex  
inline-grid grid  
ruby   ruby-base
ruby-text
ruby-base-container
ruby-text-container
  list-item  
    run-in

Видно, что значения четко делятся минимум на два типа: с дефисом и без. У некоторых свойств без дефиса есть «партнер» с дефисом, а то и куча их, причем дефис бывает и справа, и слева. Случайно ли это? Конечно, нет.

Рассмотрим столбцы таблицы. В первом столбце все свойства, кроме ruby, начинаются с inline. И элементы с такими значениями display ведут себя как элементы строки ― пытаются встроиться в строку окружающего текста, сохраняют пробелы в коде вокруг себя, подчиняются свойству vertical-align, т.е. живут в инлайновом контексте форматирования, по его законам.

У значений из второго столбца нет общей части, но есть общая черта: все элементы с таким значением display снаружи ведут себя как блоки. У них может по-разному рассчитываться ширина, они могут пропускать или не пропускать через себя float-ы, но в главном они едины: идут друг за дружкой по вертикали, их внешние margin-ы схлопываются с соседями, и самое главное ― они диктуют своему окружению, чтобы оно тоже было блочным. Если рядом с элементом с таким display случайно окажется какой-то «голый» инлайновый контент, то строгий рендерер браузера тотчас же велит этому нарушителю «одеться» в анонимную блочную обертку (с инлайновым контекстом внутри), чтобы почтенному блоку не приходилось стыдиться такого соседства:). Может, логичнее было бы назвать эти значения «block-table», «block-flex» и т.д.? Впрочем, принцип и так ясен, запомнить легко.

Наконец, в третий столбец у нас попали значения из как будто совершенно разных групп. Но если присмотреться, у большинства из них тоже можно найти что-то общее: влияние элемента с таким display на своих соседей зависит от того, где этот элемент оказался. Например, table-cell, оказавшись внутри table-row, не просто ведет себя как ячейка, но и «превращает в ячейки» (точнее, вынуждает оборачиваться в анонимные table-cell’ы) своих соседей c «обычными» значениями display. А та же table-cell среди обычных блоков лишь тихо «завернется» в анонимные table-row и table, и будет вести себя как простая таблица из одной ячейки. Особняком стоит экзотический зверек run-in (тоже с непростой судьбой ― его следы в спецификациях тянутся еще с 1998 г., с CSS2.0, то исчезая, то появляясь вновь, при этом его никогда не поддерживал Firefox, а недавно его поддержку убрал Хром). По факту это инлайн, который иногда умеет «вбегать» внутрь… следующего за ним блока. Вряд ли вам часто доведется с ним сталкиваться (хотя оно здорово упростило бы решение задач типа этой, а также иногда используется для так называемых «заголовков в подбор»), но, по-моему, в третий столбец оно попало не зря.

Итого, три столбца поделили наши значения display по тому, как они влияют на соседей элемента:

  1. Участники инлайнового контекста (все, начинающиеся на inline, и примкнувший к ним ruby). Оказавшись среди текста, встраиваются в него.
  2. Участники блочного контекста (все значения без дефиса за вычетом none, inline и ruby, но с добавлением list-item). Оказавшись среди текста, разбивают его в анонимные блоки.
  3. Ни то ни другое. На соседей не влияет (none), либо поведение зависит от внешнего контекста (table-*, ruby-*) или каких-то других, но тоже внешних, условий (run-in).

А что мы видим в строках? Во-первых, бросаются в глаза пары вида «нечто» — «inline-нечто». Практически у каждого «снаружи-блочного» типа отображения есть его «снаружи-инлайновый» напарник! Элементы с display из этих пар ведут себя совершенно одинаково внутри ― задают один и тот же тип форматирования своему содержимому, одинаковым образом (при прочих равных) выстраивают своих потомков. Единственное исключение ― самый обычный block, отличающийся от инлайн-блока нюансами наследования родительской ширины и поведения margin-ов с float-ами. К объяснению этого исключения мы вот-вот подойдем, а пока посмотрим, что связывает оставшиеся соседние по горизонтали клетки нашей таблицы. Мы сразу видим две группы вида «нечто» — «нечто-поменьше», причем второго может быть целая куча, оно может подразделяться на «нечто-еще-меньше» и т.д. Причем для тех значений, которые задают для своих потомков контексты форматирования с особыми правилами, и те в зависимости от этих правил могут вести себя по-разному… по причине чего и оказались у нас в третьем столбце:)

А вот у (inline-)flex и (inline-)grid таких «производных» значений нет. Помните, мы упоминали, что у флексбоксового и сеточного контекстов есть загадочная особенность? И вот в чем она: эти контексты форматирования влияют на отображение своих непосредственных участников напрямую. Кто бы ни попал в контейнер с display:flex ― блок, инлайн-блок или другой flex-контейнер ― флексовый контекст форматирования их всех уравняет. И выровняет (если у него заданы правила для выравнивания). Не разбирая, кто был строчным, кто блочным. Правда, только снаружи: внутри они останутся такими, какими были ― блочными, табличными, флексовыми и т.д. «Магия» этих новых раскладочных контекстов сильна (попробуйте и убедитесь!), но на «внуков» элемента-контейнера она уже не распространяется.

Наконец, в нашей таблице остались пустые клетки. Например, те, которым могли бы соответствовать значения inline-list-item и (условно) block-ruby. Со вторым еще ладно: ruby-аннотации нужны для текста, а не для блоков, да и то изредка. Но перечисления и нумерации в самом тексте встречаются сплошь и рядом, так что первый вариант был бы не лишним, правда?

Display на плаву и в других неудобных позициях

Говоря о display, стоит вспомнить свойства float и position:absolute/fixed, которые умеют «переопределять» указанное значение display, часто вызывая путаницу. Алгоритм этого описан в спецификации CSS2.1 (к счастью, на этот раз в тексте, а не списке опечаток:). Какие закономерности, вдобавок к только что найденным, мы видим там?

Во-первых, очевидно, none «забарывает» всех, «обнуляя» прочие визуальные свойства (аналогия с умножением на ноль). Во-вторых, эти свойства начисто почти начисто (см. уточнение в комментариях) «срубают» частицу «inline-», если она была ― что тоже логично: и плавающие, и абсолютно позиционированные элементы вырваны из потока, а значит, лишены связи с текстом, в который могли бы встроиться, и «внешняя инлайновость» для них утратила смысл. В-третьих, элемент так же вырывается из «экзотических» контекстов вроде табличного, а значит, и особые табличные правила для него тоже теряют смысл. И что остается элементу, если он не может быть ни inline-чем-либо, ни частью таблицы? Только старый добрый block. Поэтому для плавающих блоков и абсолютно позиционированных элементов display можно и не задавать ― без него им не стать ничем, кроме блока.

Блок в блоке: исключительность в обычности

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

Например, все inline-*ruby). Они сами живут в инлайновом контексте, а внутри у них ― разные другие контексты форматирования. Та же история с table, flex и grid, только живут они в блочном. У table-* выстраивается вся «матрешка» табличной модели (в табличном контексте, если нужно ― через анонимные обертки), а внутри самой внутренней table-cell размещаются обычные блоки с текстом, т.е. контекст в ней блочный.

Получается, что почти все значения display являются своего рода «переходниками» между контекстами форматирования: сами находятся в одном, а внутри у них другой!

И только бедняга block (и еще list-item… но до него еще доберемся) ничем таким не выделяется. Он и снаружи блочный, и внутри блочный ― насквозь блочный. Сам живет в блочном контексте и продолжает этот же контекст внутрь себя, без перемен.

Вот почему таблицы (и их «запчасти»), инлайн-блоки, потомки флекс-контейнеров, а также «блоки поневоле» ― float-ы и абсолютно позиционированные ― создают блочный контекст форматирования автоматически. Собственно, у них-то и выбора нет, создавать или не создавать. А вот у обычного блока есть возможность «продолжить» существующий. Вот он по умолчанию и делает, как проще ― продолжает. И поэтому остается подвержен влиянию float-ов и cхлопывающихся margin-ов не только внутри себя, но и снаружи ― ведь форматирование блоков текста в одном блочном контексте идет по общим сквозным правилам, ведь CSS изначально создавался именно для оформления сплошных потоков текста. И никакие clear- и подобные -фиксы ничего не могли с этим поделать.

Так «типичность» значения block оказалась его исключительной особенностью. Хотя изначально «так и задумывалось», сегодня она часто мешает, и приходится «силой» заставлять его создавать отдельный контекст. Чаще всего через overflow, который тоже в какой-то мере выделяет (хоть и не вырывает) блок из потока и «обносит жестким забором» по периметру. И у всех способов свои издержки (хотя есть призрачная надежда на появление стандартного). Впрочем, с новыми механизмами раскладки ― теми же флексбоками ― необходимость «мучить» старичка block станет не такой частой.

Один display ― два бокса?

Значение list-item уникально умением создавать два бокса вместо одного: в дополнение к основному блочному ― еще и специальный бокс для маркера (если таковой задан в свойствах списка). Но вот что такое этот бокс маркера, куда его засунуть (кроме как внутрь текста) и вообще что с ним можно сделать ― спецификация рассказать «забыла». Поэтому отображение маркеров отдано на откуп браузерам и управлять им почти не удается. И годами нам то и дело приходилось вообще убирать эти маркеры и делать свои, либо фоном, либо псевдоэлементами ::before.

Но если бы этим маркером можно было удобно управлять, да использовать те же ::before/::after в дополнение к нему ― кто бы отказался? Да и возможность добавить какой-никакой бокс «на халяву» и к инлайновому элементу бы порой не помешала…

А теперь всем, кто дочитал до этого места ― огромный сюрприз от W3C!

Сюрприз вышел всего неделю назад, и называется эта спецификация CSS Display Module. 3-го уровня, т.к. расширяет определение свойства display из CSS2.1. Это еще первый черновик, но черновик интересный.

Во-первых, отдельных значений display в нем стало больше, чуть ли не три десятка. И среди них появился предсказанный нашей «периодической таблицей» inline-list-item. Более того, маркер списка стал полноценным псевдоэлементом ::marker ― и значит, мы сможем (если верить другой спецификации) управлять им с помощью всего CSS-арсенала, который у нас есть. Фактически, мы наконец получим второй ::before!

Но эта новость меркнет перед следующей. По новой спецификации, мы сможем управлять поведением элементов снаружи (относительно соседей) и внутри (относительно потомков) независимо ― с помощью отдельных свойств display-outside и display-inside соответственно. А наш «обычный display» превратился в сокращенную запись для этих свойств (и еще одного, display-list, как раз отвечающего за дополнительные маркеры для элементов списка).

(Добавлено 30.12.2015: предыдущий абзац описывает, как было дело в первом черновике, на момент публикации статьи. В текущей версии спецификации от отдельных свойств display-inside и display-outside отказались, но значение обычного display сделали составным, и смысл его половинок тот же, что у бывших отдельных свойств — поведение бокса снаружи и внутри. Так что общий принцип по-прежнему верен.)

А ведь это значит, что мы теперь сможем сами создавать любые «кирпичики» для наших страниц, не только соответствующие любой клетке «периодической таблицы», но и ранее вообще невиданные! Например, ячейки таблицы с флексбоксами внутри, минуя (анонимную) блочную обертку. Или тот же блочный ruby-контейнер (как говорится, «не для науки, а просто поглазеть»). Или упростить структуру вложенной таблицы, придав «наружной стороне» внутренней таблицы свойства ячейки внешней (по идее, она автоматом подхватит ее высоту, и у нас, фактически, наконец появится rowspan/colspan для CSS-таблиц похоже, с таблицами по актуальной спецификации всё-таки не получится, но вот в контексте гридов это будет можно). Конечно, не все комбинации имеют смысл (например, делать бокс с наружными свойствами «table-row» и не помещать его в табличный контекст толку мало ― он всё равно обернется в анонимные обертки и управлять им будет трудно), но решение множества задач верстки станет намного проще. А главное ― многие «странности» поведения элементов, у которых «вершки» в одном контексте форматирования, а «корешки» ― в другом, станут наконец понятны интуитивно.

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

Ведь спецификации CSS порой увлекательнее детективов!

P.S. Это тоже может быть интересно:

16 Комментарии

  1. NMitra

    Ужас, я с флексом то не разобралась…
     

      1. NMitra

        Да, видела. Стоящее видео. Мои познания только им пока и ограничиваются ))

        1. Илья Стрельцын (Автор записи)

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

  2. GreLI

    Пара комментириев:

    Сетки (они же «гриды») изобретены и предложены Майкрософтом, так что удивлятся их поддержке в IE не стоит. Гугловцы обещают, что скоро будет и в Блинке. Надо сказать, что спецификация далеко продвинулась по сравнению с первым черновиком: можно давать имена позициям, улучшен алгоритм автоматического размещения, добавлен ASCII-арт из черновика Template Layout, реализация в IE по сравнениюм со всеми этими дополнениями довольно ограничена.

    Свойство position не начисто срубает inline. Свойство display имеет влияние, когда не элемент не спозиционирован свойствами вроде top. Тогда, согласно спецификации, он располагается примерно там, где оказался бы не будь спозиционирован. И тогда строчный элемент оказывается примерно там, где был бы в строке, как правило, это несколько ниже или выше блочного элемента.

    1. Илья Стрельцын (Автор записи)

      Спасибо за отклик и важные уточнения!

      Действительно, со «срубанием начисто» я погорячился, подразумевал типичный сценарий с top/left/etc. Что Grid Layout родом из MS я в курсе, хотел слегка поиздеваться над стереотипом о вечно отстающем-догоняющем IE.

      Сaniuse утверждал, что в IE реализована версия 2011 года, «ASCII-арт» там вроде бы уже есть. Но сходу заставить работать в IE пример из этого раздела спеки у меня не получилось. Модуль действительно вырисовывается мощнейший, делай что хочешь сразу в двух измерениях, но я всё же опасаюсь, что реализации еще долго останутся экспериментальными (а спецификация — черновиком) из-за гигантской сложности тестирования всего этого многообразия…

  3. Илья Стрельцын (Автор записи)

    Кстати, мне очень нравится определение контекста форматирования из нового черновика:

    Контекст форматирования: штука, которая заставляет CSS делать раскладку.

    Правда, там стоит пометка на будущее «исправить формулировку», но я бы оставил так. Лучше ведь и не скажешь! :)

    1. Алексей

      Может «нечто, создающее раскладку»? :) Или «контекст форматирования, это нечто, создающее в CSS новую раскладку»?… или «Контекст форматирования, это нечто, создающее в стилях документа новую раскладку, в которой действуют свои, обособленные правила форматирования»?
      Или «Контекст форматирования, это нечто, создающее в стилях документа новую раскладку, в которой некоторые правила форматирования действуют обособленно от общего контекста форматирования документа»?
      ЗЫ: это я так, на правах мозгового штурма =)

      1. SelenIT (Автор записи)

        В нынешней редакции уже изменили на «Среда, в которой раскладываются связанные друг с другом боксы», с дополнением, что «Разные контексты форматирования раскладывают свои боксы по разным правилам» =)

  4. Aleksey

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

    1. Илья Стрельцын (Автор записи)

      Принимаю претензию. С картинками у меня проблема, да. Постараюсь что-нибудь придумать!

      1. Aleksey

        Что Вы, ни в коем случае не претензия. Наоборот, спасибо большое.

  5. brego

    Превосходный материал. Спасибо.

  6. Fat

    Спасибо невероятное за материал!
    Читаю ресурс почти каждый день.
    Экстра классные статьи. Так держать!

  7. Алексей

    Да, вот эта штука, которая говорит и для внешнего и для внутреннего как взаимодействовать — классная! А ещё с селектором :has, который сможет через потомков оказывать влияние на предков — вообще здорово!

    1. SelenIT (Автор записи)

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

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

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