Перемещения и трансформации в CSS3. Плавная анимация объектов только с помощью CSS (5 примеров)

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

Анимация на CSS3 с помощью transition

В своих проектах я много раз обращалась к CSS-свойству transition . С его помощью можно создать примитивные симпатичные анимации. Обычно применяю его для hover-ов, ведь времена, когда абсолютно всё выделялось подчеркиванием при наведении, прошли еще до того, как я увлеклась Веб-дизайном.

Свойство transition ответственно за параметры анимации, такие как: изменяемое CSS-свойство объекта, длительность анимационного перехода, функция времени, задержка анимации.

transition : свойство скорость_анимации временная_функция задержка

Самый банальный вариант анимации на CSS3 - преобразование цвета блока при наведении. Посмотрим как это получится transition и без него:

Используя transition. (Цвет фона меняется плавно.)

With_transition { background :#efefef; -webkit-transition : background 1s linear 0s ; -moz-transition : background 1s linear 0s ; -o-transition : background 1s linear 0s ; transition : background 1s linear 0s ; } .with_transition:hover { background :#F9FF66; }

Без transition. (Цвета заменяют друг друга мгновенно.)

Without_transition { background :#efefef ; } .without_transition:hover { background :#91FF66 ; }

Свойство transition простое и понятное. Хочу только остановиться на одном из его параметров - временной функции. Эта функция задается с помощью кривой Безье (cubic-bezier ), которая принимает 4 значения (x1,y1,x2,y2) - координаты направляющих точек.

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

.over { -webkit-transition : ; -moz-transition : left 1s cubic-bezier(0,.99,.98,.02) 0s ; -o-transition : left 1s cubic-bezier(0,.99,.98,.02) 0s ; transition : left 1s cubic-bezier(0,.99,.98,.02) 0s ; left :0px ; } .kot-krol:hover .over{ left:325px ; }

Трансформация на CSS3 (transform)

Анимация на сайтах выглядит круто, даже если это обычное изменение фона или положения объекта. Но намного эффектнее будет применить трансформацию. Для нее в CSS3 существует свойство transform и несколько значений, которые оно может принять. Ниже рассмотрю все возможные:

Например, используем поворот transform : rotate(<угол>) :

.orange img, .kiwi img, .apricot img { -webkit-transition : all 0.5s linear 0s ; -moz-transition : all 0.5s linear 0s ; -o-transition : all 0.5s linear 0s ; transition : all 0.5s linear 0s ; } .orange:hover img, .kiwi:hover img, .apricot:hover img { -webkit-transform : rotate(360deg) ; -moz-transform : rotate(360deg) ; -ms-transform : rotate(360deg) ; -o-transform : rotate(360deg) ; transform : rotate(360deg) ; }

Или же смещение transform : translate(x, y) :

.translate img { -webkit-transition :all 1.5s ease-in 0s ; -moz-transition : all 1.5s ease-in 0s ; -o-transition : all 1.5s ease-in 0s ; transition : all 1.5s ease-in 0s ; } .translate:hover img { -webkit-transform : translate(300px) ; -moz-transform : translate(300px) ; -ms-transform : translate(300px) ; -o-transform : translate(300px) ; transform : translate(300px) ; }

Также можно применить масштаб transform : scale(x, y) :

.scale img { -webkit-transition : all 1.5s linear 0s ; -moz-transition : all 1.5s linear 0s ; -o-transition : all 1.5s linear 0s ; transition : all 1.5s linear 0s ; } .scale:hover img { -webkit-transform : scale(1.4) ; -moz-transform : scale(1.4) ; -ms-transform : scale(1.4) ; -o-transform : scale(1.4) ; transform : scale(1.4) ; }

И еще наклон transform : skewX[Y](<угол>) :

.skew { -webkit-transition : all 1.5s linear 0s ; -moz-transition : all 1.5s linear 0s ; -o-transition : all 1.5s linear 0s ; transition : all 1.5s linear 0s ; } .skew:hover { -webkit-transform : skew(-30deg) ; -moz-transform : skew(-30deg) ; -ms-transform : skew(-30deg) ; -o-transform : skew(-30deg) ; transform : skew(-30deg) ; }

Более сложные трюки с анимацией на CSS3 (animation, @keyframes)

Все это помогает быстро и просто сделать интересный дизайн. Казалось бы, чего еще желать? Но я столкнулась с проблемой, с которой не удалось справится лишь CSS-свойствами transform и transition .

Речь идет о следующем: хотелось на некотором сайте сделать один блок постоянно вращающимся. Конечно, первая мысль - написать пару строчек на JavaScript, но до сегодняшнего дня меня успели убедить в том, что такой подход неправильный и даже некрутой! Пришлось искать другие пути.

Итак, я узнала о CSS-свойствах animation и @keyframes . Действительно очень полезная для анимации на CSS3 штука!

Два вышеупомянуых свойства функционируют вместе. animation задает параметры анимации (продолжительность анимации, временную функцию, задержку, количество итераций). Последнее представляло для меня особый интерес.

@keyframes , в свою очередь, вмещает разные состояния анимируемого элемента, как бы точки отсчета. Первым параметром animation принимает имя @keyframes . Выглядит это, примерно, вот так:

.kot { -webkit-animation : rotating 30s infinite linear ; -moz-animation : rotating 30s infinite linear ; -ms-animation : rotating 30s infinite linear ; -o-animation : rotating 30s infinite linear ; animation : rotating 30s infinite linear ; } @-webkit-keyframes rotating { to { -webkit-transform : rotate(360deg); } } @-moz-keyframes rotating { to { -moz-transform : rotate(360deg); } } @-ms-keyframes rotating { to { -ms-transform : rotate(360deg) ; } } @-o-keyframes rotating { to { -o-transform : rotate(360deg) ; } } @keyframes rotating { to { transform : rotate(360deg) ; } }

Для моей задачи - постоянно вращающийся блок на CSS3 - хватило задать только конечное положение элемента (to). Но в @keyframes можно задавать и начальное положение (from), и любые промежуточные в процентах. Это пригодится для создания более сложных анимаций.

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

Перемещение может быть немного сумасшедшим, как это:

Перемещение может быть и не таким явным. Например, таким, которое возникает при наведении курсора мыши на один из квадратов на рисунке ниже:

Your browser does not support inline frames or is currently configured not to display inline frames.

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

Преобразование с помощью translate3d()

При перемещении элемента изменяется его вертикальная и горизонтальная позиции. Существуют несколько свойств CSS , которые применяются для этого. Но я хочу порекомендовать вам использовать функцию translate3d свойства transform вместо привычных margin , padding , left , top , потому что она обеспечивает более плавную анимацию.

Функция translate3d принимает три аргумента, но сначала рассмотрим те, которые отвечают за перемещение содержимого по горизонтали и вертикали:

Аргумент Х задает перемещение по горизонтали, Y — по вертикали. Например, если вы хотите переместить содержимое на 20 пикселей вправо и вверх, функция translate3d должна выглядеть следующим образом:

Foo { transform: translate3d(20px, 20px, 0px); }

Третий аргумент, который определяет перемещение по оси Z , мы рассматривать не будем. Так как нас интересует 2d-hover эффекты CSS .

Как видите, функция translate3d не особенно сложная. Далее мы рассмотрим, как использовать ее в анимации CSS для создания движения.

Переход

Чтобы использовать это свойство в переходе, нужно выполнить два этапа. Сначала необходимо указать transform в качестве свойства, которое должно отслеживать переход:

PictureContainer img { position: relative; top: 0px; transition: transform .2s ease-in-out; }

Определив переход, вы можете задать свойство transform с функцией translate3d :

PictureContainer img:hover { transform: translate3d(0px, -150px, 0px); }

Как показано в примере, приведенном в начале статьи, CSS hover эффект при наведении курсора мыши на любой из элементов приводит к смещению изображения вверх на 150 пикселей.

Анимация

В случае анимации, убедитесь, что ключевые кадры в @keyframes содержат свойство transform с translate3d :

@keyframes bobble { 0% { transform: translate3d(50px, 40px, 0px); animation-timing-function: ease-in; } 50% { transform: translate3d(50px, 50px, 0px); animation-timing-function: ease-out; } 100% { transform: translate3d(50px, 40px, 0px); } }

Пример из статьи содержит все, что нужно, чтобы вы увидели, как работает CSS hover эффект для табличной верстки.

Не забывайте о префиксах

Чтобы разметка работала в различных браузерах, обязательно используйте для свойства transform вендорные префиксы или библиотеку —prefix-free .

Переходы с помощью JavaScript

Также можно создавать анимацию перемещения в JavaScript . Те же правила действуют и здесь. Сначала нужно установить позицию, используя transform translate3d , но в JavaScript это немного сложнее.

Фрагмент кода, который нужен для этого, выглядит следующим образом:

function getSupportedPropertyName(properties) { for (var i = 0; i < properties.length; i++) { if (typeof document.body.style] != "undefined") { return properties[i]; } } return null; } var transform = ["transform", "msTransform", "webkitTransform", "mozTransform", "oTransform"]; var item = document.querySelector("#theItem"); var transformProperty = getSupportedPropertyName(transform); if (transformProperty) { item.style = translate3d(someValueX, someValueY, 0px); }

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

Почему нам не подходит установка позиции с помощью margin , top , left и т.д.?

Если у вас нет на то особой причины, не используйте для создания hover эффектов CSS свойства margin , padding , top , left , bottom или right . Хотя это может показаться противоречащим здравому смыслу. Позвольте мне пояснить…

Ненужные вычисления

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

Вы можете задать для position элемента, который вы перемещаете, значение fixed или absolute . Это избавит браузер от необходимости вычислять макет для всего документа. Но в этом случае браузер все равно выполняет вычисления для элемента, который перемещается. И результат применения translate3d не обязательно будет идентичен результату, получаемому при использовании margin , padding и т.д. Более того, как вы увидите в следующем разделе, они не будут на 100% идентичны.

Аппаратное ускорение

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

GPU предназначен только для обработки задач, связанных с отображением на экране. В то же время процессор параллельно обрабатывает огромное количество разнообразных задач. И для того, чтобы ваша анимация отображалась плавно, нельзя пренебрегать этой закономерностью. Разница в плавности отображения анимации может быть не сильно заметна на мощном стационарном компьютере или ноутбуке, но явно проявится на мобильных устройствах. Из личного опыта могу сказать, что на этих устройствах анимация с использованием CPU проигрывается более прерывисто, чем та, которая использует GPU .

А как обеспечить, чтобы анимация в режиме аппаратного ускорения использовала GPU ? Применить translate3d ! При преобразовании элемента с помощью translate3d он обрабатывается через GPU в Webkit-браузерах , таких как Chrome и Safari (которые установлены на iPhone и iPad ), в Internet Explorer 9/10 , а также в последних версиях Firefox . Это дает translate3d явные преимущества.

Как насчет JavaScript?

Что касается hover эффектов CSS , созданных на JavaScript , где все интерполяции обрабатывается кодом, я на самом деле не знаю, является ли использование GPU таким продуктивным. Но для установки с помощью JavaScript переходов и анимации CSS со свойством translate3d используется GPU .

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

Боже, благослови преобразования!

Причина, по которой transform является более производительным, заключается в том, что оно не затрагивают никакие другие элементы. Любые действия, которые вы выполняете, применяются только к одному элементу, и браузеру не нужно перестраивать все окно. Он модифицирует только ту часть экрана, которая содержит перемещающийся контент. Это не зависит от того, задействован GPU или нет.

Осуждают то, чего не понимают.
Квинтилиан

П рогрессивно развивающиеся HTML5 и CSS3 позволяют веб-мастерам создавать всё более интерактивные веб-страницы. С помощью функций CSS3 Transitions и CSS3 Animations можно легко добавить индивидуальности при создании своего сайта.

Функция CSS3 Transitions

Функция CSS3 Transitions заключается в плавном изменении одного значения свойства CSS на другое. Другими словами, переходы CSS позволяют плавно изменять одно анимированное состояние на другое в течение заданного времени.

Рассмотрим следующую разметку:

#img {
opacity : 1;

transition-duration : 2s ;
transition-delay : 0s ;

}

#img:hover {
opacity : 0 ;
}

Что же из этого следует? А вот что. Если переместить курсор на изображение, то оно начнёт плавно исчезать (transition-property : opacity ) в течении 2 секунд (transition-duration : 2s ), без задержки во времени (transition-delay : 0s ).

Рассмотрим свойства вызывающие переход:

  • transition-property - указывает имя свойства CSS для эффекта перехода. Эффект перехода обычно происходит тогда, когда пользователь наводит курсор на элемент. Значение по умолчанию "all".
  • transition-duration - определяет, сколько секунд (s) или миллисекунд (ms) необходимое для завершения эффекта перехода. По умолчанию значение равно нулю, что означает, что переход происходит мгновенно.
  • transition-delay - определяет, когда эффект перехода начнется. Значение transition-delay указывается в секундах (s) или в миллисекундах (ms). Время может быть отрицательным, в этом случае переход начинается на полпути от его продолжительности. Значение по умолчанию равно нулю.
  • transition-timing-function - задает скорость эффекта перехода. Это свойство позволяет изменять скорость в течении эффекта перехода.

id="imageWrapper" >
id="backImage" src ="imageB.jpg" />
id="frontImage" src ="imageA.jpg" />

#imageWrapper {
display : inline-block ;
width : 320px ;
height : 240px ;

position : relative ;
}

#imageWrapper img {
width : 320px ;
height : 240px ;
position : absolute ;
transition-property : opacity ;
transition-duration : 2s ;
transition-timing-function : linear ;
}

#imageWrapper #frontImage, #imageWrapper:hover #backImage {
opacity : 1 ;
}

#imageWrapper:hover #frontImage, #imageWrapper #backImage {
opacity : 0 ;
}

Вот что получилось из этой разметки:

Наведите курсор на изображение, чтобы увидеть эффект CSS3 перехода.

Функция CSS3 Animations

CSS3 Анимация похожа на CSS3 Transitions в том, что они плавно анимации значения CSS с течением времени. Различия (а) как один указывает свойства анимации, (б) каким запускает анимацию и (в) сложность анимации возможно.

Эффект анимации осуществляется с использованием “@keyframes ”. Эффект анимации позволяет элементу постепенно изменяться от одного стиля к другому. Можно изменить столько стилей, сколько вы хотите. Столько раз, сколько вы хотите.

Выглядит так:

@keyframes fadeOut {
from {
opacity : 1 ;
}
to {
opacity : 0 ;
}
}

#img {
animation-duration : 2s ;
animation-delay : 0s ;
animation-timing-function : linear ;

}

Img:hover {
animation-name : fadeOut ;
}

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

  • animation-fill-mode - значение forwards указывает браузеру, что следует остановить анимацию на последнем кадре по окончанию последнего повтора и не отматывать ее к первоначальному состтоянию.
  • animation-name - указывает имя keyframe , которое вы хотите связать с селектором.
  • animation-timing-function - указывает скорость анимации. Кривая скорости определяет время анимации, которое используются для перехода от одного набора стилей CSS к другому. Используется для плавного изменения скорости.

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

Это позволяет программировать такие эффекты, как показано в разметке и примере ниже:

#bouncingImage {
width : 320px ;
height : 240px ;
box-shadow : 2px 2px 5px 0px gray ;
animation-duration : 2s ;
animation-timing-function : ease-in-out ;
animation-fill-mode : forwards ;
}

#bouncingImage:hover {
animation-name : zoomInBounce ;
}

@keyframes zoomInBounce {
from {
transform : scale(1) ;
}

30% {
transform : scale(1.4) ;
}

40% {
transform : scale(1.15) ;
}

50% {
transform : scale(1.35) ;
}

60% {
transform : scale(1.2) ;
}

70% {
transform : scale(1.3) ;
}

80% {
transform : scale(1.225) ;
}

90% {
transform : scale(1.275) ;
}

To {
transform : scale(1.25) ;
}
}

Наведите курсор на изображение, чтобы увидеть эффект.

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

  • Плавное изменение цвета
  • Плавное затухание
  • Плавное увеличение — уменьшение
  • Плавное перемещение
  • Плавный поворот

Плавное затухание

CSS код пишем примерно тот же самый, только свойство указываем — all, то есть ко всему, что последует после , будет применена плавность. В нашем случае это затухание. Блок изменит прозрачность при наведении на 50%.

1 2 3 4 5 6 -webkit-transition: all 1s ease; -o-transition: all 1s ease; -moz-transition: all 1s ease; transition : all 1s ease; #block1 : hover { opacity : 0.4 ; }

Webkit-transition: all 1s ease; -o-transition: all 1s ease; -moz-transition: all 1s ease; transition: all 1s ease; #block1:hover{opacity:0.4;}

Плавное увеличение

Здесь все то же самое. Только в примере я установил значение linear вместо ease. Устанавливаем в ширину и высоту, отличную от оригинального размера.

Плавное перемещение

Здесь значения будем прописывать в псевдоклассе, используя свойство transform.

1 2 3 4 5 6 #block1 : hover { -webkit-transform: translate (50px , 0 ) ; -moz-transform: translate (50px , 0 ) ; -o-transform: translate (50px , 0 ) ; transform : translate (50px , 0 ) ; }

#block1:hover{ -webkit-transform: translate(50px,0); -moz-transform: translate(50px,0); -o-transform: translate(50px,0); transform: translate(50px,0); }; }

#block1:hover{ -webkit-transform: rotate(180deg); -moz-transform: rotate(180deg); -o-transform: rotate(180deg); }

Это означает, что объект будет повернут на 180° по часовой стрелке

Вернемся к теме о браузерах. Opera, Mozilla, Chrome прекрасно поддерживают все эти новшества, но Internet Explorer как обычно живет своей жизнью и никуда не спешит. У него и так все хорошо. 🙂 То есть все, о чем я писал выше, он просто не понимает. Вот такие дела. Скачайте исходники и изучите код более подробно.

Результат данного урока работает в браузерах Safari, Chrome, Opera, Firefox, начиная с версии 4 (где увидите трансформации, но без анимации). Также, с помощью браузерного префикса -ms-, вы сможете увидеть положительные результат в IE, начиная с 9ой версии.

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

Для работы трансформаций в Firefox и Opera просто замените префикс -webkit на -moz и -o. Для IE - на -ms.

1. Введение в CSS трансформации

CSS трансформации используют для изменения вида, поворота и других преобразований элемента. Все эти настройки выставляются в обычных таблицах стилей, и когда вы открываете страницу, то уже видите готовый результат трансформации. Для того чтобы увидеть само преобразование из одного вида в другой (анимацию трансформации), к элементу можно прикрутить какое-то событие (например, событие mouseover);

В примере, указанном ниже, мы расположили 4 абсолютно одинаковых div-а с рамкой в 2px. Для трансформации данных элементов в браузерах, работающих на webkit, добавляем префикс -webkit-transform:

Без данных трансформаций div-ы будут выглядеть абсолютно одинаково.

2. Анимация

Для анимации трансформаций в Webkit браузерах можно воспользоваться префиксом -webkit-transition. Демонстрация представлена ниже:

Перед вами 4 одинаковых div-а. Для запуска анимации необходимо подвести/отвести мышь. При всём при этом, никакого JavaScript. Только HTML и CSS.

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

Опять же, мы используем только HTML и CSS. В данном случае, изменяем настройки border-color, border-radius.

4. Множественные трансформации на одном элементе

Для применения множественных трансформаций к одному и тому же элементу просто перечислите настройки через пробел. К примеру:

Данные настройки при наводке мыши за 1 секунду изменят цвет под-меню, повернут его, увеличат в размере.

4. Анимация в действии

Вот ещё один интересный пример комбинирования различного рода трансформаций в одной анимации:

Данный пример может работать не очень хорошо в Safari 3 и в ранних версиях Opera.

Блок, окружённый точечной рамкой, который появляется во время проигрывания анимации, отображает позицию элемента div. Его мы просто смещаем, а его содержание поворачиваем. Всё просто!

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

5. Использование различных видов анимации

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

При событии:hover, синий квадрат, повернётся, поменяет цвет на красный, и передвинется из верхнего левого угла в правый нижний.

Первое, что вы наверное должны были заметить, так это особенность передвижения квадрата. Теперь оно не резкое, а более “изогнутое”. Всё благодаря функциям ease-out и ease-in.

Также обратите внимание, что изменение цвета происходит до поворота.

Фишка в том, что вы можете разбить -webkit-transition на несколько записей:

#block { ... background: blue; ... -webkit-transition-property: left, top, background, -webkit-transform; -webkit-transition-duration: 2s, 2s, 1s, 1s; -webkit-transition-timing-function: ease-out, ease-in, linear, ease-in-out; -webkit-transition-delay: 0, 0, 0, 1s; ... } #stage:hover #block { left: 100px; top: 100px; background: red; -webkit-transform: rotate(360deg); }

6. Событие одного элемента преобразует другой

Многих наверное заинтересует подобный функционал: клик на один элемент вызывает преобразование другого. В CSS этого можно достичь, воспользовавшись селекторами >, + и ~.

Вот и соответствующий пример:

В этом примере мы воспользовались знаком +, чтобы взаимодействовать с #box1 и #box2. ~ может использоваться для получения доступа к элементам, которые находятся где-то далеко от элемента, ожидающего события.

#box2 { position: absolute; left: 120px; ... background: blue; ... } #box1:hover + #box2 { -webkit-transform: rotate(360deg); -moz-transform: rotate(360deg); -o-transform: rotate(360deg); -ms-transform: rotate(360deg); transform: rotate(360deg); left: 627px; background: yellow; }

В то же время, мы можем анимировать и первый блок:

Недостаток данных примеров только в том, что они не работают (или работают криво) в более ранних версиях браузеров.

Спасибо Niall за предложенный урок!



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: