WTF, HTML и CSS?
Ниже перечислены причины, по которым HTML и CSS могут заставить вас чертыхнуться. Это список затруднений, ошибок и дилемм, которые в них присутствуют и стабильно портят нам настроение.
Содержание
- Объявление doctype
- Расчет размеров контейнера
- Единицы Rem и мобильный Safari
- Обтекаемые элементы идут первыми
- Обтекаемые элементы и клирфикс
- Обтекаемые элементы и вычисление высоты родителя
- Все обтекаемые элементы — блочные
- Смежные вертикальные отступы схлопываются
- Стилизация строк таблицы
- Firefox и кнопки с помощью тега
<input>
- Внутреннее выделение у кнопок в Firefox
- Всегда устанавливайте
type
тега<button>
- Лимит на количество селекторов в Internet Explorer
- Объяснение того, как работает позиционирование
- Ширина элемента и его позиционирование
- Фиксированное позиционирование и свойство
transform
Объявление doctype
Всегда нужно прописывать doctype. Я рекомендую простой doctype HTML5:
<!DOCTYPE html>
Его отсутствие может вызвать проблемы с таблицами, инпутами и т.д., если страница будет отображаться в режиме совместимости (quirks mode).
Расчет размеров контейнера
Элементы, для которых установлен width
на самом деле шире, если у них есть
padding
и/или border-width
. Чтобы этого избежать, используйте массово
распространенный на сегодняшний день сброс box-sizing: border-box;
.
Единицы Rem и мобильный Safari
В то время как мобильный Safari поддерживает использование rem
в любом css-свойстве,
при использовании rem
в медиа-запросах происходит конфуз и он начинает бесконечно
менять размеры текста.
На данный момент вместо rem
стоит использовать em
.
html {
font-size: 16px;
}
/* Вызывает баг с изменением размеров Mobile Safari */
@media (min-width: 40rem) {
html {
font-size: 20px;
}
}
/* В Mobile Safari все отлично работает */
@media (min-width: 40em) {
html {
font-size: 20px;
}
}
Нужна помощь Если у вас есть ссылка на баг-репорт в Apple или WebKit, я с удовольствием его добавлю. Сам я не уверен куда слать баг-репорт, так как этот баг воспроизводится только на мобильном Safari.
Обтекаемые элементы идут первыми
Элементы, к которым применен float, всегда должны отображаться в документе первыми. Элементы надо обернуть в какой-то блок, иначе может возникнуть эффект лесенки, когда контент показывают сбоку от обтекаемого элемента, а не под ним.
<div class="parent">
<div class="float">Float</div>
<div class="content">
<!-- ... -->
</div>
</div>
Обтекаемые элементы и клирфикс
Если вы применили к элементу float
, то, вероятно, вы захотите его заклирить.
Любой контент, который идет после такого элемента будет его обтекать, если
к элементу не применен клирфикс. Для создания клирфикса можно использовать
техники, приведенные ниже.
Для клирфикса, вызываемого отдельным классом можно использовать микро клирфикс.
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
В качестве альтернативы можно задать родителю overflow
, со значениями auto
или hidden
.
.parent {
overflow: auto; /* clearfix */
}
.other-parent {
overflow: hidden; /* clearfix */
}
Имейте ввиду, что overflow
может привести к появлению нежелательных побочных
эффектов, обычно касающихся элементов, для которых установлено позиционирование,
отличное от static
.
Подсказка Сделайте себе и своим сотрудникам одолжение, добавляя комментарии вроде
/* clearfix */
, когда клирите обтекаемые элементы, так как свойства могут использоваться там и по совершенно другим причинам.
Обтекаемые элементы и вычисление высоты родителя
Высота родительского элемента, для всех дочерних элементов которого установлен float
будет равна 0. Чтобы высота соответствовала реальной следует использовать clearfix.
Все обтекаемые элементы — блочные
Элементы с установленным float
автоматически получают display: block;
.
Поэтому не имеет смысла устанавливать и то и другое, так как float
все равно
перезапишет установленное вами значение display
.
.element {
float: left;
display: block; /* Не обязательно */
}
Забавный факт Много лет назад мы должны были устанавливать
display: inline;
для того, чтобы избежать бага с двойными отступами в IE6. Однако, эти дни давно в прошлом.
Смежные вертикальные отступы схлопываются
Верхний и нижний margin
соседних элементов (когда один идет сразу за другим)
могут и будут схлопываться, но это не касается элементов с float
или тех,
которые позиционированы абсолютно. Подробнее об этом вы можете прочесть в этой
статье в MDN или разделе о схлопывании margin в спецификации CSS2.
Смежные горизонтальные margin
никогда не схлопываются.
Стилизация строк таблицы
Для строк таблицы, тегов <tr>
, нельзя задать border
, если не задан
border-collapse: collapse;
на родительском элементе <table>
. Более того,
если у дочерних тегов <td>
или <th>
установлено то же значение
border-width
, что и для <tr>
, то к <tr>
border
не применится.
Можете убедиться в этом на примере.
Firefox и кнопки с помощью тега <input>
По загадочным причинам Firefox применяет к тегу input
с типами submit
и
button
line-height
, которое не удастся перезаписать с помощью CSS. Есть
два решения этой проблемы:
- Использовать элемент
<button>
- Не использовать в кнопках
line-height
Если вы предпочли первый вариант (и я бы рекомендовал именно его, так как тег <button>
просто отличный), вот что нужно знать:
<!-- Плохая идея -->
<input type="submit" value="Сохранить изменения">
<input type="button" value="Отменить">
<!-- Отлично работает везде -->
<button type="submit">Сохранить изменения</button>
<button type="button">Отменить</button>
Если вы захотите выбрать второй, просто не устанавливайте line-height
и
используйте для вертикального выравнивания текста кнопки только padding
.
Откройте пример в Firefox, чтобы увидеть, в чем проблема и как с ней
справится.
Хорошие новости Похоже в 30-й версии Firefox ошибку исправят. Но это хорошая новость для нас в будущем, а пока не забывайте исправлять этот баг в CSS.
Внутреннее выделение у кнопок в Firefox
Firefox добавляет внутреннее выделение в кнопках (и в <input>
, и в
<button>
) для :focus
. Вероятно, это делается для повышения доступности,
но расположение весьма странное. Чтобы избавиться от этого безобразия можно
использовать следующий CSS:
input::-moz-focus-inner,
button::-moz-focus-inner {
padding: 0;
border: 0;
}
Можете увидеть как это работает в том же примере, что и в предыдущем разделе.
Подсказка Добавляйте какое-то состояние для buttons, links, и inputs, находящимся в фокусе. Обеспечение очевидности и доступности интерфейсов это первостепенная задача, важная как для продвинутых пользователей, которые быстро пробегают контент глазами, так и для пользователей с плохим зрением.
Всегда устанавливайте type
тега <button>
Значение по умолчанию атрибута type
— submit
, что значит, что любая кнопка в
форме может её отправить. Следует использовать type="button"
для любых кнопок,
которые этого делать не должны и явно определять type="submit"
для остальных.
<button type="submit">Сохранить изменения</button>
<button type="button">Отменить</button>
Для действий, которые требуют использования тега <button>
не находящегося в
форме используйте type="button"
.
<button class="dismiss" type="button">x</button>
Забавный факт: IE7 явно не корректно поддерживает атрибут
value
тега<button>
. Вместо того, чтобы прочесть значение атрибута, он получает его изinnerHTML
(содержимое между открывающим и закрывающим тегом<button>
). Но, по двум причинам, я не вижу в этом проблемы: IE7 уже почти не используется и это достаточно странная ситуация, когда одновременно заданы и значение атрибутаvalue
и контент внутри<button>
.
Лимит на количество селекторов в Internet Explorer
Internet Explorer 9 и ниже обладает ограничением на 4,096 селекторов в
таблице стилей. Кроме того существует лимит в 31 таблицу стилей и <style></style>
подключенных на одной странице. Все таблицы сверх этого лимита просто игнорируются
браузером. Или разбивайте ваш CSS или начинайте рефакторить. Я бы предложил последнее.
В качестве полезного дополнения, вот описание того, как браузеры считают селекторы:
/* Один селектор */
.element { }
/* Ещё два селектора */
.element,
.other-element { }
/* Ещё три селектора */
input[type="text"],
.form-control,
.form-group > input { }
Объяснение того, как работает позиционирование
Элементы с position: fixed;
позиционируются относительно вьюпорта браузера.
Элементы с position: absolute;
позиционируются относительно ближайшего родителя
со значением position
, отличным от static
(например, relative
, absolute
, или fixed
)
Ширина элемента и его позиционирование
Не стоит задавать width: 100%;
для элементов с position: [absolute|fixed];
,
left
, и right
. Использование width: 100%;
работает так же как совместное
использование left: 0;
и right: 0;
. Стоит использовать либо то, либо другое,
но не все вместе.
Фиксированное позиционирование и свойство transform
Браузеры игнорируют position: fixed;
если у родителя элемента установлено
свойство transform
. Использование трансформаций создает новый контейнер,
в результате чего элемент принудительно оказывается в блоке с position: relative;
и элемент с фиксированным позиционированием начинает вести себя как элемент с
position: absolute;
.
Посмотрите пример и прочтите пост Эрика Мэйера (Eric Meyer) на эту тему.