Заметки с тегом «html5»

Inline SVG для пиктограмм

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

Все изображения собраны в одном SVG-файле shapes.svg.


<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
  <defs>
    <rect id="shape-rectangle" x="1" y="1" width="30" height="30"/>
    <circle id="shape-circle" cx="16" cy="16" r="24"/>
  </defs>
</svg>

Тут у нас две фигуры: квадрат и круг. Чтобы в дальнейшем мы могли сослаться на них, у каждой фигуры должны быть уникальные значения id . Забегая вперёд скажу, что их уникальность должна быть не только в пределах SVG, но и в пределах всего документа, где в дальнейшем будет отображаться эта иконка.

На заметку:

Все фигуры определены внутри тега <defs> . Они не будут отображаться, если попытаться открыть этот файл в каком-нибудь редакторе или просмотрщике. На них можно только сослаться. Несколько контуров могут быть объединены в одну фигуру с помощью тега <g>.

Затем в HTML можно сослаться на заготовленные контуры


<svg xmlns="http://www.w3.org/2000/svg"
      style="width: 32px; height: 32px;">
  <use xlink:href="shapes.svg#shape-rectangle"></use>
</svg>

Браузер отобразит квадрат в блоке размером 32 на 32 пиксела. Габариты блока, разумеется, нужно задавать с помощью CSS. В данном примере я указал их в атрибуте style только для наглядности.


<svg xmlns="http://www.w3.org/2000/svg"
      viewBox="-9 -9 50 50"
      style="width: 32px; height: 32px;">
  <use xlink:href="shapes.svg#shape-circle"></use>
</svg>

C кругом чуть сложнее так как он не вписывается в желаемые габариты 32 на 32 пиксела. Поэтому inline SVG нужно указать атрибут viewBox. Браузер сам правильно смасштабирует фигуру до размеров блока.

Подводные камни

При использование inline SVG нужно знать и помнить несколько особенностей.

Поддержка

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

Internet Explorer

Мы обнаружили, что ссылка на внешний SVG-файл с контурами не работает, если страница отображается в IE. Это известное поведение и исправить хаками его нельзя. Остаётся только явно включить этот SVG в HTML страницу. Соответственно при использовании в <use xlink:href="#shape-rectangle"></use> остаётся один якорь (для этого и нужна была уникальность id).

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


<script id="svg-loader">
  $.ajax({url: "shapes.svg", cache: true, dataType: "html"})
    .done(function (data) {
      $("#svg-loader").before(data);
      $(".svg-icon > use").attr("xlink:href", function (i, href) {
        return href.substr(href.indexOf("#"));
      });
    });
</script>

Важно, чтобы браузер доставал файл из своего кеша, если это возможно.

Ещё важно, чтобы в SVG разметке не было самозакрывающихся тегов. Нужно явно указывать закрывающий тег, если нет контента. Старые парсеры HTML-супа допускали лишь ограниченное количество самозакрывающихся тегов ( <hr/>, <br/>, <input/> и т.п.) — поэтому мы не можем писать <div/> . Конструкции SVG могут поломать весь документ при определённом стечении обстоятельств.

Комментарии к заметке: 8

Охота за последним видимым элементом

Последний элемент среди соседей можно выбрать селектором псевдо-класса :last-child.


.item { display: block; }
.item:last-child { font-weight: bold; }

Разметка:


<div>
  <div class="item item_rank_1">Object “A”</div>
  <div class="item item_rank_1">Object “B”</div>
  <div class="item item_rank_0">Object “C”</div>
</div>

Но, если с помощью медиа-запроса скрыть часть элементов списка, то получить последний видимый элемент уже так просто не выйдет.


@media (max-width: 600px) {
  .item_rank_0 { display: none; }
}

Казалось бы можно использовать селектор .item_rank_1:last-child , но это так не работает. Псевдо-класс :last-child позволяет найти только одного последнего ребёнка своего родителя.

Но мы уже живём в мире HTML5, где можно грабить корованы и придумывать свои собственные теги (оригинал ). По этому вместо того, чтобы отличаться классами, элементы будут отличаются названиями тегов.


<div>
  <item-rank-1 class="item">Object “A”</item-rank-1>
  <item-rank-1 class="item">Object “B”</item-rank-1>
  <item-rank-0 class="item">Object “C”</item-rank-0>
</div>

Да, так тоже можно, если очень хочется.

Теперь в медиа-запросе можно использовать селектор :last-of-type для того, чтобы получить последний элемент группы, которая не была скрыта.


@media (max-width: 600px) {
  item-rank-0.item { display: none; }
  item-rank-1:last-of-type { font-weight: bold; }
}

Таким способом можно создавать любые теги и они будут прекрасно поддаваться оформлению через CSS. Для IE < 9 нужно будет их предварительно создать с помощью JavaScript так как делаем это для новых HTML5 элементов.

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

Живой пример

PS: Не забудьте, что вес тега меньше, чем вес класса при определении специфичности селектора. Так же в названии тега обязательно должен быть символ - , чтобы парсер мог отличить обычные элементы от ваших собственных.

Комментарии к заметке: 21

Разметка «хлебных крошек» с помощью microdata

«Хлебные крошки» (breadcrumbs) помогают пользователям ориентироваться в структуре сайта. Хотя, стоит заметить, что в современном дизайне их встречаешь всё реже и реже. Но сейчас они могут оказаться полезными не только пользователям, но и поисковикам.

Поисковики и сами прекрасно умеют определять структуру сайта. Google, например, может построить «крошки» от главной страницы сайта до целевой страницы из цепочки ссылок и вывести их в сниппете. Но, лучше всего «хлебные крошки» разметить с помощью microdata. В словаре Data-Vocabulary.org есть специальный тип для этого — Breadcrumb .


<div class="breadcrumbs">
  <span itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
    <a href="http://noteskeeper.ru" itemprop="url">
      <span itemprop="title">Свежие заметки</span>
    </a> &#8250;
    <span itemprop="child" itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
      <a href="http://noteskeeper.ru/topic/markup/" itemprop="url">
        <span itemprop="title">Вёрстка</span>
      </a> &#8250;
      <span itemprop="child" itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
        <a href="http://noteskeeper.ru/527/" itemprop="url">
          <span itemprop="title">Вёрстка независимыми блоками</span>
        </a>
      </span>
    </span>
  </span>
</div>

Пример в выдаче Google

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

Формат разметки, возможно, ещё будет меняться. На текущий момент, все объекты типа Breadcrumb неявно связываются между собой. Последовательность в цепочке определяется их последовательностью в документе. Для явного связывания объектов есть поле child . В этом случае объекты должны быть вложены друг в друга (как в моём примере).

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


<ul class="breadcrumbs">
  <li itemscope itemtype="http://data-vocabulary.org/Breadcrumb"
          itemref="breadcrumb-1">
    <a href="http://noteskeeper.ru" itemprop="url">
      <span itemprop="title">Свежие заметки</span>
    </a>
  </li >
  <li itemprop="child" itemscope itemtype="http://data-vocabulary.org/Breadcrumb"
          id="breadcrumb-1" itemref="breadcrumb-2">
    <a href="http://noteskeeper.ru/topic/markup/" itemprop="url">
      <span itemprop="title">Вёрстка</span>
    </a>
  </li>
  <li itemprop="child" itemscope itemtype="http://data-vocabulary.org/Breadcrumb"
          id="breadcrumb-2">
    <a href="http://noteskeeper.ru/527/" itemprop="url">
      <span itemprop="title">Вёрстка независимыми блоками</span>
    </a>
  </li>
</ul>

Технически, получилась точно такая же структура — чётко связанный список «крошек». Осталось только проверить на практике, как к нему отнесётся Google.

Обновление: Гугл нормально связал между собой крошки, через аттрибут itemref.

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

Комментарии к заметке: 23

Вложенные объекты microdata

Связывание нескольких вложенных в друг друга объектов microdata происходит через атрибут itemprop.


<article itemscope itemtype="http://schema.org/CreativeWork">
  <aside itemprop="author" itemscope itemtype="http://schema.org/Person">
    <link itemprop="url" href="http://noteskeeper.ru/about/">
    <span itemprop="name">Владимир Кузнецов</span>
  </aside>
  <link itemprop="url" href="http://noteskeeper.ru/811/">
  <h1 itemprop="name">Вложенные объекты microdata</h1>
</article>

Получаем такую структуру:


creativework
  itemType = http://schema.org/CreativeWork
  author
    person
      itemType = http://schema.org/Person
      url = http://noteskeeper.ru/about/
      name = Владимир Кузнецов
  url = http://noteskeeper.ru/811/
  name = Вложенные объекты microdata

Если убрать атрибут itemprop="author", то объект CreativeWork потеряет связь с Person и тот, в свою очередь, переместится на корневой уровень в иерархии объектов, хоть, фактически, останется на том же самом месте в документе.


creativework
  itemType = http://schema.org/CreativeWork
  url = http://noteskeeper.ru/811/
  name = Вложенные объекты microdata

person
  itemType = http://schema.org/Person
  url = http://noteskeeper.ru/about/
  name = Владимир Кузнецов

Очевидно, что элементы, которые будут находиться внутри Person для объекта CreativeWork будут не доступны.

Комментарии к заметке: 2

Обратные связи в микроразметке microdata

Экспериментируя с микроразметкой и отслеживая реакцию поисковиков на это, я пришел к печальному выводу, что Google не очень-то любит так называемые обратные связи. Если, например, вы размечаете AggregateRating, то он должен быть частью структуры CreativeWork.

Хорошая разметка:


<div itemscope itemtype="http://schema.org/CreativeWork">
  <link itemprop="url" href="http://noteskeeper.ru/807/">
  <meta itemprop="name" content="Обратные связи в микроразметке microdata">
  <span itemprop="aggregateRating" itemscope
      itemtype="http://schema.org/AggregateRating">
    Оценка читателей <span itemprop="ratingValue">4</span> на основе
    <span itemprop="reviewCount">1</span> комментария
  </span>
</div>

Не совсем хорошая разметка:


<div itemscope itemtype="http://schema.org/AggregateRating">
  <span itemprop="itemReviewed" itemscope
      itemtype="http://schema.org/CreativeWork">
    <link itemprop="url" href="http://noteskeeper.ru/807/">
    <meta itemprop="name" content="Обратные связи в микроразметке microdata">
  </span>
  Оценка читателей <span itemprop="ratingValue">4</span> на основе
  <span itemprop="reviewCount">1</span> комментария
</div>

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

Есть подозрение, что по тем же причинам Google игнорирует объекты, соединённые через itemref . Хоть валидаторы и формируют правильную структуру, но поисковик эту связь почему-то не учитывает. Хочется верить в то, что это временное явление.

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