Formulário de login urso animado feito com HTML, CSS e JS

Formulário de login de urso animado usando HTML, CSS e JavaScript

Hoje, criaremos um projeto único e emocionante. Vocês devem ter visto diferentes tipos de formulários de login e devem ter criado diferentes tipos de páginas de login. Mas vocês já viram um formulário de login SVG animado em que um urso polar branco olha para o texto do seu e-mail e, quando você digita sua senha, ele coloca as mãos nos olhos? 

Vamos dar uma olhada no nosso projeto e ver o quão interativo ele é. Nós criaremos este projeto do zero, então aqueles que não têm ideia, não se preocupem.

formulario login animado 1 - Formulário de login urso animado feito com HTML, CSS e JS

Pré-requisitos:

  1. Conhecimento básico de estrutura HTML
  2. Estilo CSS e conceito de animação
  3. Funções Javascript.

Estrutura HTML

Primeiro, criaremos a estrutura de um formulário de login SVG animado. Para isso, usaremos o elemento <form> e, dentro do elemento form, usando a tag <div> com a classe “svgContainer”, criaremos um frame do formulário e, dentro dele, usando o elemento block-level, adicionaremos o link para o arquivo SVG. 

Um SVG é um gráfico vetorial escalável que não perde sua qualidade quando incorporado dentro do site. Adicionaremos SVG para todas as partes do urso polar, como o rosto, sobrancelhas e boca. Basta copiar este elemento de classe svg e colá-lo dentro da sua estrutura html, e aqui a função principal do CSS é adicionar animação ao projeto.

Agora criaremos um contêiner dentro do qual criaremos dois campos para inserir o ID de e-mail e a senha. Usando a tag label, criaremos um rótulo para que as pessoas saibam exatamente o que foi solicitado a inserir dentro do campo. Da mesma forma, criaremos um campo para senhas e um botão de envio.

<form>
    <div class="svgContainer">
        <div>
            <svg class="mySVG" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 200">
                <defs>
                    <circle id="armMaskPath" cx="100" cy="100" r="100"/>    
                </defs>
                <clipPath id="armMask">
                    <use xlink:href="#armMaskPath" overflow="visible"/>
                </clipPath>
                <circle cx="100" cy="100" r="100" fill="#a9ddf3"/>
                <g class="body">
                    <path fill="#FFFFFF" d="M193.3,135.9c-5.8-8.4-15.5-13.9-26.5-13.9H151V72c0-27.6-22.4-50-50-50S51,44.4,51,72v50H32.1 c-10.6,0-20,5.1-25.8,13l0,78h187L193.3,135.9z"/>
                    <path fill="none" stroke="#3A5E77" stroke-width="2.5" stroke-linecap="round" stroke-linejoinn="round" d="M193.3,135.9 c-5.8-8.4-15.5-13.9-26.5-13.9H151V72c0-27.6-22.4-50-50-50S51,44.4,51,72v50H32.1c-10.6,0-20,5.1-25.8,13"/>
                    <path fill="#DDF1FA" d="M100,156.4c-22.9,0-43,11.1-54.1,27.7c15.6,10,34.2,15.9,54.1,15.9s38.5-5.8,54.1-15.9 C143,167.5,122.9,156.4,100,156.4z"/>
                </g>
                <g class="earL">
                    <g class="outerEar" fill="#ddf1fa" stroke="#3a5e77" stroke-width="2.5">
                        <circle cx="47" cy="83" r="11.5"/>
                        <path d="M46.3 78.9c-2.3 0-4.1 1.9-4.1 4.1 0 2.3 1.9 4.1 4.1 4.1" stroke-linecap="round" stroke-linejoin="round"/>
                    </g>
                    <g class="earHair">
                        <rect x="51" y="64" fill="#FFFFFF" width="15" height="35"/>
                        <path d="M53.4 62.8C48.5 67.4 45 72.2 42.8 77c3.4-.1 6.8-.1 10.1.1-4 3.7-6.8 7.6-8.2 11.6 2.1 0 4.2 0 6.3.2-2.6 4.1-3.8 8.3-3.7 12.5 1.2-.7 3.4-1.4 5.2-1.9" fill="#fff" stroke="#3a5e77" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
                    </g>
                </g>
                <g class="earR">
                    <g class="outerEar" fill="#ddf1fa" stroke="#3a5e77" stroke-width="2.5">
                        <circle cx="155" cy="83" r="11.5"/>
                        <path d="M155.7 78.9c2.3 0 4.1 1.9 4.1 4.1 0 2.3-1.9 4.1-4.1 4.1" stroke-linecap="round" stroke-linejoin="round"/>
                    </g>
                    <g class="earHair">
                        <rect x="131" y="64" fill="#FFFFFF" width="20" height="35"/>
                        <path d="M148.6 62.8c4.9 4.6 8.4 9.4 10.6 14.2-3.4-.1-6.8-.1-10.1.1 4 3.7 6.8 7.6 8.2 11.6-2.1 0-4.2 0-6.3.2 2.6 4.1 3.8 8.3 3.7 12.5-1.2-.7-3.4-1.4-5.2-1.9" fill="#fff" stroke="#3a5e77" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
                    </g>
                </g>
                <path class="chin" d="M84.1 121.6c2.7 2.9 6.1 5.4 9.8 7.5l.9-4.5c2.9 2.5 6.3 4.8 10.2 6.5 0-1.9-.1-3.9-.2-5.8 3 1.2 6.2 2 9.7 2.5-.3-2.1-.7-4.1-1.2-6.1" fill="none" stroke="#3a5e77" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
                <path class="face" fill="#DDF1FA" d="M134.5,46v35.5c0,21.815-15.446,39.5-34.5,39.5s-34.5-17.685-34.5-39.5V46"/>
                <path class="hair" fill="#FFFFFF" stroke="#3A5E77" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" d="M81.457,27.929 c1.755-4.084,5.51-8.262,11.253-11.77c0.979,2.565,1.883,5.14,2.712,7.723c3.162-4.265,8.626-8.27,16.272-11.235 c-0.737,3.293-1.588,6.573-2.554,9.837c4.857-2.116,11.049-3.64,18.428-4.156c-2.403,3.23-5.021,6.391-7.852,9.474"/>
                <g class="eyebrow">
                    <path fill="#FFFFFF" d="M138.142,55.064c-4.93,1.259-9.874,2.118-14.787,2.599c-0.336,3.341-0.776,6.689-1.322,10.037 c-4.569-1.465-8.909-3.222-12.996-5.226c-0.98,3.075-2.07,6.137-3.267,9.179c-5.514-3.067-10.559-6.545-15.097-10.329 c-1.806,2.889-3.745,5.73-5.816,8.515c-7.916-4.124-15.053-9.114-21.296-14.738l1.107-11.768h73.475V55.064z"/>
                    <path fill="#FFFFFF" stroke="#3A5E77" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" d="M63.56,55.102 c6.243,5.624,13.38,10.614,21.296,14.738c2.071-2.785,4.01-5.626,5.816-8.515c4.537,3.785,9.583,7.263,15.097,10.329 c1.197-3.043,2.287-6.104,3.267-9.179c4.087,2.004,8.427,3.761,12.996,5.226c0.545-3.348,0.986-6.696,1.322-10.037 c4.913-0.481,9.857-1.34,14.787-2.599"/>
                </g>
                <g class="eyeL">
                    <circle cx="85.5" cy="78.5" r="3.5" fill="#3a5e77"/>
                    <circle cx="84" cy="76" r="1" fill="#fff"/>
                </g>
                <g class="eyeR">
                    <circle cx="114.5" cy="78.5" r="3.5" fill="#3a5e77"/>
                    <circle cx="113" cy="76" r="1" fill="#fff"/>
                </g>
                <g class="mouth">
                    <path class="mouthBG" fill="#617E92" d="M100.2,101c-0.4,0-1.4,0-1.8,0c-2.7-0.3-5.3-1.1-8-2.5c-0.7-0.3-0.9-1.2-0.6-1.8 c0.2-0.5,0.7-0.7,1.2-0.7c0.2,0,0.5,0.1,0.6,0.2c3,1.5,5.8,2.3,8.6,2.3s5.7-0.7,8.6-2.3c0.2-0.1,0.4-0.2,0.6-0.2 c0.5,0,1,0.3,1.2,0.7c0.4,0.7,0.1,1.5-0.6,1.9c-2.6,1.4-5.3,2.2-7.9,2.5C101.7,101,100.5,101,100.2,101z"/>
                    <path style="display: none;" class="mouthSmallBG" fill="#617E92" d="M100.2,101c-0.4,0-1.4,0-1.8,0c-2.7-0.3-5.3-1.1-8-2.5c-0.7-0.3-0.9-1.2-0.6-1.8 c0.2-0.5,0.7-0.7,1.2-0.7c0.2,0,0.5,0.1,0.6,0.2c3,1.5,5.8,2.3,8.6,2.3s5.7-0.7,8.6-2.3c0.2-0.1,0.4-0.2,0.6-0.2 c0.5,0,1,0.3,1.2,0.7c0.4,0.7,0.1,1.5-0.6,1.9c-2.6,1.4-5.3,2.2-7.9,2.5C101.7,101,100.5,101,100.2,101z"/>
                    <path style="display: none;" class="mouthMediumBG" d="M95,104.2c-4.5,0-8.2-3.7-8.2-8.2v-2c0-1.2,1-2.2,2.2-2.2h22c1.2,0,2.2,1,2.2,2.2v2 c0,4.5-3.7,8.2-8.2,8.2H95z"/>
                    <path style="display: none;" class="mouthLargeBG" d="M100 110.2c-9 0-16.2-7.3-16.2-16.2 0-2.3 1.9-4.2 4.2-4.2h24c2.3 0 4.2 1.9 4.2 4.2 0 9-7.2 16.2-16.2 16.2z" fill="#617e92" stroke="#3a5e77" stroke-linejoin="round" stroke-width="2.5"/>
                    <defs>
                        <path id="mouthMaskPath" d="M100.2,101c-0.4,0-1.4,0-1.8,0c-2.7-0.3-5.3-1.1-8-2.5c-0.7-0.3-0.9-1.2-0.6-1.8 c0.2-0.5,0.7-0.7,1.2-0.7c0.2,0,0.5,0.1,0.6,0.2c3,1.5,5.8,2.3,8.6,2.3s5.7-0.7,8.6-2.3c0.2-0.1,0.4-0.2,0.6-0.2 c0.5,0,1,0.3,1.2,0.7c0.4,0.7,0.1,1.5-0.6,1.9c-2.6,1.4-5.3,2.2-7.9,2.5C101.7,101,100.5,101,100.2,101z"/>
                    </defs>
                    <clipPath id="mouthMask">
                        <use xlink:href="#mouthMaskPath" overflow="visible"/>
                    </clipPath>
                    <g clip-path="url(#mouthMask)">
                        <g class="tongue">
                            <circle cx="100" cy="107" r="8" fill="#cc4a6c"/>
                            <ellipse class="tongueHighlight" cx="100" cy="100.5" rx="3" ry="1.5" opacity=".1" fill="#fff"/>
                        </g>
                    </g>
                    <path clip-path="url(#mouthMask)" class="tooth" style="fill:#FFFFFF;" d="M106,97h-4c-1.1,0-2-0.9-2-2v-2h8v2C108,96.1,107.1,97,106,97z"/>
                    <path class="mouthOutline" fill="none" stroke="#3A5E77" stroke-width="2.5" stroke-linejoin="round" d="M100.2,101c-0.4,0-1.4,0-1.8,0c-2.7-0.3-5.3-1.1-8-2.5c-0.7-0.3-0.9-1.2-0.6-1.8 c0.2-0.5,0.7-0.7,1.2-0.7c0.2,0,0.5,0.1,0.6,0.2c3,1.5,5.8,2.3,8.6,2.3s5.7-0.7,8.6-2.3c0.2-0.1,0.4-0.2,0.6-0.2 c0.5,0,1,0.3,1.2,0.7c0.4,0.7,0.1,1.5-0.6,1.9c-2.6,1.4-5.3,2.2-7.9,2.5C101.7,101,100.5,101,100.2,101z"/>
                </g>
                <path class="nose" d="M97.7 79.9h4.7c1.9 0 3 2.2 1.9 3.7l-2.3 3.3c-.9 1.3-2.9 1.3-3.8 0l-2.3-3.3c-1.3-1.6-.2-3.7 1.8-3.7z" fill="#3a5e77"/>
                <g class="arms" clip-path="url(#armMask)">
                    <g class="armL">
                        <path fill="#ddf1fa" stroke="#3a5e77" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.5" d="M121.3 97.4L111 58.7l38.8-10.4 20 36.1z"/>
                        <path fill="#ddf1fa" stroke="#3a5e77" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.5" d="M134.4 52.5l19.3-5.2c2.7-.7 5.4.9 6.1 3.5.7 2.7-.9 5.4-3.5 6.1L146 59.7M160.8 76.5l19.4-5.2c2.7-.7 5.4.9 6.1 3.5.7 2.7-.9 5.4-3.5 6.1l-18.3 4.9M158.3 66.8l23.1-6.2c2.7-.7 5.4.9 6.1 3.5.7 2.7-.9 5.4-3.5 6.1l-23.1 6.2M150.9 58.4l26-7c2.7-.7 5.4.9 6.1 3.5.7 2.7-.9 5.4-3.5 6.1l-21.3 5.7"/>
                        <path fill="#a9ddf3" d="M178.8 74.7l2.2-.6c1.1-.3 2.2.3 2.4 1.4.3 1.1-.3 2.2-1.4 2.4l-2.2.6-1-3.8zM180.1 64l2.2-.6c1.1-.3 2.2.3 2.4 1.4.3 1.1-.3 2.2-1.4 2.4l-2.2.6-1-3.8zM175.5 54.9l2.2-.6c1.1-.3 2.2.3 2.4 1.4.3 1.1-.3 2.2-1.4 2.4l-2.2.6-1-3.8zM152.1 49.4l2.2-.6c1.1-.3 2.2.3 2.4 1.4.3 1.1-.3 2.2-1.4 2.4l-2.2.6-1-3.8z"/>
                        <path fill="#fff" stroke="#3a5e77" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M123.5 96.8c-41.4 14.9-84.1 30.7-108.2 35.5L1.2 80c33.5-9.9 71.9-16.5 111.9-21.8"/>
                        <path fill="#fff" stroke="#3a5e77" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M108.5 59.4c7.7-5.3 14.3-8.4 22.8-13.2-2.4 5.3-4.7 10.3-6.7 15.1 4.3.3 8.4.7 12.3 1.3-4.2 5-8.1 9.6-11.5 13.9 3.1 1.1 6 2.4 8.7 3.8-1.4 2.9-2.7 5.8-3.9 8.5 2.5 3.5 4.6 7.2 6.3 11-4.9-.8-9-.7-16.2-2.7M94.5 102.8c-.6 4-3.8 8.9-9.4 14.7-2.6-1.8-5-3.7-7.2-5.7-2.5 4.1-6.6 8.8-12.2 14-1.9-2.2-3.4-4.5-4.5-6.9-4.4 3.3-9.5 6.9-15.4 10.8-.2-3.4.1-7.1 1.1-10.9M97.5 62.9c-1.7-2.4-5.9-4.1-12.4-5.2-.9 2.2-1.8 4.3-2.5 6.5-3.8-1.8-9.4-3.1-17-3.8.5 2.3 1.2 4.5 1.9 6.8-5-.6-11.2-.9-18.4-1 2 2.9.9 3.5 3.9 6.2"/>
                    </g>
                    <g class="armR">
                        <path fill="#ddf1fa" stroke="#3a5e77" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.5" d="M265.4 97.3l10.4-38.6-38.9-10.5-20 36.1z"/>
                        <path fill="#ddf1fa" stroke="#3a5e77" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2.5" d="M252.4 52.4L233 47.2c-2.7-.7-5.4.9-6.1 3.5-.7 2.7.9 5.4 3.5 6.1l10.3 2.8M226 76.4l-19.4-5.2c-2.7-.7-5.4.9-6.1 3.5-.7 2.7.9 5.4 3.5 6.1l18.3 4.9M228.4 66.7l-23.1-6.2c-2.7-.7-5.4.9-6.1 3.5-.7 2.7.9 5.4 3.5 6.1l23.1 6.2M235.8 58.3l-26-7c-2.7-.7-5.4.9-6.1 3.5-.7 2.7.9 5.4 3.5 6.1l21.3 5.7"/>
                        <path fill="#a9ddf3" d="M207.9 74.7l-2.2-.6c-1.1-.3-2.2.3-2.4 1.4-.3 1.1.3 2.2 1.4 2.4l2.2.6 1-3.8zM206.7 64l-2.2-.6c-1.1-.3-2.2.3-2.4 1.4-.3 1.1.3 2.2 1.4 2.4l2.2.6 1-3.8zM211.2 54.8l-2.2-.6c-1.1-.3-2.2.3-2.4 1.4-.3 1.1.3 2.2 1.4 2.4l2.2.6 1-3.8zM234.6 49.4l-2.2-.6c-1.1-.3-2.2.3-2.4 1.4-.3 1.1.3 2.2 1.4 2.4l2.2.6 1-3.8z"/>
                        <path fill="#fff" stroke="#3a5e77" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M263.3 96.7c41.4 14.9 84.1 30.7 108.2 35.5l14-52.3C352 70 313.6 63.5 273.6 58.1"/>
                        <path fill="#fff" stroke="#3a5e77" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M278.2 59.3l-18.6-10 2.5 11.9-10.7 6.5 9.9 8.7-13.9 6.4 9.1 5.9-13.2 9.2 23.1-.9M284.5 100.1c-.4 4 1.8 8.9 6.7 14.8 3.5-1.8 6.7-3.6 9.7-5.5 1.8 4.2 5.1 8.9 10.1 14.1 2.7-2.1 5.1-4.4 7.1-6.8 4.1 3.4 9 7 14.7 11 1.2-3.4 1.8-7 1.7-10.9M314 66.7s5.4-5.7 12.6-7.4c1.7 2.9 3.3 5.7 4.9 8.6 3.8-2.5 9.8-4.4 18.2-5.7.1 3.1.1 6.1 0 9.2 5.5-1 12.5-1.6 20.8-1.9-1.4 3.9-2.5 8.4-2.5 8.4"/>
                    </g>                
                </g>
            </svg>
        </div>
    </div>
    
    <div class="inputGroup inputGroup1">
        <label for="email1">Email</label>
        <input type="text" id="email" class="email" maxlength="256"/>
        <p class="helper helper1">[email protected]</p>
        <span class="indicator"></span>
    </div>
    <div class="inputGroup inputGroup2">
        <label for="password">Password</label>
        <input type="password" id="password" class="password" />
    </div>
    <div class="inputGroup inputGroup3">
        <button id="login">Log in</button>
    </div>    
</form>
formulario login animado 2 - Formulário de login urso animado feito com HTML, CSS e JS

Adicionando CSS ao nosso projeto:

Usando a tag HTML, adicionaremos o estilo básico ao nosso projeto. Definiremos a largura e a altura para 100% e, usando a tag body, definiremos a cor de fundo do corpo para azul claro e a posição do conteúdo do corpo é relativa à página.

Também usando a propriedade da família de fontes, definiremos o estilo da família de fontes como “Source Sans Pro” e a espessura da fonte como 400.

html {
  width: 100%;
  height: 100%;
}

body {
  background-color: #eff3f4;
  position: relative;
  width: 100%;
  height: 100%;
  font-size: 16px;
  font-family: "Source Sans Pro", sans-serif;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}
formulario login animado 3 - Formulário de login urso animado feito com HTML, CSS e JS

Estilo de formulário e SVG:

Usando a tag form, adicionaremos estilo à estrutura do formulário; usando a propriedade position, definiremos a posição como “absoluta” e, usando as propriedades top e left, adicionaremos 50% de espaço a ambos os lados. Além disso, usando a propriedade border radius, definiremos o raio da borda para dar uma aparência de canto suave.

Agora, usando o seletor de classe filho, adicionaremos o estilo ao nosso avatar SVG. Definiremos a posição como relativa, a cor de fundo como branca e a largura como 100%.

form {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: block;
  width: 100%;
  max-width: 400px;
  background-color: #FFF;
  margin: 0;
  padding: 2.25em;
  box-sizing: border-box;
  border: solid 1px #DDD;
  border-radius: 0.5em;
  font-family: "Source Sans Pro", sans-serif;
}
form .svgContainer {
  position: relative;
  width: 200px;
  height: 200px;
  margin: 0 auto 1em;
  border-radius: 50%;
  background: none;
  border: solid 2.5px #3A5E77;
  overflow: hidden;
  pointer-events: none;
}
form .svgContainer div {
  position: relative;
  width: 100%;
  height: 0;
  overflow: hidden;
  padding-bottom: 100%;
}
form .svgContainer .mySVG {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
formulario login animado 4 - Formulário de login urso animado feito com HTML, CSS e JS

Adicionando estilo de elemento de formulário

Usando a tag form, com a classe inputGroup, adicionaremos uma margem de 2 em aos lados esquerdo e direito do campo de entrada e, usando a margin bottom, adicionaremos uma margem inferior de 0 px. Além disso, usando a tag label, adicionaremos o estilo ao label; definiremos o display para block; e, usando a propriedade color, definiremos a cor para green e blue.

Além disso, adicionaremos algum estilo à tag do botão e adicionaremos uma propriedade hover ao botão na qual, ao passarmos o mouse sobre ele, a cor de fundo do botão será alterada.

form .inputGroup {
  margin: 0 0 2em;
  padding: 0;
  position: relative;
}
form .inputGroup:last-of-type {
  margin-bottom: 0;
}
form label {
  margin: 0 0 12px;
  display: block;
  font-size: 1.25em;
  color: #217093;
  font-weight: 700;
  font-family: inherit;
}
form input[type=email], form input[type=text], form input[type=password] {
  display: block;
  margin: 0;
  padding: 0 1em 0;
  background-color: #f3fafd;
  border: solid 2px #217093;
  border-radius: 4px;
  -webkit-appearance: none;
  box-sizing: border-box;
  width: 100%;
  height: 65px;
  font-size: 1.55em;
  color: #353538;
  font-weight: 600;
  font-family: inherit;
  transition: box-shadow 0.2s linear, border-color 0.25s ease-out;
}
form input[type=email]:focus, form input[type=text]:focus, form input[type=password]:focus {
  outline: none;
  box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1);
  border: solid 2px #4eb8dd;
}
form input[type=email], form input[type=text] {
  padding: 14px 1em 0px;
}
form button {
  display: block;
  margin: 0;
  padding: 0.65em 1em 1em;
  background-color: #4eb8dd;
  border: none;
  border-radius: 4px;
  box-sizing: border-box;
  box-shadow: none;
  width: 100%;
  height: 65px;
  font-size: 1.55em;
  color: #FFF;
  font-weight: 600;
  font-family: inherit;
  transition: background-color 0.2s ease-out;
}
form button:hover, form button:active {
  background-color: #217093;
}
form .inputGroup1 .helper {
  position: absolute;
  z-index: 1;
  font-family: inherit;
}
form .inputGroup1 .helper1 {
  top: 0;
  left: 0;
  transform: translate(1.4em, 2.6em) scale(1);
  transform-origin: 0 0;
  color: #217093;
  font-size: 1.25em;
  font-weight: 400;
  opacity: 0.65;
  pointer-events: none;
  transition: transform 0.2s ease-out, opacity 0.2s linear;
}
form .inputGroup1.focusWithText .helper {
  /*input[type='email']:focus + .helper {*/
  transform: translate(1.4em, 2em) scale(0.65);
  opacity: 1;
}
formulario login animado 5 - Formulário de login urso animado feito com HTML, CSS e JS

Adicionando Javascript: criando variáveis

Criaremos algumas variáveis ​​e atribuiremos o valor de elementos html usando as variáveis ​​email, password, mySVG, armL, armR, eyeL e eyeR. Selecionaremos todos os elementos da tag HTML para adicionar animação de avatar SVG e, usando o elemento document.queryselector, atribuiremos o valor à variável.

var email = document.querySelector('#email'),
    password = document.querySelector('#password'),
    mySVG = document.querySelector('.svgContainer'),
    armL = document.querySelector('.armL'),
    armR = document.querySelector('.armR'),
    eyeL = document.querySelector('.eyeL'),
    eyeR = document.querySelector('.eyeR'),
    nose = document.querySelector('.nose'),
    mouth = document.querySelector('.mouth'),
    mouthBG = document.querySelector('.mouthBG'),
    mouthSmallBG = document.querySelector('.mouthSmallBG'),
    mouthMediumBG = document.querySelector('.mouthMediumBG'),
    mouthLargeBG = document.querySelector('.mouthLargeBG'),
    mouthMaskPath = document.querySelector('#mouthMaskPath'),
    mouthOutline = document.querySelector('.mouthOutline'),
    tooth = document.querySelector('.tooth'),
    tongue = document.querySelector('.tongue'),
    chin = document.querySelector('.chin'),
    face = document.querySelector('.face'),
    eyebrow = document.querySelector('.eyebrow'),
    outerEarL = document.querySelector('.earL .outerEar'),
    outerEarR = document.querySelector('.earR .outerEar'),
    earHairL = document.querySelector('.earL .earHair'),
    earHairR = document.querySelector('.earR .earHair'),
    hair = document.querySelector('.hair');
var caretPos, curEmailIndex, screenCenter, svgCoords, eyeMaxHorizD = 20,
    eyeMaxVertD = 10,
    noseMaxHorizD = 23,
    noseMaxVertD = 10,
    dFromC, eyeDistH, eyeLDistV, eyeRDistV, eyeDistR, mouthStatus = "small";

Criação de função

Criaremos uma função chamada getcoord (e). Esta função nos ajudará a encontrar as coordenadas ou a distância entre o campo de entrada e o cursor. Usando var carPos, que é a posição do cursor no campo de entrada email, e usando as tags div e span para medir as dimensões do texto. As coordenadas email {}, coordenadas caret {}, coordenadas center {} armazenaremos diferentes dimensões do elemento.

function getCoord(e) {
    var carPos = email.selectionEnd,
        div = document.createElement('div'),
        span = document.createElement('span'),
        copyStyle = getComputedStyle(email),
        emailCoords = {},
        caretCoords = {},
        centerCoords = {};
    [].forEach.call(copyStyle, function(prop) {
        div.style[prop] = copyStyle[prop];
    });
    div.style.position = 'absolute';
    document.body.appendChild(div);
    div.textContent = email.value.substr(0, carPos);
    span.textContent = email.value.substr(carPos) || '.';
    div.appendChild(span);

    emailCoords = getPosition(email); //console.log("emailCoords.x: " + emailCoords.x + ", emailCoords.y: " + emailCoords.y);
    caretCoords = getPosition(span); //console.log("caretCoords.x " + caretCoords.x + ", caretCoords.y: " + caretCoords.y);
    centerCoords = getPosition(mySVG); //console.log("centerCoords.x: " + centerCoords.x);
    svgCoords = getPosition(mySVG);
    screenCenter = centerCoords.x + (mySVG.offsetWidth / 2); //console.log("screenCenter: " + screenCenter);
    caretPos = caretCoords.x + emailCoords.x; //console.log("caretPos: " + caretPos);

    dFromC = screenCenter - caretPos; //console.log("dFromC: " + dFromC);
    var pFromC = Math.round((caretPos / screenCenter) * 100) / 100;
    if (pFromC < 1) {

    } else if (pFromC > 1) {
        pFromC -= 2;
        pFromC = Math.abs(pFromC);
    }

Movimentos oculares horizontais

Calcularemos a distância horizontal na qual os olhos devem ser movidos; calcularemos como uma pequena porção do centro e usaremos o grampo para mover a distância dos olhos no máximo.

eyeDistH = -dFromC * .05;
if (eyeDistH > eyeMaxHorizD) {
    eyeDistH = eyeMaxHorizD;
} else if (eyeDistH < -eyeMaxHorizD) {
    eyeDistH = -eyeMaxHorizD;
}

Adicionando animação: adicionaremos animação usando a plataforma GSAP para adicionar vários movimentos de características faciais.

var eyeLCoords = {x: svgCoords.x + 84, y: svgCoords.y + 76};
var eyeRCoords = {x: svgCoords.x + 113, y: svgCoords.y + 76};
var noseCoords = {x: svgCoords.x + 97, y: svgCoords.y + 81};
var mouthCoords = {x: svgCoords.x + 100, y: svgCoords.y + 100};

Calculando ângulos para movimentos

Usaremos os conceitos de ângulos aqui. Usando a função angle, selecionaremos os ângulos e, então, usando as posições dos ângulos dos eixos x e y, definiremos o ângulo do olho.

1.

Adicionando características faciais e transformação

Essas variáveis ​​chinX e chinY ajudarão a armazenar os movimentos e transformações dos elementos e, usando a propriedade tweenMax GSAP, adicionaremos o estilo ao nosso avatar SVG animado.

var chinX = mouthX * .8;
var chinY = mouthY * .5;
var chinS = 1 - ((dFromC * .15) / 100);
if(chinS > 1) { chinS = 1 - (chinS - 1); }

var faceX = mouthX * .3;
var faceY = mouthY * .4;
var faceSkew = Math.cos(mouthAngle) * 5;
var eyebrowSkew = Math.cos(mouthAngle) * 25;

var outerEarX = Math.cos(mouthAngle) * 4;
var outerEarY = Math.cos(mouthAngle) * 5;

var hairX = Math.cos(mouthAngle) * 6;
var hairS = 1.2;
TweenMax.to(eyeL, 1, {x: -eyeLX, y: -eyeLY, ease: Expo.easeOut});
TweenMax.to(eyeR, 1, {x: -eyeRX, y: -eyeRY, ease: Expo.easeOut});
TweenMax.to(nose, 1, {x: -noseX, y: -noseY, rotation: mouthR, transformOrigin: "center center", ease: Expo.easeOut});
TweenMax.to(mouth, 1, {x: -mouthX, y: -mouthY, rotation: mouthR, transformOrigin: "center center", ease: Expo.easeOut});
TweenMax.to(chin, 1, {x: -chinX, y: -chinY, scaleY: chinS, ease: Expo.easeOut});
TweenMax.to(face, 1, {x: -faceX, y: -faceY, skewX: -faceSkew, transformOrigin: "center top", ease: Expo.easeOut});
TweenMax.to(eyebrow, 1, {x: -faceX, y: -faceY, skewX: -eyebrowSkew, transformOrigin: "center top", ease: Expo.easeOut});
TweenMax.to(outerEarL, 1, {x: outerEarX, y: -outerEarY, ease: Expo.easeOut});
TweenMax.to(outerEarR, 1, {x: outerEarX, y: outerEarY, ease: Expo.easeOut});
TweenMax.to(earHairL, 1, {x: -outerEarX, y: -outerEarY, ease: Expo.easeOut});
TweenMax.to(earHairR, 1, {x: -outerEarX, y: outerEarY, ease: Expo.easeOut});
TweenMax.to(hair, 1, {x: hairX, scaleY: hairS, transformOrigin: "center bottom", ease: Expo.easeOut});

Adicionando animação ao campo de senha

Criaremos uma função chamada onEmailInput, acionaremos a função chamada getcoord e, usando o target.value, adicionaremos movimento ao avatar de acordo com o comprimento do e-mail. Usando a condição if e else, adicionaremos a validação do e-mail, na qual usaremos a propriedade de animação gsap do TweenMax. Quanto maior o comprimento do e-mail, mais a boca do avatar se abrirá.

Então adicionaremos a animação ao campo de senha, no qual adicionaremos as animações da mão esquerda e direita. Assim que o usuário clicar no campo de senha, adicionaremos um event listener ao campo de entrada de senha e, quando o usuário clicar no campo, a animação da mão será acionada e o valor será atribuído ao avatar.

function onEmailInput(e) {
    getCoord(e);
    var value = e.target.value;
    curEmailIndex = value.length;
    
    // very crude email validation for now to trigger effects
    if(curEmailIndex > 0) {
        if(mouthStatus == "small") {
            mouthStatus = "medium";
            TweenMax.to([mouthBG, mouthOutline, mouthMaskPath], 1, {morphSVG: mouthMediumBG, shapeIndex: 8, ease: Expo.easeOut});
            TweenMax.to(tooth, 1, {x: 0, y: 0, ease: Expo.easeOut});
            TweenMax.to(tongue, 1, {x: 0, y: 1, ease: Expo.easeOut});
            TweenMax.to([eyeL, eyeR], 1, {scaleX: .85, scaleY: .85, ease: Expo.easeOut});
        }
        if(value.includes("@")) {
            mouthStatus = "large";
            TweenMax.to([mouthBG, mouthOutline, mouthMaskPath], 1, {morphSVG: mouthLargeBG, ease: Expo.easeOut});
            TweenMax.to(tooth, 1, {x: 3, y: -2, ease: Expo.easeOut});
            TweenMax.to(tongue, 1, {y: 2, ease: Expo.easeOut});
            TweenMax.to([eyeL, eyeR], 1, {scaleX: .65, scaleY: .65, ease: Expo.easeOut, transformOrigin: "center center"});
        } else {
            mouthStatus = "medium";
            TweenMax.to([mouthBG, mouthOutline, mouthMaskPath], 1, {morphSVG: mouthMediumBG, ease: Expo.easeOut});
            TweenMax.to(tooth, 1, {x: 0, y: 0, ease: Expo.easeOut});
            TweenMax.to(tongue, 1, {x: 0, y: 1, ease: Expo.easeOut});
            TweenMax.to([eyeL, eyeR], 1, {scaleX: .85, scaleY: .85, ease: Expo.easeOut});
        }
    } else {
        mouthStatus = "small";
        TweenMax.to([mouthBG, mouthOutline, mouthMaskPath], 1, {morphSVG: mouthSmallBG, shapeIndex: 9, ease: Expo.easeOut});
        TweenMax.to(tooth, 1, {x: 0, y: 0, ease: Expo.easeOut});
        TweenMax.to(tongue, 1, {y: 0, ease: Expo.easeOut});
        TweenMax.to([eyeL, eyeR], 1, {scaleX: 1, scaleY: 1, ease: Expo.easeOut});
    }
}

function onEmailFocus(e) {
    e.target.parentElement.classList.add("focusWithText");
    getCoord();
}

function onEmailBlur(e) {
    if(e.target.value == "") {
        e.target.parentElement.classList.remove("focusWithText");
    }
    resetFace();
}

function onPasswordFocus(e) {
    coverEyes();
}

function onPasswordBlur(e) {
    uncoverEyes();
}

function coverEyes() {
    TweenMax.to(armL, .45, {x: -93, y: 2, rotation: 0, ease: Quad.easeOut});
    TweenMax.to(armR, .45, {x: -93, y: 2, rotation: 0, ease: Quad.easeOut, delay: .1});
}

function uncoverEyes() {
    TweenMax.to(armL, 1.35, {y: 220, ease: Quad.easeOut});
    TweenMax.to(armL, 1.35, {rotation: 105, ease: Quad.easeOut, delay: .1});
    TweenMax.to(armR, 1.35, {y: 220, ease: Quad.easeOut});
    TweenMax.to(armR, 1.35, {rotation: -105, ease: Quad.easeOut, delay: .1});
}

function resetFace() {
    TweenMax.to([eyeL, eyeR], 1, {x: 0, y: 0, ease: Expo.easeOut});
    TweenMax.to(nose, 1, {x: 0, y: 0, scaleX: 1, scaleY: 1, ease: Expo.easeOut});
    TweenMax.to(mouth, 1, {x: 0, y: 0, rotation: 0, ease: Expo.easeOut});
    TweenMax.to(chin, 1, {x: 0, y: 0, scaleY: 1, ease: Expo.easeOut});
    TweenMax.to([face, eyebrow], 1, {x: 0, y: 0, skewX: 0, ease: Expo.easeOut});
    TweenMax.to([outerEarL, outerEarR, earHairL, earHairR, hair], 1, {x: 0, y: 0, scaleY: 1, ease: Expo.easeOut});
}

function getAngle(x1, y1, x2, y2) {
    var angle = Math.atan2(y1 - y2, x1 - x2);
    return angle;
}

function getPosition(el) {
    var xPos = 0;
    var yPos = 0;

    while (el) {
        if (el.tagName == "BODY") {
            // deal with browser quirks with body/window/document and page scroll
            var xScroll = el.scrollLeft || document.documentElement.scrollLeft;
            var yScroll = el.scrollTop || document.documentElement.scrollTop;

            xPos += (el.offsetLeft - xScroll + el.clientLeft);
            yPos += (el.offsetTop - yScroll + el.clientTop);
        } else {
            // for all other non-BODY elements
            xPos += (el.offsetLeft - el.scrollLeft + el.clientLeft);
            yPos += (el.offsetTop - el.scrollTop + el.clientTop);
        }

        el = el.offsetParent;
    }
    return {
        x: xPos,
        y: yPos
    };
}

email.addEventListener('focus', onEmailFocus);
email.addEventListener('blur', onEmailBlur);
email.addEventListener('input', onEmailInput);
password.addEventListener('focus', onPasswordFocus);
password.addEventListener('blur', onPasswordBlur);
TweenMax.set(armL, {x: -93, y: 220, rotation: 105, transformOrigin: "top left"});
TweenMax.set(armR, {x: -93, y: 220, rotation: -105, transformOrigin: "top right"});

Resultado Final

See the Pen Animated SVG Avatar by Darin Senneff by Oscar Diaz (@kingplatano) on CodePen.

Conclusão

Parabéns, você completou seu Formulário de login de urso animado e ainda pode melhorá-lo conforme suas preferências. Você pode implantá-lo nas plataformas Github, Vercel ou Netfliy e torná-lo ativo para seus amigos.

Espero que você tenha gostado deste Tutorial e que voce tenha aprendido novo. Se você tiver algum problema com seu projeto, não se preocupe. Você pode facilmente pegar o código-fonte para este projeto. Basta clicar no botão abaixo para começar sua aventura de codificação.

Sobre o Autor

Robson dos Santos
Robson dos Santos

DICA EXTRA!!!Algumas pessoas estão nos perguntando qual é o curso que recomendamos para quem deseja aprender programação, mesmo sem ter qualquer conhecimento sobre o assunto. Nossa recomendação, tanto para quem está iniciando, como para quem já possui mais experiência, é essa AQUI!

    0 Comentários

    Deixe um comentário

    O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *