Бесконечная заставка с пинг-понгом

Бесконечная заставка с пинг-понгом

Ещё один способ работать с элементами, не зная их id

Во всех наших прошлых проектах с пинг-понгом мы использовали JavaScript, чтобы управлять платформами и шариком. Но можно обойтись и без него — и написать всё на чистом CSS. Играть, правда, пока не получится, зато выглядит классно. 

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

Бесконечная заставка с пинг-понгом

Что делаем

Страничку, на которой бесконечно движутся платформы и отбивают шарики — заодно попрактикуемся в CSS. Можно просто расслабиться и посмотреть на идеальные синхронные отбивания. Глупость, но приятно.

Готовим страницу

Всё, что нам нужно сделать, — подготовить область и нарисовать в ней две платформы и два круга:

<!DOCTYPE html>
<html lang="ru" >
<head>
  <meta charset="UTF-8">
  <title>Заставка с пинг-понгом</title>
  <!-- подключаем файл со стилями -->
  <link rel="stylesheet" href="style.css">

</head>
<body>
  <!-- указываем внутренние размеры графического контейнера, чтобы привязать к ним все элементы -->
  <svg viewBox="0 0 100 75">
    <!-- рисуем левую и правую платформы -->
    <path d="m2,0 v15" />
    <path d="m98,0 v15" />
    <!-- рисуем оба круга на одном и том же месте -->
    <circle cx="50" cy="68" r="5" />
    <circle cx="50" cy="68" r="5" />
  </svg>
</body>
</html>

Первый элемент на странице, который требует подробного пояснения — это блок <svg> с параметром viewBox. Работает так:

  1. Пишем параметр <svg viewBox="0 0 100 75">
  2. В этом параметре указаны 4 числа.
  3. Первые два числа — координаты левого верхнего угла, а вторые два — координаты правого нижнего угла.
  4. Эта система координат будет использоваться для всех элементов внутри блока <svg>.
  5. Это значит, что круг с координатами (50, 37) будет находиться ровно по центру этого блока, потому что координаты привязаны к значениям из п. 2.

Внутри этого блока нарисуем две платформы, например, так:

<path d="m2,0 v15">

А вот как это работает:

  1. <path> рисует какое-то векторное изображение по правилам, которые описаны внутри тега.
  2. d — отвечает за параметры рисования, которые в нём указаны.
  3. m2,0 — перемещает виртуальный карандаш к точке с координатами (2,0).
  4. v15 — рисует вертикальную линию вниз на указанное число.

С кругами всё проще: мы указываем только центр и радиус. То, что мы рисуем два круга в одном и том же месте — не опечатка. В стилях мы их разведём.

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

Настраиваем внешний вид элементов

Чтобы всё выглядело эффектнее, сделаем тёмный фон и расположим область рисования по центру страницы:

/* общие настройки для всей страницы */
body {
  background: #16161c;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

Теперь настроим параметры самой области рисования:

/* задаём размеры области рисования SVG-элементов */
svg {
  /* ширина и высота привязана к размерам экрана */
  width: 100vmin;
  height: 75vmin;
  /* убираем обводку у области рисования */
  border: 0px dotted #f3f9f4;
  position: absolute;
  /* ставим тёмный фон */
  background: #ffffff02;
}

Здесь же укажем толщину линии для рисования фигур и её цвет. У нас виртуальные размеры области рисования — 100 на 75 пикселей, поэтому линия из четырёх пикселей получается толстой:

/* общие параметры рисования платформы и кругов */
path,
circle {
  stroke: #f3f9f4;
  stroke-width: 4px;
  fill: none;
}
Бесконечная заставка с пинг-понгом
Появились платформы и красивый круг

Добавляем анимацию

Обычно мы добавляем к каждому элементу на странице параметр id, чтобы можно было отличать его от остальных элементов. Но есть и другой способ: использовать псевдокласс :nth-of-type, например:

path:nth-of-type(2) {
animation-delay: -1875ms;
}

Работает так:

  1. Число в скобках — порядковый номер элемента такого типа среди других таких же элементов.
  2. Нумерация начинается с единицы.
  3. В каком порядке мы описывали элементы на странице — в таком порядке они и создаются.
  4. Получается, path:nth-of-type(2) позволит нам обратиться ко второму элементу path на странице, то есть ко второй платформе. 

Чтобы не делать одинаковое время запуска анимации для правой платформы и её круга, установим задержку анимации для этих элементов:

/* ставим задержку начала анимации для второго круга и платформы */
circle:nth-of-type(2) {
  animation-delay: -2500ms;
}
path:nth-of-type(2) {
  animation-delay: -1875ms;
}

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

/* общая настройка анимации кругов */
circle {
  /* устанавливаем бесконечную анимацию длительностью 5 секунд с постоянной скоростью, а раскадровку анимации берём из параметра circleAnimation */
  animation: circleAnimation 5000ms infinite linear;
}

/* общая настройка анимации платформ */
path {
  /* отдельно указываем вторым параметром время сдвига начала второй платформы */
  /* также указываем, что анимация бесконечная, на каждом следующем цикле анимации фигура должна двигаться в обратном направлении, а начало и конец анимации должны быть плавными */
  animation: paddleAnimation 1250ms -625ms infinite alternate ease-in-out;
}

Прописываем раскадровку

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

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

/* раскадровка анимации кругов */
@keyframes circleAnimation {
  25% {
    transform: translate(-39px, -30.5px);
  }
  50% {
    transform: translate(0px, -61px);
  }
  75% {
    transform: translate(39px, -30.5px);
  }
}

/* раскадровка анимации платформы */
@keyframes paddleAnimation {
  100% {
    transform: translateY(60px);
  }
}

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

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

<!DOCTYPE html>
<html lang="ru" >
<head>
  <meta charset="UTF-8">
  <title>Заставка с пинг-понгом</title>
  <!-- подключаем файл со стилями -->
  <link rel="stylesheet" href="style.css">

</head>
<body>
  <!-- указываем внутренние размеры графического контейнера, чтобы привязать к ним все элементы -->
  <svg viewBox="0 0 100 75">
    <!-- рисуем левую и правую платформы -->
    <path d="m2,0 v15" />
    <path d="m98,0 v15" />
    <!-- рисуем оба круга на одном и том же месте -->
    <circle cx="50" cy="68" r="5" />
    <circle cx="50" cy="68" r="5" />
  </svg>
</body>
</html>

/* общие настройки для всей страницы */
body {
  background: #16161c;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* задаём размеры области рисования SVG-элементов */
svg {
  /* ширина и высота привязана к размерам экрана */
  width: 100vmin;
  height: 75vmin;
  /* убираем обводку у области рисования */
  border: 0px dotted #f3f9f4;
  position: absolute;
  /* ставим тёмный фон */
  background: #ffffff02;
}

/* общие параметры рисования платформы и кругов */
path,
circle {
  stroke: #f3f9f4;
  stroke-width: 4px;
  fill: none;
}

/* ставим задержку начала анимации для второго круга и платформы */
circle:nth-of-type(2) {
  animation-delay: -2500ms;
}
path:nth-of-type(2) {
  animation-delay: -1875ms;
}

/* общая настройка анимации кругов  */
circle {
  /* устанавливаем бесконечную анимацию длительностью 5 секунд с постоянной скоростью, а раскадровку анимации берём из параметра circleAnimation */
  animation: circleAnimation 5000ms infinite linear;
}

/* общая настройка анимации платформ */
path {
  /* отдельно указываем вторым параметром время сдвига начала второй платформы */
  /* также указываем, что анимация бесконечная, на каждом следующем цикле анимации фигура должна двигаться в обратном направлении, а начало и конец анимации должны быть плавными */
  animation: paddleAnimation 1250ms -625ms infinite alternate ease-in-out;
}

/* раскадровка анимации кругов */
@keyframes circleAnimation {
  25% {
    transform: translate(-39px, -30.5px);
  }
  50% {
    transform: translate(0px, -61px);
  }
  75% {
    transform: translate(39px, -30.5px);
  }
}

/* раскадровка анимации платформы */
@keyframes paddleAnimation {
  100% {
    transform: translateY(60px);
  }
}

Текст:

Михаил Полянин

Редактор:

Максим Ильяхов

Художник:

Даня Берковский

Корректор:

Ирина Михеева

Вёрстка:

Кирилл Климентьев

Соцсети:

Виталий Вебер

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства и компенсация, если вы пойдёте работать в «Яндекс».
Начать карьеру в ИТ
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
medium