Заметки в категории «Вёрстка» :: Хранитель заметок

noteskeeper.ru

Персональный журнал для заметок Владимира Кузнецова

Заметки в категории «Вёрстка»

Исправляем структуру HTML5-документа в старых браузерах

В старых версиях Internet Explorer теги, которых нет в HTML 4.01, правильно будут стилизоваться только, если они предварительно созданы через JavaScript.

document.createElement("article");

Если JavaScript будет отключен, то для таких тегов не только не будут применяться стили, но и сама структура документа будет нарушена.

Пример правильной структуры документа в Firefox 8

Правильная структура HTML5-документа

А так этот же документ будет разобран в Internet Explorer 6

Структура документа нарушена из-за новых тегов

Из-за нарушения общей структуры в таком документе становятся бессмысленными и каскадные правила CSS.

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

Исправленная структура документа

Навигация по ссылкам в списках

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

Список авторов статей в блоге

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

<ul class="authors">
  <li class="author">
    <div class="author-userpic">
      <a class="author-archive-link" title="Vicki Moyes" href="/author/vicki/">
        <img class="author-pic photo" alt="Vicki Moyes" src="/img/users/vicki-moyes.jpg">
      </a>
    </div>
    <p class="author-title">
      <a href="/author/vicki/" class="author-title-archive-link">Vicki Moyes</a>
    </p>
    <p class="author-bio">Director of Moyes Gliders.
      Organizer of annual Forbes competition.</p>
  </li>
</ul>

Используем tabindex=-1

Элементы, обрамленные ссылками

При переключении фокуса с помощью клавиши «Tab» пользователь каждый раз сначала попадает на ссылку с фотографии, затем на ссылку с имени.

Проектируя интерфейс, первостепенно внимание уделяется пользователям, работающим с мышью или touch-интерфейсом. Кому-то из них привычнее и удобнее кликать по картинкам, а кто-то кликает только по явно обозначенным ссылкам. Поэтому удалить ссылку, обрамляющую фотографию, нельзя. Но зато можно сделать так, чтобы она не участвовала в последовательности переключения фокуса с клавиатуры. Для этого добавим ей атрибут tabindex="-1".

Переходы только по именам авторов

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

Одна ссылка

В этом примере два находящиеся рядом объекта (фотография и имя автора) должны вести на одну и ту же страницу. Технически их можно обернуть одной ссылкой. В HTML5 внутри строчного элемента a могут находиться как строчные, так и блочные элементы.

<a href="page.html">
    <div><img src="img1.jpg" alt="Page image"></div>
    <p>Page title</p>
</a>

Фрагмент кода валиден на 100%, только если используется в HTML5 документе.

Оглавление HTML5 документа

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

  1. Свежие заметки :: Хранитель заметок
    1. Свежие заметки
      1. Убираем неоднородности на повторяющейся текстуре
      2. Deferred Object
      3. Возвращаясь к проверке типа данных
      4. Тень у полей ввода в мобильном Safari
        1. Очень простое решение
      5. Таблица без таблицы или display: table-cell для всех браузеров
    2. Навигация по сайту
      1. Облако тегов
      2. Категории
      3. Ссылки
    3. Архив заметок по месяцам

Только два типа тегов влияют на оглавление страницы: заголовки (h1-h6 и hgroup) и структурные теги (section, article, aside и nav).

Влияние заголовков на построение оглавления

<div>
    <h1>Свежие заметки :: Хранитель заметок</h1>
    <!-- начинаем новый подраздел -->
    <h2>Свежие заметки</h2>
    <!-- начинается статья -->
    <h3>Убираем неоднородности на повторяющейся текстуре</h3>
    <!-- статья про неоднородности и как их убрать -->
    <p>Повторяющиеся текстуры бумаги или ткани могут быть с
        разными неоднородностями по площади.</p>
    ...
    <!-- статья закончилась и начинается новая -->
    <h3>Deferred Object</h3>
    <!-- статья про отложенные объекты -->
    <p>Термин «отложенный объект» тесно связан с событийной
        моделью создания компонент и модулей приложения.</p>
    ...
    <h3>Возвращаясь к проверке типа данных</h3>
    ...
    <h3>Тень у полей ввода в мобильном Safari</h3>
    ...
    <h4>Очень простое решение</h4>
    ...
    <h3>Таблица без таблицы или display: table-cell
        для всех браузеров</h3>
    ...
    <!-- раздел свежих заметок закончился и начинается новый раздел -->
    <h2>Навигация по сайту</h2>
    <h3>Облако тегов</h3>
    <ul>
        <li class="rank-9">jquery</li>
        <li class="rank-6">ui</li>
        <li class="rank-4">utility</li>
        <li class="rank-4">hint</li>
        <li class="rank-4">css</li>
    </ul>
    <h3>Категории</h3>
    <ul>
        <li>Вёрстка</li>
        <li>JavaScript</li>
        <li>Apple</li>
        <li>Разное</li>
    </ul>
    <h3>Ссылки</h3>
    ...
    <h2>Архив заметок по месяцам</h2>
    ...
</div>

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

Учет разделов при построении оглавления

Добавим в разметку страницы некоторые структурные элементы.

<div>
    <h1>Свежие заметки :: Хранитель заметок</h1>
    <section>
        <h2>Свежие заметки</h2>
        <article>
            <h3>Убираем неоднородности на повторяющейся текстуре</h3>
            <p>Повторяющиеся текстуры бумаги или ткани могут быть с
                разными неоднородностями по площади.</p>
            ...
        </article>
        <article>
            <h3>Deferred Object</h3>
            <p>Термин «отложенный объект» тесно связан с событийной
                моделью создания компонент и модулей приложения.</p>
            ...
        </article>
        <article>
            <h3>Возвращаясь к проверке типа данных</h3>
            ...
        </article>
        <article>
            <h3>Тень у полей ввода в мобильном Safari</h3>
            ...
            <h4>Очень простое решение</h4>
            ...
        </article>
        <article>
            <h3>Таблица без таблицы или display: table-cell
                для всех браузеров</h3>
            ...
        </article>
    </section>
    <nav>
        <h2>Навигация по сайту</h2>
        <section>
            <h3>Облако тегов</h3>
            <ul>
                <li class="rank-9">jquery</li>
                <li class="rank-6">ui</li>
                <li class="rank-4">utility</li>
                <li class="rank-4">hint</li>
                <li class="rank-4">css</li>
            </ul>
        </section>
        <section>
            <h3>Категории</h3>
            <ul>
                <li>Вёрстка</li>
                <li>JavaScript</li>
                <li>Apple</li>
                <li>Разное</li>
            </ul>
        </section>
        <section>
            <h3>Ссылки</h3>
            ...
        </section>
    </nav>
    <nav>
        <h2>Архив заметок по месяцам</h2>
        ...
    </nav>
</div>

Фактически структура оглавления ни сколько не поменялась. Но теперь разделы заданы явно с помощь тегов section, article, nav.

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

В спецификации HTML5 указано:

Sections may contain headings of any rank, but authors are strongly encouraged to either use only h1 elements, or to use elements of the appropriate rank for the section’s nesting level.

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

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

Смешанный подход

Неявные разделы могут появляется внутри явных разделов (но не наоборот).

<div>
    <h1>Свежие заметки :: Хранитель заметок</h1>
    <section>
        <h2>Свежие заметки</h2>
        <article>
            <h3>Тень у полей ввода в мобильном Safari</h3>
            ...
            <h4>Очень простое решение</h4>
            ...
        </article>
    </section>
</div>

Этот фрагмент документа, очевидно, выдаст следующую структуру:

  1. Свежие заметки :: Хранитель заметок
    1. Свежие заметки
      1. Тень у полей ввода в мобильном Safari
        1. Очень простое решение

Заголовок h4 образует неявный раздел внутри статьи, заданной явным образом тегом article.

Разделы без названия

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

Оставлять же без названия разделы section и article не стоит. Наличие такого раздела, например, может быть связано с не правильным выбором тега между div, section и article. Если для блока нельзя придумать заголовок, то его стоит просто разметить с помощью тега div.

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

<body>
    <article>
        <h1>Blog post title</h1>
        <p>Blog post content</p>
    </article>
</body>

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

hgroup

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

Инструменты и документация

Тень у полей ввода в мобильном Safari

У всех полей ввода в мобильном Safari на iPhone и iPad есть легкая внутренняя тень. Если это поле как-то особенно декорируется, то тень может помешать нормальному отображению. Убрать её можно, назначив фоном не сплошной цвет или текстуру, а градиент.

@media screen and (-webkit-min-device-pixel-ratio:0) {
    .search {
        /* remove inner shadow on iOS input */
        background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(hsla(0,0%,100%,0)), to(hsla(0,0%,100%,0)));
        background-image: -webkit-linear-gradient(hsla(0,0%,100%,0), hsla(0,0%,100%,0));
    }
}

Параметры подбираются в зависимости от контекста.

Так как эта тень никак не проявляет себя в настольных браузерах, то правила для неё фильтруем с помощью media queries и префиксов только для мобильных устройств.

Очень простое решение

Роман Комаров подсказал, что эту тень можно убрать более простым способом

@media screen and (-webkit-min-device-pixel-ratio:0) {
    .search {
        -webkit-appearance: none;
    }
}

Таблица без таблицы или display: table-cell для всех браузеров

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

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

.table {
    display: table;
}
.table-row {
    display: table-row;
}
.table-cell {
    display: table-cell;
}

Разметка, например, может быть такой:

<div class="table">
    <ul class="table-row">
        <li class="table-cell">Ячейка 1</li>
        <li class="table-cell">Ячейка 2</li>
        <li class="table-cell">Ячейка 3</li>
    </ul>
</div>

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

.table, .table-row, .table-cell {
    display: block;
    float: left;
}
.table-cell {
    clear: right;
    zoom: 1;
}
.table {
    overflow: hidden;
    position: relative;
}

Комбинация float: left; и clear: right; заставляет следующий блок намертво прилипнуть к предыдущему, образовывая ячейки нашей таблицы. Можно использовать прибивку в другую сторону, если нужен обратный порядок элементов.

Закомментировать HTML

Чтобы закомментировать кусок HTML нужно обрамить его последовательностью <!-- с одной стороны и --> с другой.

<!-- <p>Эта строка не разбирается и не отображается</p> -->

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

Самопроизвольное увеличение ширины кнопки в IE

В старых версиях IE кнопки обладали очень не приятным эффектом. У них появлялись отступы слева и справа, когда длина кнопки становилась значительной. Это могло проявляться как при наличии padding-left и padding-right, так и при достаточно длинной надписи. Особенно это становится актуально для кнопок, которые специально декорируются и, как правило, имеют шрифт большого кегля.

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

overflow: visible;

Пример «до» и «после» для IE6 и IE7.

overflow: visible убирает отступы у кнопки в IE6 и IE7

В новых версиях такого эффекта не наблюдается. Это правило может свободно применяться в основном стиле страниц.

Позиционируем всё

Конференция уральских веб-разработчиков 2011

В феврале 2011 года прошла уже вторая по счёту Конференция уральских веб-разработчиков, на которой я выступил с докладом «Позиционируем всё»

Презентация доклада (PDF, 2Мб)

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

CSS Grid — модульная сетка в YUI3

CSS Grid появился в YUI3 еще когда пакет был на ранней стадии тестирования и перекочевал туда из второй версии YUI. Он открывал широкие перспективы перед программистами верстальщиками в организации структуры страницы. Можно было делить страницу или блок на колонки, сменой всего лишь одного класса менять их местами и много другое. Там применялась обычная техника позиционирования через float: left или float: right.

Однако через некоторое время после официального выпуска разработчики объявили этот компонент устаревшим и не рекомендовали его применять в реальных проектах на базе YUI3.

The current Grids system was designed with the needs of older browsers (including Firefox 2) in mind. With Firefox 2 coming off the A-Grade in the next GBS update (due in July), there are structural changes that we want to make in engineering a successor to the 2.x version of Grids.

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

Теперь CSS Grid ориентирован только на работу в современных браузерах и основан на блоках с display: inline-block.

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

Как и прежде колонке необходимо явно задать ширину или можно воспользоваться заготовленными классами 24-х колончатой модульной сетки. Имя класса задает пропорции блока относительно родительского контейнера.

<div class="yui3-g">
    <div class="yui3-u-1-4">
        <div>колонка 25%</div>
    </div>
    <div class="yui3-u-1-2">
        <div>колонка 50%</div>
    </div>
    <div class="yui3-u-1-8">
        <div>колонка 12.5%</div>
    </div>
    <div class="yui3-u-1-8">
        <div>колонка 12.5%</div>
    </div>
</div>

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

Интересным моментом этого компонента является то, как разработчики легко избавились от нежелательных зазоров в несколько пикселей между колонками. Так как элементы уже не блочные, то лишние пробелы в коде между блоками с классом yui3-u не игнорируются, а учитываются при отрисовке, как если бы это были пробелы между словами. От этих артефактов можно избавиться, удалив эти пробелы и пожертвовав читаемостью кода. Но такой пробел мог бы случайно возникнуть на любом этапе разработки. В Yahoo поступили гораздо хитрее. Все зазоры между колонками убираются с помощью правил letter-spacing или word-spacing, в зависимости от браузера.

Режимы и квази-режимы

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

Квази-режимы являются весьма эффективными с точки зрения устранения режимов и уменьшению количества ошибочных действий.

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

<div>
    <div id="mode1" style="display: block;">Режим 1</div>
    <div id="mode2" style="display: none;">Режим 2</div>
    <div id="mode3" style="display: none;">Режим 3</div>
    <div id="mode4" style="display: none;">Режим 4</div>
</div>

Замена атрибута style на class у каждого блока особо ситуацию не меняет. Это все равно остается явное определение.

Мне нравится другой метод.

<div class="mode1">
    <div id="mode1">Режим 1</div>
    <div id="mode2">Режим 2</div>
    <div id="mode3">Режим 3</div>
    <div id="mode4">Режим 4</div>
</div>

Устанавливая класс у внешнего div в значения «mode1», «mode2», «mode3» или «mode4» активируются те или иные CSS-правила.

#mode1 {
    display: block;
}
#model2, #model3, #model4 {
    display: none;
}
.mode2 #mode1, .mode3 #mode1, .mode4 #mode1 {
    display: none;
}
.mode2 #mode2, .mode3 #mode3, .mode4 #mode4 {
    display: block;
}

Блок #mode1 будет видим по умолчанию, а остальные при соответствующем классе у внешнего блока.

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

Плюсы такого способа:

  1. Вся логика переключения представлений сконцентрирована в CSS-файле
  2. Удобно вести отладку. Нужно заменить только одной значение, чтобы полностью поменялся внешний вид.
  3. Уменьшается количество однотипного JavaScript-кода