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

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



Ниже изложено то, чему руководства по CSS меня не научили.

Свойство padding-top относительно ширины родительского элемента


Как часто вы использовали относительные единицы в CSS? Я их большой поклонник, потому что они позволяют создать адаптивный веб-сайт, не слишком углубляясь в медиазапросы. Если вы хотите установить высоту элемента в половину от высоты родителя, то достаточно просто написать height: 50%.

Вы можете использовать относительные единицы где угодно. Если хотите добавить расстояние между двумя вертикальными элементами, то можете написать margin-top: 15% и появится внешний отступ. Расстояние будет составлять 15% от исходной высоты. Я думаю, вы все это знаете, и не буду тратить ваше время. Но, возможно, вы не знаете, что все не так просто.

В некоторых ситуациях лучше использовать padding вместо margin. Но когда вы устанавливаете padding-top: 15%… Что за?..

Свойство не работает так, как мы ожидаем. Оно не устанавливает параметры относительно высоты родителя. Что происходит?

Объяснение


Оно устанавливает параметры относительно родительской ширины. Вам нужна демонстрация? Вот:


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

Нет, я шучу — нет никаких объяснений, почему так происходит. По крайней мере, я нигде не смог найти объяснений. Просто так происходит, имейте это в виду.

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

.parent {
  height: auto;
  width: 100px;
}

.child {
  padding-top: 100%;
}

Тогда высота элемента будет такой же, как высота дочернего элемента, хотя мы задали height: auto. С другой стороны, высота дочернего элемента будет такой же, как и ширина родительского элемента, поскольку мы устанавливаем padding-top: 100%. В результате получается квадрат, и элемент будет поддерживать это соотношение при любых размерах.

Вот рабочий пример:


Если измените padding-top: 100% на любой другой процент, то получится прямоугольник. Если меняете ширину, то соотношение все равно сохраняется.

Трансформация может накапливать правила


Если вы изучали информатику, то наверняка помните эту ужасную черепаху и ее двигающуюся ручку. Эта образовательная концепция более известна как черепашья графика, цель которой состоит в том, чтобы провести черепаху по пути при помощи простых инструкций — «20 шагов вперед», «поворот на 90 градусов» и тому подобное.

Что, если бы используя CSS, вы могли задать команду перемещение на «20 пикселей вправо» относительно текущего положения элемента, а не его стартовой позиции? А если я скажу, что вы можете это сделать, используя свойство transform?

Многие разработчики не знают, что свойство transform может накапливать правила и правило n+1 будет относиться к позиции, достигнутой в n-м правиле, а не к исходной позиции.

Вы растеряны? Возможно, этот пример поможет вам прийти в себя:


Обратите внимание, что мы не использовали никаких переменных JavaScript для сохранения текущей позиции или текущего вращения. Эта информация нигде не хранится! Решение простое, если напишете:

transform: translateX(20px);

А затем добавите следующее правило:

transform: translateX(20px) translateX(40px)

Второе правило не будет заменять первое — они будут применяться последовательно. Тот факт, что они применяются последовательно имеет важное значение. Когда вы поворачиваете элемент, вы изменяете систему отсчета, и дальнейшие правила будут относиться к новой системе отсчета. Таким образом, эта запись:

transform: rotateZ(20deg) translateX(30px)

будет отличаться от такой:

transform: translateX(30px) rotateZ(20deg)

Вы также можете комбинировать разные единицы измерения. Например, вы можете отцентрировать элемент размером в 600 следующим образом:

transform: translateX(50vw) translateX(-300px)

Но если вы не собираетесь его анимировать, то, возможно, calc () — лучшая альтернатива.

Если вы волнуетесь по поводу черепахи, то я создал другой фрагмент, который воссоздает динамику:


К сожалению, она пока не рисует. Но, если захотите, всегда можете реализовать функцию рисования.

Внешние и внутренние отступы отсчитываются по часовой стрелке


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

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

Позвольте дать вам подсказку:
Отступы и границы следуют по часовой стрелке

Объясню проще. Вы с уверенностью можете использовать:

padding-top: 3px;
padding-left: 6px;
padding-right: 6px;
padding-bottom: 3px;

Но точно так же вы можете использовать более короткую альтернативу:

padding: 3px 6px 3px 6px;

Порядок запомнить легко — просто посмотрите на эти часы:



Начинайте с 12:00 и продолжайте движение по часовой стрелке. Вы получите правильный порядок.

Если вместо этого вы используете только два значения:

padding: 2px 4px;

Браузер расширит его, повторив параметры:

padding: 2px 4px 2px 4px;

Если вы используете три значения:

padding: 2px 4px 6px;

Браузер будет использовать среднее значение как для левого, так и для правого края, как если бы вы написали:

padding: 2px 4px 6px 4px;

Фон поддерживает несколько изображений


Это одно из наименее известных свойств, хотя оно широко поддерживается.

Вы знаете, что можно указать URL-адрес изображения внутри свойства background, но, если необходимо, можете вставить столько изображений, сколько хотите. Все, что вам нужно сделать, это разделить их запятой:

background: url('first-image.jpeg') top left,
            url('second-image.jpeg') bottom right;

Почему это может быть полезно? Что вы думаете о Линусе Торвальдсе на фоне сгенерированного при помощи CSS восхода солнца?


Вы также можете сделать квадратным прямоугольное изображение, добавляя те затененные границы, которые так популярны в Instagram. Для этого я повторил одно и то же изображение дважды, увеличив фоновое изображение в 5 раз:


Обнаружение сенсорных устройств


Благодаря медиа-запросам мы можем сделать сайты гибкими, а макеты адаптировать к экранам различных размеров. Но этого недостаточно!

Смартфоны, планшеты и классические персональные компьютеры отличаются по своей природе. Дело не в размере экрана.

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

Вам не нужен сложный JavaScript-код для определения user-agent. Все необходимое есть в CSS:

@media (any-pointer: fine) {
  /*
    These rules will be applied to not-touchscreen devices
  */
}

@media (any-pointer: coarse) {
  /*
    These rules will be applied to touchscreen devices only
  */
}

Вот пример:


Подсказка: Для проверки вам не нужен смартфон, можете имитировать сенсорное устройство с помощью инструментов Google Chrome, просто щелкнув этот значок:



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

В конце концов, вы можете предусмотреть файл touchscreen.css и при необходимости его импортировать:

@import url('touchscreen.css') screen and (any-pointer: coarse);

Примечание: в настоящее время не поддерживается Firefox, как вы можете видеть на caniuse.com.

Отступы схлопываются



«И следите за лестницами. Они любят меняться» (Перси Уизли Гарри Поттеру)

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

Вы применяете правило, и оно работает. Но когда я думал, что знаю все о CSS, произошло вот это:


Что, черт возьми, происходит? Вероятно, вы ждете, что текст будет внутри поля заголовка, но заголовок оказался внизу. Я не хотел подобного расклада. Позже я обнаружил, что с отступами происходит путаница.

Что это значит? Предположим, мы хотим создать такой макет:



Мы создали разметку для трех элементов и установили разную высоту верхней границы для каждого из них. Вроде бы все должно работать? Нет.

Если вы так сделаете, браузер заметит три смежных поля и захочет объединить их в один большой блок.

Результат будет выглядеть так:



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

Если вы работали с CSS много лет и никогда не встречались с этой проблемой, то это потому, что отступы объединяются только когда:

  • поля вертикальны (с горизонтальными подобного не происходит);
  • внешние элементы не содержат текст или другой контент;
  • не установлены внутренние отступы или границы;
  • свойство display определено как «block»;
  • свойство overflow отличается от «initial»;
  • отступы не являются отрицательными.

И список можно продолжить. Если вы столкнулись с этой проблемой, то можете просто исключить одно из этих условий (кроме первого), и отступы придут в норму. Вы также можете избегать использования margin-top, а вместо этого использовать top и padding-top.

Обратите внимание, что это может случиться и для элементов одного уровня. Если у вас есть два родственных элемента один над другим и вы устанавливаете margin-bottom: 30px для первого и margin-top: 60px для второго, то с наименьшим будут проблемы. Отступы в результате не будут равны 30 + 60 = 90 пикселей, а будут равны наибольшему значению (30, 60) = 60 пикселей.

Финальные размышления


На этом все! Надеюсь, я не зря тратил время на статью и она оказалась полезной для вас.


Заглядывайте на VPS.today — сайт для поиска виртуальных серверов. 1500 тарифов от 130 хостеров, удобный интерфейс и большое число критериев для поиска самого лучшего виртуального сервера.

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


  1. Madeas
    08.11.2018 12:53

    Исправьте последовательность в:
    padding-top: 3px;
    padding-left: 6px;
    padding-right: 6px;
    padding-bottom: 3px;

    Не по «часам».

    И в данном случае лучше использовать не padding: 3px 6px 3px 6px;, а padding: 3px 6px . Разумеется, если стороны равнозначны

    Добавлю еще немного не в тему, для calc() на css-tricks есть еще интересное применение


  1. staticlab
    08.11.2018 13:12

    Объяснение
    Оно устанавливает параметры относительно родительской высоты.

    относительно родительской ширины


    1. RVera Автор
      08.11.2018 13:51

      Спасибо, исправлено.


  1. anttoshka
    08.11.2018 13:21

    Как минимум половина советов описывается в начальных книгах.


    1. 4tlen
      08.11.2018 23:13

      Мне сейчас натаскивать на веб нового и эта статья в тему.


  1. XAHTEP26
    08.11.2018 13:24

    Оно устанавливает параметры относительно родительской высоты. Вам нужна демонстрация?

    Не высоты, а ширины.

    Если вы так сделаете, браузер заметит три смежных поля и захочет объединить их в один большой блок.

    Результат будет выглядеть так:
    image

    Не совсем так. За отступ берется не сумма а максимальное значение из Margin 1, Margin 2 и Margin 3.

    Если вы работали с CSS много лет и никогда не встречались с этой проблемой, то это потому, что отступы объединяются только когда:
    • ...
    • свойство overflow отличается от «initial»;
    • ...


    Наоборот. Не отличается от initial, а равно initial. Или visible.


    1. XAHTEP26
      08.11.2018 14:08

      И если уж быть совсем точным, то padding-top считается не от ширины родителя, а от ширины доступного пространства. Т. е. если у родительского блока стоит box-sizing: border-box; и есть padding или border, то их размеры вычитаются из той ширины от которой считается padding-top и т. п.


      1. Aingis
        08.11.2018 14:12
        +1

        Нет. Если вы возьмёте один элемент из нескольких в ряду внутри флекс-контейнера (или гридов), то обнаружите, что размер будет считаться от ширины родителя, а не «доступного пространства», которое ещё было непонятно как считать, если пришлось бы учитывать такие вещи. Но да, эта ширина считается по content-box, то есть по внутренней стороне padding (все помнят блочную модель?), так же как и при стандартные объявления вроде width: 100%.


        1. XAHTEP26
          09.11.2018 09:11

          Спасибо. content-box это в моем понимании и есть «доступное пространство», просто не знал как его правильно обозвать.


  1. aPiks
    08.11.2018 13:44

    Или перевод так-себе, или автор так-себе. Много ошибок в статье.


  1. stayacid
    08.11.2018 13:45

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

    Может все-таки ширины? И, кстати, почему только паддинг? Маргин в процентах тоже считается от ширины родительского контейнера


  1. mishast
    08.11.2018 14:30

    Про схлопывание конечно… нет приличных слов, сам по этим граблям ходил


  1. transcengopher
    08.11.2018 15:54

    «Трюк» с padding-top звучит как использование Undefined Behavior, особенно учитывая что в спецификации ничего про это нет (согласно данной статье). Я бы, в таком случае, воздержался от использования этого в проде, иначе есть риск нарваться на «багфикс», который добавит разъяснение в спецификации, и сделает

    padding-top: x%
    зависимым от высоты, а не ширины, во имя снижения количества неожиданностей в обработке.


    1. staticlab
      08.11.2018 17:57
      +2

      Всё там есть:


      The percentage is calculated with respect to the width of the generated box's containing block, even for 'padding-top' and 'padding-bottom'. If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1.

      Даже подчёркивают, что рассчитывается относительно ширины даже для вертикальных паддингов.


    1. selvaoscura
      09.11.2018 00:38

      В спецификации как раз и сказано от чего считается padding в процентах: https://www.w3.org/TR/CSS2/box.html#propdef-padding-top

      Percentages: refer to width of containing block


  1. timfcsm
    09.11.2018 00:38

    интересно, что за руководства такие читал автор, что они его не научили таким базовым вещам… всё что тут описано будет новостью только для тех кто неделю назад не знал что такое css и есть в любой мало-мальски адекватной книжке или справочнике


  1. evgenWebm
    09.11.2018 16:38

    Стараюсь всегда использовать такой вариант написания
    padding-top: 0px;
    padding-left: 0px;
    padding-right: 0px;
    padding-bottom: 0px;
    Вариант, padding: 0 0 0 0; не столь интуитивно понятен. Хотя никогда не было проблем с написанием его.
    Если с padding еще ладно, это не критично. То всякие бэкграунды и тп, пишу только отдельными свойствами. Я когда вижу правило записанное в одну строку, но при этом имеет длину книги война и мир, хочется лично разбить такому писателю.
    Конечно имхо и на истину не претендую. Просто считаю, что читать правила так легче и понятней. А не когда сначала надо строку распарсить в уме, чтобы увидеть что там написано.


    1. AndrewTishkin
      09.11.2018 21:37

      А каким инструментарием можно вообще развернуть краткий CSS в полный и наоборот? Чтобы копья не ломать.

      Сокращают, вероятно, минификаторы…


      1. 4tlen
        09.11.2018 23:50

        Скорее всего копать в сторону css shortcat expanded плагинов для вашей IDE