Веб-разработка
May 28

Позиционирование и двумерные трансформации — Тренажёр HTML Academy

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

Этот блок и, как я понимаю, последующие блоки по HTML/CSS идут уже без какой-то сквозной темы. То есть мы начинаем пылесосить нюансы или отдельные фишки, функции. Там недалеко уже и «Продвинутый уровень», где уже совсем тонкости. Правда, тут еще два монструозных блока по JavaScript надо преодолеть, но все по порядку.

Так как нет сквозной темы, то и как-то переформатировать части не получится. Да и не особо уже хочется, особенно после предыдущих частей про построение сеток. На форматировался пока! Поэтому буду конспектировать в указанном в тренажёре порядке. Кстати, почему-то с этой части пропали «Конспекты».

Позиционирование

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

По умолчанию все элементы находятся в потоке, согласно стандартной блочной модели, и их значение position: static; — статично. Это обычно опускается, но именно благодаря значению по умолчанию для меня стала понятна логика этого свойства.

Позиция статична static относительно чего? Относительно своего положения в потоке. При работе со свойством position, да и не только, стоит отделять сам бокс элемента от его положения — это две сущности. Можно представить, что у каждого элемента есть два слоя — видимый бокс и невидимый, но занимающий место под ним.

И как раз значение static фиксирует их вместе — бокс занимает место в соответствии с видимыми размерами. Так и работает вся блочная система, это просто и логично. Остальные же значения свойства position меняют это поведение.

Относительное позиционирование relative

Значение relative отделяет «видимый» бокс от его занимаемого места или положения в потоке и позволяет управлять позицией относительно него. Это и называется относительным позиционированием. При этом занимаемая место область остается на месте, двигается только видимая.

Мы можем смещать бокс в стороны с помощью свойств top, bottom, left, right, которые работает только с позиционируемыми элементами и для режима относительного позиционирования работают как интервалы от края бокса до края занимаемой области с указанной стороны.

bottom: 20px; right: 10px;

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

Абсолютное позиционирование absolute

Совсем иначе работает другой режим — абсолютное позиционирование, которое задается значением position: absolute;. При этом режиме позиционирования элемент полностью выпадает из потока — занимаемое место пропадает.

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

Кстати, свойство position: absolute; имеет приоритет над свойством float и при одновременном указании этих свойств float игнорируется.

Также при установке абсолютного позиционирования любому элементу присваивается свойство блочного бокса display: block;, даже если изначально это был строчный элемент. Поэтому любым абсолютно позиционированным элементам можно задать размерные свойства width и height.

Итак, занимаемого места у нас нет, элемент выпал из потока. По умолчанию, если не задавать свойств позиционирования top, bottom, left и right, элемент останется на месте, но сожмётся до размера содержимого.

Для position: absolite; свойства позиционирования работают иначе. Эти свойства работают как интервалы от границы бокса до границы документа или до ближайшего родителя с относительным позиционированием relative.

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

Это не viewport — окно браузера, и не исходный родитель <body> или <html>, это именно какая-то внешняя граница документа. Я даже проверил поигравшись с позиционированием и margin'ами для всех тегов.

Фиксированное fixed и липкое sticky позиционирование

Следующее значение свойства position: fixed; похоже на абсолютное, но отвечает за позиционирование, как раз, относительно окна браузера viewport.

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

С помощью позиционных свойств top, left и др. можно задать расположение элемента относительно краёв экрана. Например, с помощью этих свойств я видел реализацию поп-ап элементов.

В тренажёре его почему-то не рассмотрели, возможно позже, но куда более интересным является «липкое» позиционирование position: sticky;.

Это своего рода гибрид относительного позиционирования relative и фиксированного fixed. Такой элемент фиксируется на экране в рамках своего родительского элемента на позиции заданной с помощью позиционных свойств.

Например, какому-то блоку на странице задано:

.sticky-box {
  position: sticky;
  top: 10px;
}

До момента попадания блока на позицию 10px от верха экрана он будет сохранять свойства относительного позиционирования relative. Но как только прокрутка опустится ниже — элемент прикрепится к верху экрана и будет находится там, пока родительский элемент липкого бокса помещается в экран.

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

В тренажёре в этой части еще раз упомянуто и разобрано свойство z-index, отвечающее за слои или «плановость» элементов. Честно, не знаю как это назвать. Мы уже разбирали это свойство и ничего нового в этой части не написано, поэтому опустим.

Испытание

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

Двумерные трансформации

Часть почти полностью посвящена свойству transform отвечающего за какую-либо, собственно, трансформацию элемента. Оно позволяет перемещать, крутить, наклонять и много чего еще, но мы рассмотрим только простейшие варианты.

Отмечу, что половина этой части сделана очень круто в виде игры — трансформируем бедного Пендальфа Синего, кидаемся фаерболами и зачищаем подземелье от монстров. И ребусы разгадываем!

Во второй половине уже делаем на реальных примерах — интерактивные кнопки, иконки и круговое меню. Менее увлекательно, но тоже интересно.

Базовые функции трансформации

Итак, первым заклинанием из фолианта трансформации transform Пендальфа мы рассмотрим функцию перемещения translate(x, y). Она принимает два аргумента — смещение по горизонтали X и по вертикали Y:

.move-block {
  transform: translate(10px, 20px);
  /* переместит на 10px вправо и 20px вниз */
}

Отрицательные значения перемещают элемент в обратную сторону, то есть по оси X влево, а по оси Y вверх. В тренажёре повествование начали с них, я про них просто упомяну — для каждой из осей есть своя отдельная функция:

.move-block-x {
  transform: translateX(-50px); /* 50px влево */
}

.move-block-y {
  transform: translateY(-10px); /* 10px вверх */
}

С помощью этого заклинания Пендальф поразил мишень фаерболом:


Следующее заклинание Пендальфа — это функция поворота объекта rotate(), которая принимает одно числовое значение в единицах deg обозначающие градус поворота:

.roll-block {
  transform: rotate(30deg);
}

Положительные значения поворачивают объект по часовой стрелке, а отрицательные против часовой.

Нюанс при использовании функции поворота — элемент поворачивается не только визуально, но с ним поворачивается и его система координат, что влияет на функцию перемещения translate():

При одновременном использовании этих функции можно легко запутаться, поэтому желательно заранее продумать — что в итоге нужно сделать с элементом.

С помощью изученных двух заклинаний Пендальф восстановил упавший частокол в городе и отразил нападение волков:


Следующее на очереди заклинание — функция изменения размера scale(). Она принимает числовые значения множителей размера объекта:

.big-block {
  transform: scale(2); /* увеличит в 2 раза */
}
.small-block {
  transform: scale(0.5); /* уменьшит или в 2 раза */
}
.zero-block {
  transform: scale(0); /* гипермассивная точка в пространстве */
}
.normal-block {
  transform: scale(1); /* базовое значение */
}

Функция умеет принимать два значения scale(x, y) и, как и в функции перемещения, они отвечают за размер по горизонтали X и по вертикали Y. Также имеются аналогичные отдельные функции scaleX() и scaleY():

.fat-block {
  transform: scale(2, 0); /* растянет по горизонтали в 2 раза */
}
.thin-block {
  transform: scaleY(2); /* растянет по вертикали или в 2 раза */
}

С помощью уменьшающего заклинания Пендальф смог проникнуть в подземелье через потайной ход:

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


Последними заклинаниями в фолианте трансформация transform у Пендальфа указаны заклинания функций наклона skewX() и skewY(). Они принимают числовое значение градусах deg и отвечают за наклон элемента вдоль своей оси. Здесь уместнее показать картинкой:

Скеу-скеу-скеу.

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

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

Лут забрал Пендальф!

Я думаю, всем понятно, что мне очень понравился такой подход в виде РПГ. Конечно, все задания так не сделаешь, но хотелось бы.

Итак, основные заклинания изучили. Их на самом деле там целая библиотека CSS-магии, но их мы рассмотрим позже. Либо в блоке тренажёра про анимацию, который будет в «Продвинутом уровне», либо уже отдельно где-то еще.

Точка отсчета transform-origin

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

Функции трансформации работают с точкой отсчета, которая по умолчанию находится по центру элемента. Именно эту точку мы перемещаем с помощью translate() и вокруг неё крутим элемент с помощью rotate().

За расположение этой точки относительно бокса элемента отвечает свойство transform-origin. Свойство принимает два значения — расположение точки по горизонтали и по вертикали. Оно принимает как размерные значения, например в пикселях px, процентах %, так и ключевые слова top, left, right, bottom и center.

Как уже написал, по умолчанию точка находится в центре и свойство имеет значение transform-origin: 50% 50%;. С координатами точки отсчета работает такая же система координат, что и с позиционированием:

.top-left-anchor {
  transform-orign: 0 0;
  /* эквивалент */
  transform-orign: top left;
}
.bottom-righ-anchor {
  transform-orign: 100% 100%;
  /* эквивалент */
  transform-orign: bottom right;
}

Только теперь «позиционируется» точка отсчёта в боксе элемента, а не сам элемент в документе.

Для тех, кто работал в графических редакторах типа Photoshop есть супер простой способ понять что такое точка отсчета элемента. У каждого объекта при свободной трансформации Ctrl+T тоже появляется точка отсчета, которая там называется anchor-point. Это по своей сути тоже самое что и transform-origin.

Остальная часть тренажёра посвящена как раз тренировке использования этого свойства в комбинации с функциями трансформации. А также примеры использования трансформаций на кнопках и, внезапно, игральных картах.

На кнопках, кстати, применяется свойство transition, о нем мы точно поговорим в блоке «Динамические эффекты», а пока нам его кинули на затравку, мол «Смотрите как можно красиво сделать!», но без детального рассмотрения.

Отдельно упомяну прикольный приём создания нестандартной тени:

Два элемента с тенью, оба повёрнуты на 3/-3 градуса и помещены под белый через z-index.

Получается реалистичный эффект листа бумаги, который немного выгибается по краям. Я, честно признаюсь, делал этот эффект через .png и был приятно удивлён такому интересному подходу.

Испытания

Испытания целых три — два с Пендальфом и одно в самом конце уже без Пендальфа. К тому моменту он ушел на пенсию.

Первое испытание в основном на rotate (). Пендальф нашел разорванную карту сокровищ и нам нужно её собрать перемещая и поворачивая куски:

Второе испытание сразу на все функции — из босса выпал какой-то кристалл и раскололся, а мы с Пендальфом его собираем воедино:

Опять, правда, подбор циферок, но тут не так сложно. Главное идти от верхних элементов к нижним.

Третье испытание с игральными картами. Привет, «Селекторы». Правда, в этот раз попроще — надо просто повернуть и переместить карты. На самом деле, слишком простое испытание для последнего в части.


Наконец-то в тренажёрах мы дошли до трансформаций и скоро будут анимации. Я еще по курсу в мобильном приложении понял, что мне максимально нравится именно эта тема!

Огромное вам спасибо за внимание!

Ссылки на предыдущие статьи по HTML Academy:

Знакомство с Веб-разработкой
Знакомство с HTML и CSS
Знакомство с JavaScript
Знакомство с PHP
Таблицы и подробно о формах
Наследование, каскады и селекторы
Блочная модель, поток и сетка на float
Гибкие флексбоксы display: flex
Удобные сетки на гридах display: grid
Пропуск блока «Погружение»
Позиционирование и двумерные трансформации <- Вы здесь
Теневое искусство и линейные градиенты
CSS-фильтры и Кекстаграм
Мастерские
Продвинутые Мастерские
...

Остальные статьи можно посмотреть у меня на главной странице блога.

Также мои соц. сетки, которые я продолжаю вести:

Мой Twitter
Мой Telegram
Мой Паблик ВК

Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!