Предлагаю читателям «Хабрахабра» перевод статьи «12 Little-Known CSS Facts (The Sequel)». Она совсем недавно была упомянута в дайджесте интересных материалов из мира веб-разработки и IT.

Update: немного «шлифанул» перевод напильником. Выражаю благодарность всем неравнодушным читателям.
Внимание! Под катом почти 1.5 Мб картинок и много интересных ссылок.

Итак, начнём-с…

1. В свойстве border-radius можно использовать slash-синтаксис.


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

Верите или нет, но следующий код валиден:

.box {
  border-radius: 35px 25px 30px 20px / 35px 25px 15px 30px;
}


Такой подход немного обескураживает в первый раз. Вот объяснение из спецификации:
Если значения указаны и «до», и «после» слеша, то значения «до» устанавливают горизонтальный радиус, а значения «после» « вертикальный.
Если slash отсутствует, то значения обоих радиусов считаются одинаковыми.

В спецификации также приводится следующая диаграмма:



Использование slash-а при указании значений позволит вам создавать несимметричные скругленные углы. Если хотите более подробно изучить эту тему, то почитайте указанную выше статью или, даже лучше, попробуйте интерактивное демо от MDN.

Большинство генераторов border-radius-ов не позволяют устанавливать дополнительные значения. Из всех найденных таких генераторов только MDN-овский это умеет.

2. Свойство font-weight может принимать «относительные» значения.


Чаще всего свойство font-weight принимает значение normal или bold. Иногда встречаются и целочисленные значения, кратные ста, такие как 100, 200 и т.д. до 900.

Но два возможных значения часто забывают — bolder и lighter.

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

В значениях веса, кратным ста, «жирный» равен 700, а «нормальный» — 400. Таким образом, если вы хотите установить вес в 300, то значение lighter, примененное к тексту, который унаследовал нормальный вес 400, установит как раз нужный вес. Если более «легкого» варианта шрифта нет (т.е. 400 — самый тонкий вариант шрифта), то те же 400 и останется, и от использования lighter эффекта не будет.

В примере используется шрифт Exo 2, который имеет 18 различных стилей, но из них нужны только некурсивные варианты шрифта — этого достаточно для всех числовых весовых значений.

В демке используется 12 вложенных box-элементов с различными значениями font-weight включая bolder и lighter, так что эффект от применения этих ключевых слов очевиден. Ниже приведены использованные стили. Обратите внимание на комментарии в коде и учтите, что каждый следующий элемент находится внутри предыдущего.
Много css-кода из демки
.box {
  font-weight: 100;
}
 
.box-2 {
  font-weight: bolder; /* maps to 400 */
}
 
.box-3 {
  font-weight: bolder; /* maps to 700 */
}
 
.box-4 {
  font-weight: 400;
}
 
.box-5 {
  font-weight: bolder; /* maps to 700 */
}
 
.box-6 {
  font-weight: bolder; /* maps to 900 */
}
 
.box-7 {
  font-weight: 700;
}
 
.box-8 {
  font-weight: bolder; /* maps to 900 */
}
 
.box-9 {
  font-weight: bolder; /* maps to 900 */
}
 
.box-10 {
  font-weight: lighter; /* maps to 700 */
}
 
.box-11 {
  font-weight: lighter; /* maps to 400 */
}
 
.box-12 {
  font-weight: lighter; /* maps to 100 */
}


В данном примере bolder и lighter, в конечном итоге, устанавливают следующие значения веса: 100, 400, 700 и 900. С девятью различными css-стилями при использовании этих ключевых слов не получится добиться значений 200, 300, 500, 600 и 800.

Это происходит из-за того, что вы указываете браузеру выбрать следующий вариант шрифта, который «жирнее» или «легче». А браузер выбирает не просто «следующий более жирный» или «следующий более тонкий» вариант, а «жирный» и «легкий» по отношению к текущему унаследованному варианту. Но, если самый «легкий» вариант шрифта имеет вес 300, например, как у Open Sans, а унаследованное значение равнялось 400, то при использовании «lighter» получится 300.

Такое поведение может сбивать с толку, но если вы «поиграетесь» с демо-примером, то всё встанет на свои места.

3. Существует свойство outline-offset


Свойство outline довольно широко известно из-за использования при дебагинге (из-за него страница не «расползается»). В спецификации, однако, добавлено свойство outline-offset, которые делает ровно то, что и означает — указывает сдвиг внешней границы от элемента.

В демо при изменении положения ползунка меняется и величина сдвига границы. В примере указаны значения от 0px до 30px, но вы можете изменить пределы на своё усмотрение. Обратите внимание, на то, что свойство outline — сокращенное свойство и не включает в себя outline-offset и его придется указывать отдельно.

Главным недостатком свойства outline-offset является тот факт, что оно поддерживается всеми браузерами кроме Internet Explorer (даже в IE 11 его нет).

4. Существует свойство table-layout


Не стоит путать это свойство с display: table.
Т.к. table-layout — не самая простая «фишка» CSS для понимания, давайте сначала обратимся к спецификации, а потом посмотрим на демо:
При таком подходе вертикальное выравнивание таблицы зависит не от содержимого ячейки, а от ширины таблицы, ширины колонки и границ или отступов между ячейками.

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

Но, если серьёзно, использование демо поможет.



В приведенном примере видно преимущество использования значения fixed для table-layout по сравнению со значением auto. Использование такого подхода не панацея, но всегда неплохо знать о такой возможности при использовании таблиц с ячейками различной ширины.

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

5. Свойство vertical-align работает по разному в ячейках таблиц и других элементах


Если вы занимаетесь разработкой сайтов с середины двухтысячных или раньше или знаете достаточно много о HTML и email-письмах, то вы, возможно, предполагаете, что свойство vertical-align является обычным улучшением старого HTML4-аттрибута valign, который сайчас указан как устаревший и несоответствующий стандарту HTML5.
Но свойство vertical-align в CSS работает не совсем так. Но не в таблицах. Что, по-моему, достаточно странно, но я полагаю, это лучше, чем свойство, вообще не работающее в таблицах.

Итак, какова разница при использовании этого свойства в обычных элементах и ячейках таблиц?

Если vertical-align применяется НЕ к ячейкам таблиц, то оно работает по следующим правилам:
  • Применимо только к inline или inline-block элементам;
  • Не влияет на содержимое элемента, а только меняет его положение относительно других inline и inline-block элементов
  • На свойсто могут влиять настройки текста или шрифта, такие как line-height и размер смежных inline и inline-block элементов.

Демо.



Свойство vertical-align установлено у поля ввода input. При нажатии на кнопки значение свойства меняется. Обратите внимание, что все эти значения различны.
Примите во внимание, что данная демка — лишь поверхностный взгляд на vertical-align. Более глубокое его рассмотрение можно изучить тут.

Когда vertical-align применяется к ячейке таблицы, то оно работает совсем по-другому. В частности, данное свойство применяется и к содержимому ячеек.
Демо.



Как показано в примере, для vertical-align есть только 4 варианта значения, которые применимы к ячейкам таблицы, кроме того значение baseline влияет и на ячейки того же уровня, что и ячейка, к которой свойство применено.

6. Псевдо-элемент ::first-letter умнее, чем вы думаете


Псевдо-элемент ::first-letter позволяет вам стилизовать первую букву элемент (примечание переводчика — привет, капитан!), например, красиво выделить её как в печатных книгах много лет назад.

Браузеры достаточно хорошо поддерживают стандарт относительно этой «первой буквы». Впервые этот псевдо-элемент я увидел в твите Matt Andrews, хотя он явно подразуемевает, что это всё таки плохая «фишка». Демо.


Это здорово, что 4 крупных браузера отображают этот псевдо-элемент одинаково, потому что, по-моему, это и есть правильный вариант отображения. Выглядело бы странным, если бы какой-нибудь символ, такой как одиночная скобочка, воспринимался как «первая буква» — это скорее можно было бы считать «первым символом», который достоин собственного нового псевдо-класса.

7. Вы можете использовать «невалидные» символы в качестве разделителей в перечне классов элемента


Этот подход обсуждал Ben Edvard в 2013 году, и, я думаю, стоит подробнее рассмотреть этот вопрос.
Ben писал об использование slash («/») в качестве разделителя HTML-классов по группам для того, чтобы сделать код более читаемым и проще сканируемым. Автор указывает, что несмотря на то, что неэкранированный slash является «невалидным» символом, браузеры его просто игнорируют, а не выдадут ошибку.
Допустим, у вас такой HTML-код:
<div class="col col-4 col-8 c-list bx bx--rounded bx--transparent">

При использовании slash-ей получается следующее:
<div class="col col-4 col-8 / c-list / bx bx--rounded bx--transparent">

Вы можете использовать любой символ (валидный или не очень) для получения того же эффекта:
<div class="col col-4 col-8 ** c-list ** bx bx--rounded bx--transparent">
<div class="col col-4 col-8 || c-list || bx bx--rounded bx--transparent">
<div class="col col-4 col-8 && c-list && bx bx--rounded bx--transparent">

Все перечисленные варианты работают нормально, в чем можно убедится, посмотрев демо
Конечно же, эти разделители не могут быть использованы в css-стилях как классы. Следующий код является неправильным и не применится к элементу:
./ {
  color: blue;
}

Если вы вынуждены использовать подобные символы в названиях своих css-классов, то можно использовать вот этот инструмент. Таким образом, вышеуказанный код будет работать, если его преобразовать до такого:
.\/ {
  color: blue;
}

Если продолжать эту тему, то Unicode-символы вообще не должны быть экранированы и можно творить разные безумные вещи:
.¦ {
  color: hotpink;
}
 
.? {
  color: yellow;
}

  <div class="¦ ?"></div>

Кроме того, вы можете «экранировать» и эти символы тоже, вместо того чтобы использовать их напрямую. Следующие css-строки аналогичны предыдущим:
.\2665 {
  color: hotpink;
}
 
.\2605 {
  color: yellow;
}


8. Количество повторов анимации может принимать дробные значения


При описании анимации можно использовать свойство animation-itereation-count для того, чтобы указать, какое количество раз анимация будет проиграна:
.example {
  animation-iteration-count: 3;
}

Вышеуказанный код говорит, что анимация будет проигрываться 3 раза. Но, возможно, вы не знали, что можно указывать и дробные значения:
.example {
  animation-iteration-count: .5;
}

В этом случае анимация будет проиграна лишь на половину первой итерации. В демо на CodePen верхнему кружку указано количество итераций 1, а нижнему — .5



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

Но в этом примере уже применяется сглаживание:



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

Если вы разбираетесь в различных функциях сглаживания, то заметите, что при использовании ease-in-out второй кружок займет то же итоговое положение, что и при использовании linear.

9. Анимация, записанная в краткой форме может не работать из-за своего названия


Некоторые разработчики заметили это случайно, хотя в спецификации есть соответствующее предупреждение. Давайте рассмотрим следующую анимацию:
@keyframes reverse {
  from {
      left: 0;
    }
 
    to {
      left: 300px;
    }
}
 
.example {
    animation: reverse 2s 1s;
}

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

Анимация не работает, т.к. reverse — валидное ключевое слово для свойства animation-direction. Так же анимация не будет работать при использовании в краткой форме в названии других ключевых слов. Но всё работает хорошо при использовании «полной» формы описания.

К ключевым словам-значениям animation-direction, «ломающими» анимации, стоит отнести и ключевые слова, относящиеся к функциям сглаживания, а так же infinite, alternate, running, paused и так далее.

10. В селекторе можно указать диапазон элементов.


Не знаю, кто начал это первым использовать, но первым я увидел это демо от Gunnar Bittersmann. Допустим, у вас есть список из 20 элементов и нужно выбрать элементы с 7 по 14 включительно. Это можно сделать вот так:
ol li:nth-child(n+7):nth-child(-n+14) {
  background: lightpink;
}


Демо.



В Safari из-за бага такой приём работать не будет. Однако, решение всё таки есть — Matt Pomaski починил это. Нужно всего лишь перечислить элементы выборки в другом порядке:
ol li:nth-child(-n+14):nth-child(n+7) {
  background: lightpink;
}

Этот код использует цепочку связанных псевдо-классов. Хотя выражение немного запутанное, ключевые числа 7 и 14 в нём используются без изменений.
Постараюсь объяснить, как это работает. Первая часть выражения говорит: «выбрать седьмой элемент, а потом все ПОСЛЕ него». А вторая часть — «выбрать четырнадцатый элемент, а потом все ДО него». Т.к. части связаны, то на пересечении запросов получается требуемый диапазон.

Для более детального рассмотрения этой темы рекомендуется почитать более раннюю статью.

11. Псевдо-элементы могут быть применены к некоторым «пустым» элементам


Наверняка вы пробовали использовать псевдо-элементы с изображениями или input-ами. Но это не работает с «замещаемыми» элементами (примечание переводчика — в комментариях к этому переводу SelenIT2 постарался объяснить, что же это за зверь такой). Я думаю, многие разработчики предполагают, что пустые элементы (те, у которых нет закрывающего тега) так же попадают в эту категорию. Но это не так.

Вы можете использовать псевдо-элементы вместе с некторыми пустыми элементами, которые не являются «замещаемыми». Например, <hr> в этом демо.



Цветная область является тегом <hr> и его двумя псевдо-элементами ::before и ::after. Интересно, что подобного результата не получилось добиться от тега <br>, который тоже не является «замещаемым».

Так же, вы можете использовать псевдо-элементы вместе с мета-тегами или <link>, если, конечно, готовы применить к ним свойство display: block как в этом демо.

12. Некоторые значения атрибутов регистро-зависимы при использовании в селекторах


Наконец-то, что-то непонятное. Допустим, есть такой HTML:
<div class="box"></div>
<input type="email">

Можно стилизовать оба этих элемента следующим образом:
div[class="box"] {
  color: blue;
}
 
input[type="email"] {
  border: solid 1px red;
}

Это замечательно работает. А как на счёт такого?
div[class="BOX"] {
  color: blue;
}
 
input[type="EMAIL"] {
  border: solid 1px red;
}


Значения обоих атрибутов написаны в верхнем регистре. В этом случае .box-элемент не получит стилизации, т.к. атрибут class регистрозависим. Поле ввода email, однако, будет стилизовано, т.к. аттрибут type регистронезависим. В этом нет ничего новаторского, но, возможно, вы это не замечали раньше.

Комментарии (21)


  1. tegArt
    21.07.2015 12:50
    +14

    Блин… переводил-переводил, 2 пункта не осталось и на тебе :(


    1. Zdomb Автор
      21.07.2015 13:17
      +12

      Ох не зря я вчера ночью этот перевод доделывал, видимо (:


      1. tegArt
        21.07.2015 13:24
        +10

        Я не знаю какие неведомые силы я на себя натравлю, но мне совесть не позволит забить и не выложить свой вариант… столько времени на перевод ушло… А вам успехов и добро пожаловать на хабр )


        1. vmb
          21.07.2015 15:10
          +1

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


          1. vmb
            21.07.2015 18:41
            +4

            Голосуйте: habrahabr.ru/post/263227


        1. Zdomb Автор
          22.07.2015 00:20
          +1

          Спасибо за пожелания.
          Итогом этого небольшого конфликта интересов может быть новая полезная фишка на Хабре, что уже есть неплохо для первого поста (:
          Даже не знаю, стоит ли загадывать подобных эффектов для следующих моих «творений»…


        1. spmbt
          22.07.2015 22:25

          Не толпитесь, уважаемые авторы, хлеба хватит на всех.

          Оба варианта понравились и подобные вещи имеют право быть.

          А чтобы не тратилось время 2 и более человек зря, самое удобное — сделать функцию нечёткого текстового поиска по названию или началу статьи по ссылке для авторов, собирающихся публиковаться.

          Тогда сайт мог бы рекомендовать ввести УРЛ оригинала и перевод названия сразу, для проверки, не занимается ли переводом кто-то ещё. Тогда, если каждый автор начнёт работу со ввода заготовки статьи или даже одного URL оригинала, всем последующим при таком же вводе выдавалось бы предупреждение, что столько-то человек с таким-то переводческим рейтингом этим же самым интересовались, а столько-то — имеют заготовку перевода. В этой же форме можно писать сообщение от переводчика, когда планирует закончить и при желании — раскрытие авторства. А отдельно в Твиттер — кто-то из авторов запишет, кто-то забудет, а кто-то вообще не будет знать.


  1. SelenIT2
    21.07.2015 13:29
    +5

    Но это не работает с «замещаемыми» элементами (буду благодарен, если подскажете, что имелось ввиду — примечание переводчика).

    Более того, я буду благодарен, если авторы спецификаций наконец соберутся с духом, договрятся друг с другом и объяснят всему сообществу, что имеется в виду:) А то разные спецификации в разное время понимали под этим совершенно разные вещи.

    В CSS1 определение было очень простым:
    Замещаемый элемент — элемент, который замещается контентом, указываемым из этого элемента. Например, в HTML элемент IMG замещается картинкой, указанной в его атрибуте SRC.

    В CSS2.1 всё начало запутываться:
    Замещаемый элемент

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

    Контент замещаемых элементов не рассматривается в модели рендеринга CSS.

    В HTML5 вообще не стали заморачиваться с определением, а тупо в лоб перечислили, какие элементы относятся к замещаемым. Фактически туда попал весь "embedded content", который вообще как-либо отображается.

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

    С какого бока упомянутый hr попал в замещаемые — тоже вопрос (конечно, «объемная» черта, которым он по умолчанию рисовался во всяких IE3±, похожа на системный контрол...), но, опять же… вот так оно сложилось:)


    1. SelenIT2
      21.07.2015 13:56

      Upd: традиция считать контролы форм замещаемыми, по-видимому, тянется из промежуточной версии CSS2.0 (наспех принятой в 1998-м и почти сразу же отмененной в пользу многострадальной 2.1, утрясавшейся аж до 2011-го, и то не до конца).


    1. Zdomb Автор
      22.07.2015 00:14

      Всё чудесатее и чудесатее!
      Спасибо за развернутый комментарий, добавил его упоминание в перевод


  1. titulusdesiderio
    21.07.2015 13:37
    +2

    ¦, ? — очешуеть!
    за теги отдельный +


    1. Ohar
      21.07.2015 16:10

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


      1. SelenIT2
        21.07.2015 16:39
        +2

        На самом деле, как раз эта фича — хорошо забытое старое двух пяти восьмилетней давности. Да и экранирование запрещенных символов в селекторах тоже не ново, во времена IE5.5-8 его умеренно активно юзали для стилизации VML-элементов (тогдашний IE считал двоеточие от неймспейс-префикса частью имени тега).

        Да, для серьезных проектов лучше бы этой фиче оставаться малоизвестной, хотя… в наши дни автоматизации всего и вся, для всяких минификаторов — может, оно и имеет право на жизнь?


  1. DjoNIK
    21.07.2015 14:50
    -2

    1. mapron
      21.07.2015 17:31

      Первый коммент в ЭТОМ посте читали?


    1. zollotov
      21.07.2015 23:43
      +1

      Да, сегодня день одинакового CSS на хабре !:)


      1. mapron
        22.07.2015 04:56
        +1

        Особенно интересно смотрятся названия постов. Читаешь «12 малоизвестных фактов о CSS », ставишь плюс, видишь «12 малоизвестных фактов о CSS — продолжение», думаешь, о, почитаю продолжение! И тут эффект дежа вю =)


        1. tegArt
          22.07.2015 08:25
          +4

          Справедливости ради слово «продолжение» есть в названии оригинальной статьи, но получилось забавно, согласен :)


  1. berezuev
    22.07.2015 13:00
    -2

    За .¦ .? надо палками из профессии гнать. И за другие «невалидные» символы, на всякий случай, тоже.

    Понаверстают хрени, потом за ними переписывать.


    1. SelenIT2
      22.07.2015 13:15
      +1

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


    1. DmitryAnatolich
      29.07.2015 22:25

      Кого надо гнать из профессии, так это кодеров LJ. За что? Да за то, что в CSS не может быть не-ASCII символов (включая кириллицу, да). Ни в каком виде.