Нюансы CSS

Лев Солнцев 21 апреля 2011

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

К примеру многие знают, что цвет в шестнадцатеричной нотации вида #RRGGBB можно писать сокращённо как #RGB, если каждый старший разряд совпадает с младшим, или что нуль можно писать без единиц измерения, таких как «px» или «em», так как нуль — в любой системе измерения нуль.

Что считает браузер

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

Правила margin-left:auto и margin-right:auto при ширине блока меньше ширины контейнера равномерно распределяют оставшееся место. Так, задав только margin-left:auto, можно выровнять элемент по правому краю.

В обычном потоке элементы идут сверху вниз, поэтому margin-top:auto устанавливается нулевым. Однако для абсолютно спозиционированных элементов действует то же распределение свободного места, и аналогичным образом можно сделать центрирование по вертикали при заданных высоте и top с bottom (не работает в IE7).

Сокращения и значения по умолчанию

Не менее широко распространено использование спрайтов, например: background:url(icons.png) 0 0 no-repeat. Однако, background-position:0 0 является значением по умолчанию, поэтому 0 0 в таком случае можно опустить.

Но если в background-position задана хоть одна координата: будь то top, left или 100%, то вторая принимает значение 50%. Это может быть полезно для значков, выровненных посередине строки по вертикали — достаточно указать лишь положение слева или справа.

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

При подобном написании:

	h1 {
	    font:2em/1 Arial,sans-serif;
	}

задаётся не только шрифт, его размер и интерлиньяж, но и сразу сбрасывается полужирное написание (font-weight:normal), а также другие свойства, такие как font-style (курсив) и font-variant (капитель). Некоторые авторы совершенно зря дописывают в font значение normal. Непонятно даже к какому правилу из перечисленных трёх оно могло бы относиться — порядок следования в сокращённых свойствах неважен, и неучитывание порядка могло приводить к ошибкам лишь в устаревших браузерах.

Другими недопонятыми, но тоже полезными сокращёнными записями являются отдельные правила рамок border-width, border-style и border-color. Например, благодаря им можно задать верхнюю и нижнюю одинаковые рамки не дублированием кода в border-top и в border-bottom, а подобным образом:

	border:solid gray;
	border-width:3px 0;

Кроме меньшего размера кода, такая запись полезна тем, что каждое значение написано только один раз, и поменять, скажем, solid на double не составляет труда.

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

Есть возможность, что border-radius может быть включен в сокращённую запись border (предлагался вариант с косой чертой «/»), поэтому записывайте на всякий случай border-radius после border.

Переусложенение

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

	a img {
	    border:0;
	}

Однако в таком случае бразуер будет на каждой картинке проверять, не находится ли она в ссылке. Если для простых страниц это кажется несущественным (вы и глазом моргнуть не успеете за те несколько миллисекунд, на которое задержится отображение страницы), то в какой-нибудь фотогалерее со сложной анимацией это может лишить вас нескольких кадров в секунду, прибавляя ощущения «тормознутости». Куда проще написать так:

	img {
	    border:0;
	}

Эффект будет тот же самый. Уточнение, что рамка появляется на ссылках a в данном случае совершенно излишне.

Из тех же соображений производительности, как правило, незачем писать имя тэга вместе с классом и уж тем более с идентификатором, который сам по себе уникален. В данном правиле могут быть только два исключения: уточнение для конкретного тэга (возможно в этом случае у вас очень общий класс), и обход недостатка IE7, где эффекты при наведении :hover тормозят, если в селекторе не указан тэг (то есть надо писать a.class:hover { color:#FC0; }).

Наследование

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

	th {
	    vertical-align:bottom;
	}
	td {
	    vertical-align:top;
	}

Вроде бы всё здорово, но, сделав так, вы лишаетесь простого способа переопределить выравнивание для целого ряда:

	tr.images {
	    vertical-align:middle;
	}

Этого можно избежать, воспользовавшись тем, что ячейки таблицы th и td наследуют правила от рядов tr, а те в свою очередь от блоков thead, tfoot и tbody.

	thead {
	    vertical-align:bottom;
	}
	tbody,
	tfoot {
	    vertical-align:top;
	}

Стоит отметить, что все браузеры, кроме IE8, наследуют еще и значение text-align для th, а сам IE8 понимет ключевое слово inherit, что также позволяет наследовать значение text-align.

Заключение

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

Теги: , ,

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

  1. tibalt 21 апреля 2011 в 20:20

    полезно, спасибо.
    не знал про использование margin-ов для выравнивания по правому краю и вертикально.

  2. kratkar 22 апреля 2011 в 13:13

    А что скажешь насчёт такой записи?

    td { vertical-align: top; }
    td[valign="middle"] {
      vertical-align: middle;}
    td[valign="bottom"] {
      vertical-align: bottom;}
    td[valign="baseline"] {
      vertical-align: baseline;}
    

    Что позволяет делать по умолчанию выравнивание сверху и использовать ||
    Т.к. виз. редакторы(TinyMCE, FCKeditor) так и делают

  3. Лев Солнцев 22 апреля 2011 в 14:10

    kratkar, думаю, что это плохой пример. Кроме смешивания HTML-кода и оформления ещё и по причинам, указанным в статье.

  4. Роман Комаров 22 апреля 2011 в 14:39

    Всё клёво, но большая часть может оптимизироваться автоматически, если есть желание, можно следить (и писать реквесты) вот к этому проекту — https://github.com/afelix/csso/

  5. Лев Солнцев 22 апреля 2011 в 15:06

    Роман, знать полезно не только чтобы писать, но и чтобы понимать написанное.

  6. Роман Комаров 22 апреля 2011 в 15:08

    Согласен :)
    Но иногда как раз не стоит писать всё супер-оптимизированно, т.к. может теряться читаемость. Хотя это и не так часто бывает критично.

  7. exessqd 22 апреля 2011 в 16:52

    kratkar эти атрибуты устарели(Deprecated) ещё в html4 и использовать их не рекомендуется, если быть точнее строго запрещено.

  8. Cuprum 23 апреля 2011 в 18:55

    Спасибо за margin:auto;!
    Помню как однажды весь извёлся, когда не мог понять, почему сбрасывается ранее заданная высота строки после объявления

    font: 16px Arial, sans-serif;
    
  9. alex.kotomanov 5 мая 2011 в 14:12

    Paul Irish в своём блоге пишет:

    - in Webkit (Chrome/Safari), applying font-weight:bold to faux-bold some @font-face'd text will not succeed. Same applies for font-style:italic. You can fix by adding the following to your @font-face declaration: (via doctype, crbug/31883, crbug/35739, webk.it/34147)

    
          font-weight:normal;
          font-style:normal;
          font-variant:normal;
          /* these values are defaults in FF/Opera/IE but not webkit */
    
    

    Получается, что записть font: 16px Arial, sans-serif; не всегда работает.

  10. Лев Солнцев 5 мая 2011 в 14:33

    alex.kotomanov, это относится к определению подключаемого шрифта @font-face, и вообще говоря просто ошибка. Запись font: 16px Arial, sans-serif; сработает, так как в ней нет ничего подобного.

  11. venom_ 6 июля 2011 в 22:50

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

  12. Дмитрий 18 июля 2011 в 0:31

    Спасибо. Постоянно забываю об этом:

    a.class:hover { color:#FC0; }
    

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

    font: 400 16px Arial, sans-serif;
    

    ,

    font: 800 16px Arial, sans-serif;
    

    . 400 - normal. 800, если не изменяет память, - bold

    Ну и из сокращений CSS3 удобны:

    
    border-radius: 10px 0 3px 2px;
    border-radius: 0 14px;
    
    box-shadow: #d9bfd9 -30px -30px 18px 1px, #afdfc9 85px 30px 23px 1px, #f4f4f7 -30px 150px 35px 2px;
    
    

    А чем плохо

    td[valign="middle"]
    

    ? Очень удобно в некоторых ситуациях и не надо стучаться к целевому элементу через тонны классов и id. Некоторые CMS с хрено-бетонным каркасом, подлезти к которому изящнее никак почти.

    
    a[rel='external'] {}
    input[type='text'] {}
    ...
    
    
  13. loto_s 17 августа 2011 в 12:58

    Что-то я не понял про margin:auto для абсолютного позиционирования, это никогда не работало. Специально еще раз попробовал - НИФИГА. Родительский блок тоже абсолют. Может я что-то не так делаю.

    
    #popup.video #video_content{
        display:block;
        position:absolute;
        margin:auto;
    }
    
    

    .

  14. Лев Солнцев 17 августа 2011 в 13:29

    loto_s, для центрирования подобным образом должны быть ещё заданы положения со всех сторон. Например:

    
    top:0;
    right:0;
    bottom:0;
    left:0
    
    

    Ещё должны быть заданы размеры (ширина, высота) у элемента. Картинки, как правило, уже их имеют. Тогда свободное оставшееся место, если таковое будет, равномерно распределится между полей margin:auto.

  15. loto_s 23 августа 2011 в 17:53

    Лев Солнцев, да но такой подходи неприемлем, т.к. возникают ситуации, когда заранее не известна высота или ширина контента. Как быть в этом случае?

  16. Лев Солнцев 23 августа 2011 в 18:13

    loto_s, использовать другие подходы. Например:

    
    right:50%;
    bottom:50%;
    transform:translate(50%,50%);
    
    

    или использовать display:table, а в нём display:table-cell с выравниванием

  17. loto_s 25 августа 2011 в 18:38

    К сожалению, данное решение не будет кроссбраузерным, IE7- как обычно словит гайку. Остается только скриптами 8(

  18. Nargus 8 февраля 2012 в 22:06

    За margin спасибо. До внедрения position:center; будет полезно знать. Да и выравнивание вправо хорошо.
    Пример с border не понравился. Как пример - хорошо, но так писать считаю излишним и переоптимизированным.
    По таблицам - возможно вы и правы по поводу указания на tr/tbody и т.п., т.к. теоритически это должно облегчить отрисовку браузеру, если он не будет при каждой td опрашивать правила. Хотя, как правило на td задаются какие-то отступы, т.ч. использования селектора td не избежать.
    Ctrl+F опечатка "border-stlye"

  19. Лев Солнцев 8 февраля 2012 в 23:08

    Спасибо за сообщение об опечатке — исправлено.

  20. Del'ka 4 сентября 2012 в 20:34

    Спасибо за разъяснения по поводу вертикального центрирования абсолют-блока. Знал что должно работать, но не понимал почему не выходит, ведь Мейер же написал что работает! Правда теперь новая загадка: зачем нужны указания top и bottom, почему нельзя просто указать height и margin.

Перейти к началу