Сбер вакансии Backend
Сбер вакансии Backend
Сбер вакансии Backend
Написать пост

Создаём Солнечную систему на чистом CSS3. Часть вторая. Кейфреймы и тени

Отредактировано

11К открытий11К показов
Создаём Солнечную систему на чистом CSS3. Часть вторая. Кейфреймы и тени

В этой статье мы продолжим разбираться в принципах создания анимированной Солнечной системы на CSS3. Мы рассмотрим использование keyframe-анимации для движения планет по орбитам вокруг Солнца и реализуем динамические тени на планетах. 

Вот на чем мы остановились в первой части: мы создали HTML-файл с единственным элементом и написали CSS-код для добавления звёздного фона и симуляции солнечного света:

			<html>
  <head>
    <link rel="stylesheet" href="solar.css"/>
  </head>
  <body>
    <div id="universe">
    </div>
  </body>
</html>
		

Добавляем Солнце

Прежде чем мы добавим в нашу вселенную какие-либо элементы, мы должны ввести подходящую систему координат. <div> нашей вселенной был прикреплён к элементу <body> через абсолютное позиционирование, но мы хотим, чтобы внутри вселенной позиционирование было относительным. Для этого добавим новый <div> с относительным позиционированием:

			<div id="universe">
  <div id="galaxy">
  </div>
</div>
		

Вот необходимый CSS-код:

			#galaxy {
  position: relative;
  width: 100%;
  height: 100%;
}
		

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

Давайте добавим элемент <div> для Солнца в центр галактики. Солнце должно быть круглым, поэтому мы превратим прямоугольный <div> в круглый. Это можно сделать, установив border-radius в 50%, что превратит любой квадрат в круг. Зададим размер 30×30 пикселей, и используем отступы для размещения строго по центру экрана. Мы также раскрасим Солнце и добавим приятную жёлтую тень блока для сияния.

			#sun {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 30px;
  height: 30px;
  margin-top: -15px;
  margin-left: -15px;
  border-radius: 50%;
  background-color: #FB7209;
  box-shadow: 0 0 60px rgba(255, 160, 60, 0.4);
  z-index: 1;
}
		

Какое-то маленькое солнце, давайте увеличим длину и ширину. Но работать в пикселях — плохая идея, ведь размеры экранов отличаются. Вместо этого будем задавать размеры в em’ах: они соотносятся со стандартным размером текста в браузере, и с масштабированием проблем не возникнет. Что ещё более важно, все абсолютные величины (размеры, отступы, границы и т.п.) можно задавать в em’ах, и поэтому все их можно масштабировать одновременно, используя font-size. Если у нас есть это:

			#sun {
  width: 1em;
  height: 1em;
  margin-top: -.5em;
  margin-left: -.5em;
  ...
}
		

… и мы добавим это:

			#sun {
  font-size: 24em;
}
		

… то все размеры #sun, выраженные в em’ах, умножатся на 24. Кроме того, увеличатся и отступы, то есть Солнце останется в центре экрана!

Одноцветное солнце выглядит не очень, поэтому мы добавим прозрачное PNG-изображение с текстурой:

Создаём Солнечную систему на чистом CSS3. Часть вторая. Кейфреймы и тени 1

Для помещения изображения поверх солнца снова воспользуемся правилом background-size:

			#sun {
  ...
  background-repeat: no-repeat;
  background-size: cover;
  background-image: url(data:image/png;base64,iVBORw0KG...AAASUVORK5CYII=);
}
		

Вот результат:

Добавляем планету на орбите, используя кейфреймы

Сейчас мы рассмотрим ещё одну фичу CSS3 — keyframe-анимацию, или кейфреймы. Они используются для плавного изменения CSS-свойств с течением времени. Например, если вы хотите, чтобы элемент класса myelement постепенно исчезал, вам стоит написать такой код:

			.myelement {
  animation: 'fader' 2s linear;
}

@keyframes fader {
  0%   { opacity: 1; }
  50%  { opacity: 0; }
  100% { opacity: 1; }
}
		

Сперва утверждение @keyframes используется для создания анимации с уникальным именем fader. Внутри блока keyframes мы создаём три кейфрейма: полная непрозрачность (на 0%, в начале анимации), полная прозрачность (на 50%, в середине анимации) и полная непрозрачность в конце. Непрозрачность — лишь одно из свойств, которые можно анимировать; в дальнейшем мы будем анимировать местоположение и вращение.

Для использования анимации достаточно добавить к определению класса правило animation. Вы задаёте имя анимации, её длительность и временную функцию. мы использовали linear, но можно использовать ease, ease-in или ease-out для ускорения анимации на различных этапах. Подробнее об этом можно почитать здесь.

Также ничего не мешает разделить все свойства анимации. Поскольку планет будет много, имеет смысл написать следующее:

			.myelement {
  animation-name: orbit;
  animiation-duration: 2s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
		

Мы используем animation-iteration-count для создания бесконечного анимационного цикла. Ключевое слово infinite можно добавить и к сокращённому виду записи.

Помните, что в общем случае нужно добавлять и варианты с префиксами: -webkit-animation, -moz-animation и -o-animation — но поскольку мы используем PrefixTree, это нам не нужно.

Поскольку все планеты нашей системы вращаются вокруг Солнца одинаково (меняется лишь диаметр орбиты), мы можем создать общий класс для планеты. Какие-то свойства совпадают и с Солнцем, поэтому упростим:

			#sun, .planet {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1em;
  height: 1em;
  margin-top: -0.5em;
  margin-left: -0.5em;
  border-radius: 50%;
}

#sun {
  background-color: #FB7209;
  background-repeat: no-repeat;
  background-size: cover;
  box-shadow: 0 0 60px rgba(255, 160, 60, 0.4);
}

.planet {
  background-color: #202020;
  background-repeat: no-repeat;
  background-size: cover;
}
		

Добавим планету в наш HTML:

			<div id="sun">
</div>
<div id="mercury" class="planet">
</div>
		

Эта работает, но планета сейчас расположена поверх Солнца, в центре. Прежде чем запустить её движение, нам нужно задать орбиту, поэтому изменим HTML так:

			<div id="sun">
</div>
<div id="mercury" class="orbit">
  <div class="planet"></div>
</div>
		

Теперь у нас есть связка орбита-планета, одинаковая для всех планет. Дадим нашей планете идентификатор #mercury, чтобы мы могли добавить её уникальные свойства. Сперва нарисуем орбиту: дадим ей тонкую, полупрозрачную границу и сделаем её круглой. Для орбиты Меркурия зададим размер 12em.

			.orbit {
  position: absolute;
  top: 50%;
  left: 50%;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
}
#mercury.orbit {
  width: 12em;
  height: 12em;
  margin-top: -6em;
  margin-left: -6em;
}
		

Орбита нарисована, но Меркурий всё ещё сидит поверх Солнца. Исправим это, задав планете отступ относительно орбиты:

			#mercury .planet {
  left: 0%;
  top: 50%;
}
		

Это поместит Меркурий слева от Солнца, на линию орбиты.

Настало время запустить вращение планеты! Провернём такой трюк: будем вращать не планету, а орбиту. Поскольку планета находится в системе координат орбиты, она будет вращаться вместе с орбитой. Создадим кейфреймы для орбит с использованием преобразований. Это новая функция CSS3: вы можете не только анимировать значения свойств, но и преобразовывать элементы, отражая, масштабируя или вращая их. В нашем случае мы зададим вращение относительно оси Z от 0 до 360 градусов.

			@keyframes orbit {
  0%   { transform: rotateZ(0deg); }
  100% { transform: rotateZ(-360deg); }
}
		

Задав анимацию, мы можем применить её к классу орбит:

			.orbit {
  ...
  animation-name: orbit;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}
		

Определим длительность анимации для Меркурия:

			#mercury.orbit {
  animation-duration: 3s;
}
		

Вот и всё. Меркурий плавно вращается вокруг Солнца, и мы всё ещё не воспользовались JavaScript. Чистый CSS:

Добавляем движущуюся тень на планете, используя анимации и тени блока

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

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

			.planet {
  ...
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}

#mercury .planet {
  animation-name: shadow-mercury;
  animation-duration: 3s;
}
		

Мы указали, что анимация планет будет зациклена, а у Меркурия она будет называться shadow-mercury. Определим её:

			@keyframes shadow-mercury {
  0%     { box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.5); /* top */ }
  25%    { box-shadow: inset 16px 0 8px rgba(0, 0, 0, 0.5); /* left */ }
  50%    { box-shadow: inset 40px -20px 16px rgba(0, 0, 0, 0.5); /* bottom */ }
  50.01% { box-shadow: inset -40px -20px 16px rgba(0, 0, 0, 0.5); /* bottom */ }
  75%    { box-shadow: inset -16px 0 8px rgba(0, 0, 0, 0.5); /* right */ }
  100%   { box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.5); /* top */ }
}
		

Внутренние тени используются для отбрасывания теней на планету. Поскольку планеты круглые, тени должны быть такими же. В начале анимации планета находится за Солнцем и полностью освещена. На 50% она полностью в тени. Когда планета проходит перед Солнцем, мы должны переключить анимацию, что мы и делаем на 50.01%. Также заметьте, что на 100% тень должна быть в точности такой же, как и на 0%, для корректного вычисления затенения.

Здесь мы намеренно сделали тень более заметной, чем в оригинальной демке:

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

Следите за новыми постами
Следите за новыми постами по любимым темам
11К открытий11К показов