Para esse tutorial, na parte de JavaScript, iremos utilizar só a linguagem, sem adotar framework ou biblioteca, primeiro porque o script será pequeno, e segundo porque sempre interessante desacoplar sua aplicação de framework, e de quebra aprendemos coisas novas, nesse caso, recursos do ES6 ou ECMAScript 2015.
Vamos seguir a premissa de separar as responsabilidade: HTML marcação, CSS estilização, e JavaScript comportamento.
Escrevendo HTML
Vamos definir nossa marcação com HTML.
<form action="" class="form-container"> </form>
Definimos primeiro o formulário, que apenas terá uma classe, nesse exemplo, .form-container.
É interessante adicionar classes a elementos os quais você precise estilizar ou precise fazer alterações pontuais mas não quer interferir em outros elementos iguais.
Prefira classes ao invés de id. Isso porque o id ele precisa ser único na página, e existe uma tendência de querermos reaproveitar os estilos, e não poderia adicionar o mesmo id em outro elemento para aproveitar o estilo.
<form action="" class="form-container"> <div class="fields"> </div> </form>
Vamos agora adicionar uma div com a classe .fields , que servirá para agrupar o elemento do formulário.
É comum vermos utilizar a tag de parágrafo para esse fim, mas semanticamente não seria o ideal, já que não se trata de um paragrafo, e a div é um elemento “não semântico”, e nesse caso se encaixa perfeitamente.
<form action="" class="form-container"> <div class="fields"> <input type="text" name="name" class="input" placeholder="Digite seu nome"/> </div> </form>
Agora adicionamos um campo do formulário, um input do tipo text. Iremos adicionar uma classe chamada .input .
<form action="" class="form-container"> <div class="fields"> <input type="text" name="name" class="input" placeholder="Digite seu nome"/> <div class="highlight"></div> </div> </form>
Agora adicionaremos uma div com uma classe chamada .highlight, ela irá ser responsável pelo efeito, como fosse simular uma barra que vai acompanhando enquanto digitamos.
Pronto, basicamente esse é no nosso HTML.
Escrevendo CSS
Vamos criar um arquivo chamado style.css, e adicionar numa pasta chamada css.
Antes de escrever o CSS, vamos linkar ao nosso arquivo index.html
<link rel="stylesheet" href="css/style.css" />
Para informar que iremos utilizar esse arquivo css, adicionamos a tag link, e no atributo href, indica onde está o arquivo, esse código ficará dentro do bloco da tag head
Para um melhor entendimento do nosso código CSS, deixarei os blocos separados para uma melhor explicar, e depois no final mostro todo código CSS.
.form-container{ width:500px; margin:0 auto; }
- Na linha 1, selecionamos o elemento do formulário;
- Na linha 2, definimos a largura do formulário;
- Na linha 3, definimos para que ele fique centralizado na horizontal.
.form-container .fields { position: relative; width: 100%; margin:25px auto; }
- Na linha 1, selecionamos o .fields . Nesse caso, usamos a seleção a partir do elemento pai, que seria o .form-container;
- Na linha 2, definimos um position com valor relative, porque no elemento filho .highlight será definido como absoluto e para garantimos o posicionamento de acordo com elemento pai, esse elemento será definido como relativo;
- Na linha 3, definimos uma largura de 100%;
- Na linha 4, definimos uma margin com altura e base de 25px e direito e esquerda com auto;
.form-container .input { width:100%; height: 50px; font-size: 12px; line-height: 12px; font-family: Arial, Helvetica, sans-serif; border:0; outline: none; border-bottom:3px solid #000; }
- Na linha 1, selecionamos o elemento do formulário, que atribuímos a classe .input;
- Na linha 2, definimos uma largura de 100%;
- Na linha 3, uma altura de 50px;
- Na linha 4, o tamanho da fonte para 12px;
- Na linha 5, o espaço entre linhas também de 12px
- Na linha 6, a fonte escolhemos Arial, Helvetica, sans-serif;
- Na linha 7, removemos a borda;
- Na linha 8, removemos o contorno;
- Na linha 9, adicionamos uma borda na base, com 3px, ele servirá como uma linha-guia para fazermos o efeito.
.form-container .highlight{ position: absolute; left:0; bottom: 0; width: auto; max-width: 100%; height:0; overflow: hidden; border-top:3px solid #F00; font-size: 12px; line-height: 12px; font-family: Arial, Helvetica, sans-serif; }
- Na linha 1, selecionamos a div.highlight;
- Na linha 2, definimos um position como absolute em relação ao elemento pai, que no caso é o form.form-container, e como definimos ele como position como relative, o calculo da posição dele será baseado no do pai, senão tivesse definido como relative o elemento pai, a base do calculo da posição seria o body;
- na linha 3, definimos left:0 para que elemento encoste a esquerda;
- Na linha 4, definimos bottom:0, para o elemento encoste na base;
- Na linha 5, definimos uma largura como automática, onde navegador irá definir essa largura;
- Na linha 6, definimos uma largura máxima de 100%;
- Na linha 7, definimos uma altura como zero para não mostrar o conteúdo que existirá dentro dela;
- Na linha 8, definimos o overflow como hidden para não permitir que conteudo seja exibido além do que foi definido na width e height;
- Na linha 9, definimos uma borda no topo, que será o efeito quando pessoa tiver digitando;
- Na linha 10, definimos o tamanho da fonte;
- Na linha 11, definimos o espaço entre linha;
- Na linha 13, definimos a fonte;
É importante as definições da tamanho, espaço de linha e fonte sejam o mesmo, tanto do campo input quanto na div.highlight
.form-container{ width:500px; margin:0 auto; } .form-container .fields { position: relative; width: 100%; margin:25px auto; } .form-container .input { width:100%; height: 50px; font-size: 12px; line-height: 12px; font-family: Arial, Helvetica, sans-serif; border:0; outline: none; border-bottom:3px solid #000; } .form-container .highlight{ position: absolute; left:0; bottom: 0; width: auto; max-width: 100%; height:0; overflow: hidden; border-top:3px solid #F00; font-size: 12px; line-height: 12px; font-family: Arial, Helvetica, sans-serif; }
Escrevendo o JavaScript
Vamos criar agora o código JavaScript, que definirá o comportamento que desejamos, que seria ao digitar no campo input, ele vai adicionar o mesmo conteúdo digitado no elemento .highlight .
Vamos criar um arquivo chamado main.js, e adicionar na pasta js.
Agora vamos adicionar o JavaScript na nossa página html.
<script type="text/javascript" src="js/main.js"></script>
Criamos uma tag script, e com atributo src indicamos onde está o arquivo js. Esse código será adicionado antes do fechamento da tag body.
Nessa parte, iremos fazer como mostrado na parte do HTML, adicionaremos cada parte e comentando, para um melhor entendimento.
let fields = document.querySelectorAll('.fields');
Definimos uma variável com palavra reservada let. Ele é diferente da palavra reservada var, porque a var ela defini uma variável global, e o let definir de acordo escopo de bloco.
Nessa variável fields, ele recebe todos os elementos que tenham a classe .fields. Se você já usou jQuery, essa sintaxe já é familiar, só que você pode fazer nativamente com querySelectorAll .
let fields = document.querySelectorAll('.fields'); fields.forEach( element => { });
Com document.querySelectorAll, ele retorna uma lista de elementos, e precisamos percorrer essa lista. E para isso usamos o forEach. Dentro desse forEach, executamos uma função anonima, que é passado o parâmetro o elemento que foi percorrido.
Essa sintaxe da função anonima é chamado arrow function. Seria uma forma curta para criação de uma função anonima, e onde o this é relacionado ao contexto e não define na função em si.
Isso poderia ser feito dessa forma, que no tutorial surgiria o mesmo efeito:
fields.forEach(function(element) { });
Mas sempre é bom ver novos recursos, porque iremos ver cada vezes mais essa sintaxe.
let fields = document.querySelectorAll('.fields'); fields.forEach( element => { let input = element.querySelector('.input'); let highlight = element.querySelector('.highlight'); });
Iremos recuperar o .input e .highlight. Agora usaremos o querySelector, que diferente do querySelectorAll, que retorna uma coleção de elementos, ele retorna apenas o primeiro. E usamos usando querySelector a partir os itens retornados do forEach.
let fields = document.querySelectorAll('.fields'); fields.forEach( element => { let input = element.querySelector('.input'); let highlight = element.querySelector('.highlight'); input.addEventListener('keyup', e => { }); });
Agora precisamos captura o que foi digitado pelo usuário. E pra isso adicionamos um evento ao input, e para adicionar evento utilizamos addEventListener. No primeiro parâmetro informamos qual evento queremos, que seria keyup, e segundo o callback, que será executado quando for disparado o evento. Como é uma função anonima, usamos a sintaxe do arrow function.
let fields = document.querySelectorAll('.fields'); fields.forEach( element => { let input = element.querySelector('.input'); let highlight = element.querySelector('.highlight'); input.addEventListener('keyup', e => { let value = input.value; highlight.innerHTML = value; }); });
Agora criamos uma variável com nome value que recebe o valor digitado no input. E depois adicionamos esse valor digitado dentro do elemento .highlight.
Pronto, dessa forma, basta digitar o valor do formulário, e vai aparecendo a barra acompanhando. Veja ele funcionando:
Algumas considerações
Quando foi solicitado para adicionar o JavaScript no final do body, ela é uma boa prática, para melhorar o carregamento da página. E outra questão, é porque é preciso carregar a estrutura dos elementos primeiro, para depois selecionarem. Mas se precisar adicionar na tag head, por exemplo? Precisaríamos informar para carregar o script só depois do carregamento do DOM. Para isso podemos fazer dessa forma:
document.addEventListener('DOMContentLoaded', function(){ /*Aqui dentro iria o código*/ });
Adicionando a um evento DOMContentLoaded, que vai executar só quando carrega o DOM.
Outra questão é sobre o arrow functions. Lembre que informei sobre this, que ela é relacionado ao contexto, e não a ele mesmo. Vamos utilizar o tutorial para vermos isso na prática. Vamos trocar arrow functions para função anonima (expression functions).
let fields = document.querySelectorAll('.fields'); fields.forEach(function(element){ let input = element.querySelector('.input'); let highlight = element.querySelector('.highlight'); input.addEventListener('keyup', function() { let value = this.value; highlight.innerHTML = value; }); });
Veja que o código permaneceu o mesmo, trocamos só arrow functions pelas funções anonimas (expression functions), mas dentro do evento keyup, ao invés de usar o input para recuperar o valor, usamos o this. Porque o this nesse caso, está relacionado a função, e não ao contexto, então ele pega o valor do evento disparado.
Nesse tutorial, vimos conceitos ES6, a definição de variável com let, arrow functions e a diferença com expression functions, como utilizar addEventListener, e como esperar a execução do código só apos carregar o DOM, com DOMContentLoaded.
Espero que tenham gostado e até a próxima.